Loading manifests/automationservice.yaml +5 −0 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,11 @@ spec: env: env: - name: LOG_LEVEL - name: LOG_LEVEL value: "INFO" value: "INFO" - name: CRDB_DATABASE value: "tfs_automation" envFrom: - secretRef: name: crdb-data startupProbe: startupProbe: exec: exec: command: ["/bin/grpc_health_probe", "-addr=:30200"] command: ["/bin/grpc_health_probe", "-addr=:30200"] Loading src/automation/service/AutomationServiceServicerImpl.py +35 −6 Original line number Original line Diff line number Diff line Loading @@ -23,16 +23,21 @@ from automation.service.zsm_handlers import ZSM_SERVICE_HANDLERS from automation.service.zsm_handler_api.ZSMFilterFields import ZSMFilterFieldEnum , TELEMETRY_SERVICE_TYPE_VALUES, TARGET_SERVICE_TYPE_VALUES , ZSM_FILTER_FIELD_ALLOWED_VALUES from automation.service.zsm_handler_api.ZSMFilterFields import ZSMFilterFieldEnum , TELEMETRY_SERVICE_TYPE_VALUES, TARGET_SERVICE_TYPE_VALUES , ZSM_FILTER_FIELD_ALLOWED_VALUES from common.proto.context_pb2 import ServiceTypeEnum , DeviceDriverEnum from common.proto.context_pb2 import ServiceTypeEnum , DeviceDriverEnum from context.client.ContextClient import ContextClient from context.client.ContextClient import ContextClient from automation.service.database.AutomationDB import AutomationDB from automation.service.database.AutomationModel import AutomationModel from common.method_wrappers.ServiceExceptions import NotFoundException LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Automation', 'RPC') METRICS_POOL = MetricsPool('Automation', 'RPC') class AutomationServiceServicerImpl(AutomationServiceServicer): class AutomationServiceServicerImpl(AutomationServiceServicer): def __init__(self): def __init__(self): self.automation_db_obj = AutomationDB(AutomationModel) LOGGER.info('Init AutomationService') LOGGER.info('Init AutomationService') @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMCreate(self, request : ZSMCreateRequest, context : grpc.ServicerContext) -> ZSMService: def ZSMCreate(self, request : ZSMCreateRequest, context : grpc.ServicerContext) -> ZSMService: LOGGER.info("Received gRPC message object: {:}".format(request)) context_client = ContextClient() context_client = ContextClient() targetService = context_client.GetService(request.target_service_id) targetService = context_client.GetService(request.target_service_id) Loading @@ -46,7 +51,13 @@ class AutomationServiceServicerImpl(AutomationServiceServicer): else: else: LOGGER.info("No matching handler found.") LOGGER.info("No matching handler found.") return ZSMService() response = ZSMService() automation_id = str(uuid4()) zsm_to_insert = AutomationModel.convert_Automation_to_row(automation_id , "Test Description") if self.automation_db_obj.add_row_to_db(zsm_to_insert): response.zsmServiceId.uuid.uuid = automation_id return response @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMUpdate(self, request : ZSMCreateUpdate, context : grpc.ServicerContext) -> ZSMService: def ZSMUpdate(self, request : ZSMCreateUpdate, context : grpc.ServicerContext) -> ZSMService: Loading @@ -55,14 +66,32 @@ class AutomationServiceServicerImpl(AutomationServiceServicer): @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMDelete(self, request : ZSMServiceID, context : grpc.ServicerContext) -> ZSMServiceState: def ZSMDelete(self, request : ZSMServiceID, context : grpc.ServicerContext) -> ZSMServiceState: LOGGER.info('NOT IMPLEMENTED ZSMDelete') LOGGER.info("Received gRPC message object: {:}".format(request)) return ZSMServiceState() zsm_id_to_search = request.uuid.uuid row = self.automation_db_obj.search_db_row_by_id(AutomationModel, 'zsm_id', zsm_id_to_search) if row is None: LOGGER.info('No matching row found zsm id: {:}'.format(zsm_id_to_search)) raise NotFoundException('ZsmID', zsm_id_to_search) self.automation_db_obj.delete_db_row_by_id(AutomationModel, 'zsm_id', zsm_id_to_search) zsmServiceState = ZSMServiceState() zsmServiceState.zsmServiceState = 5 zsmServiceState.zsmServiceStateMessage = "Removed id: {:}".format(request) return zsmServiceState @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMGetById(self, request : ZSMServiceID, context : grpc.ServicerContext) -> ZSMService: def ZSMGetById(self, request : ZSMServiceID, context : grpc.ServicerContext) -> ZSMService: LOGGER.info('NOT IMPLEMENTED ZSMGetById') LOGGER.info("Received gRPC message object: {:}".format(request)) return ZSMService() zsm_id_to_search = request.uuid.uuid row = self.automation_db_obj.search_db_row_by_id(AutomationModel, 'zsm_id', zsm_id_to_search) if row is None: LOGGER.info('No matching row found zsm id: {:}'.format(zsm_id_to_search)) raise NotFoundException('ZsmID', zsm_id_to_search) response = AutomationModel.convert_row_to_Automation(row) return response @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMGetByService(self, request : ServiceId, context : grpc.ServicerContext) -> ZSMService: def ZSMGetByService(self, request : ServiceId, context : grpc.ServicerContext) -> ZSMService: Loading src/automation/service/__main__.py +17 −3 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,10 @@ from common.Settings import ( wait_for_environment_variables wait_for_environment_variables ) ) from .AutomationService import AutomationService from .AutomationService import AutomationService from common.tools.database.GenericDatabase import Database from automation.service.database.AutomationModel import AutomationModel from .database.Engine import Engine from .database.models._Base import rebuild_database LOG_LEVEL = get_log_level() LOG_LEVEL = get_log_level() logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") Loading Loading @@ -58,9 +62,19 @@ def main(): metrics_port = get_metrics_port() metrics_port = get_metrics_port() start_http_server(metrics_port) start_http_server(metrics_port) # Start Event Collection+Dispatching Engine # Get Database Engine instance and initialize database, if needed event_engine = EventEngine(terminate=terminate) LOGGER.info('Getting SQLAlchemy DB Engine...') event_engine.start() db_engine = Engine.get_engine() if db_engine is None: LOGGER.error('Unable to get SQLAlchemy DB Engine...') return -1 try: Engine.create_database(db_engine) except: # pylint: disable=bare-except # pragma: no cover LOGGER.exception('Failed to check/create the database: {:s}'.format(str(db_engine.url))) rebuild_database(db_engine) # Starting Automation service # Starting Automation service grpc_service = AutomationService() grpc_service = AutomationService() Loading src/automation/service/database/AutomationDB.py 0 → 100644 +26 −0 Original line number Original line Diff line number Diff line # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging from common.method_wrappers.Decorator import MetricsPool from common.tools.database.GenericDatabase import Database from common.method_wrappers.ServiceExceptions import OperationFailedException LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Automation', 'Database') class AutomationDB(Database): def __init__(self, model) -> None: LOGGER.info('Init AutomationService') super().__init__(model) src/automation/service/database/AutomationModel.py 0 → 100644 +59 −0 Original line number Original line Diff line number Diff line # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging from sqlalchemy.dialects.postgresql import UUID from sqlalchemy import Column, Integer, String, Text from sqlalchemy.orm import registry from .models._Base import _Base from common.proto.automation_pb2 import ZSMService logging.basicConfig(level=logging.INFO) LOGGER = logging.getLogger(__name__) # Create a base class for declarative models Base = registry().generate_base() class AutomationModel(_Base): __tablename__ = 'automation' zsm_id = Column(UUID(as_uuid=False), primary_key=True) zsm_description = Column(Text , nullable=False) # helps in logging the information def __repr__(self): return (f"<Automation(zsm_id='{self.zsm_id}', zsm_description='{self.zsm_description}'>") @classmethod def convert_Automation_to_row(cls, uuid , zsm_description): """ Create an instance of Automation from a request object. Args: request: The request object containing the data. Returns: An instance of Automation initialized with data from the request. """ return cls( zsm_id = uuid, zsm_description = zsm_description ) @classmethod def convert_row_to_Automation(cls, row): """ Create and return a dictionary representation of a Automation instance. Args: row: The Automation instance (row) containing the data. Returns: Automation object """ response = ZSMService() response.zsmServiceId.uuid.uuid = row.zsm_id return response Loading
manifests/automationservice.yaml +5 −0 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,11 @@ spec: env: env: - name: LOG_LEVEL - name: LOG_LEVEL value: "INFO" value: "INFO" - name: CRDB_DATABASE value: "tfs_automation" envFrom: - secretRef: name: crdb-data startupProbe: startupProbe: exec: exec: command: ["/bin/grpc_health_probe", "-addr=:30200"] command: ["/bin/grpc_health_probe", "-addr=:30200"] Loading
src/automation/service/AutomationServiceServicerImpl.py +35 −6 Original line number Original line Diff line number Diff line Loading @@ -23,16 +23,21 @@ from automation.service.zsm_handlers import ZSM_SERVICE_HANDLERS from automation.service.zsm_handler_api.ZSMFilterFields import ZSMFilterFieldEnum , TELEMETRY_SERVICE_TYPE_VALUES, TARGET_SERVICE_TYPE_VALUES , ZSM_FILTER_FIELD_ALLOWED_VALUES from automation.service.zsm_handler_api.ZSMFilterFields import ZSMFilterFieldEnum , TELEMETRY_SERVICE_TYPE_VALUES, TARGET_SERVICE_TYPE_VALUES , ZSM_FILTER_FIELD_ALLOWED_VALUES from common.proto.context_pb2 import ServiceTypeEnum , DeviceDriverEnum from common.proto.context_pb2 import ServiceTypeEnum , DeviceDriverEnum from context.client.ContextClient import ContextClient from context.client.ContextClient import ContextClient from automation.service.database.AutomationDB import AutomationDB from automation.service.database.AutomationModel import AutomationModel from common.method_wrappers.ServiceExceptions import NotFoundException LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Automation', 'RPC') METRICS_POOL = MetricsPool('Automation', 'RPC') class AutomationServiceServicerImpl(AutomationServiceServicer): class AutomationServiceServicerImpl(AutomationServiceServicer): def __init__(self): def __init__(self): self.automation_db_obj = AutomationDB(AutomationModel) LOGGER.info('Init AutomationService') LOGGER.info('Init AutomationService') @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMCreate(self, request : ZSMCreateRequest, context : grpc.ServicerContext) -> ZSMService: def ZSMCreate(self, request : ZSMCreateRequest, context : grpc.ServicerContext) -> ZSMService: LOGGER.info("Received gRPC message object: {:}".format(request)) context_client = ContextClient() context_client = ContextClient() targetService = context_client.GetService(request.target_service_id) targetService = context_client.GetService(request.target_service_id) Loading @@ -46,7 +51,13 @@ class AutomationServiceServicerImpl(AutomationServiceServicer): else: else: LOGGER.info("No matching handler found.") LOGGER.info("No matching handler found.") return ZSMService() response = ZSMService() automation_id = str(uuid4()) zsm_to_insert = AutomationModel.convert_Automation_to_row(automation_id , "Test Description") if self.automation_db_obj.add_row_to_db(zsm_to_insert): response.zsmServiceId.uuid.uuid = automation_id return response @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMUpdate(self, request : ZSMCreateUpdate, context : grpc.ServicerContext) -> ZSMService: def ZSMUpdate(self, request : ZSMCreateUpdate, context : grpc.ServicerContext) -> ZSMService: Loading @@ -55,14 +66,32 @@ class AutomationServiceServicerImpl(AutomationServiceServicer): @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMDelete(self, request : ZSMServiceID, context : grpc.ServicerContext) -> ZSMServiceState: def ZSMDelete(self, request : ZSMServiceID, context : grpc.ServicerContext) -> ZSMServiceState: LOGGER.info('NOT IMPLEMENTED ZSMDelete') LOGGER.info("Received gRPC message object: {:}".format(request)) return ZSMServiceState() zsm_id_to_search = request.uuid.uuid row = self.automation_db_obj.search_db_row_by_id(AutomationModel, 'zsm_id', zsm_id_to_search) if row is None: LOGGER.info('No matching row found zsm id: {:}'.format(zsm_id_to_search)) raise NotFoundException('ZsmID', zsm_id_to_search) self.automation_db_obj.delete_db_row_by_id(AutomationModel, 'zsm_id', zsm_id_to_search) zsmServiceState = ZSMServiceState() zsmServiceState.zsmServiceState = 5 zsmServiceState.zsmServiceStateMessage = "Removed id: {:}".format(request) return zsmServiceState @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMGetById(self, request : ZSMServiceID, context : grpc.ServicerContext) -> ZSMService: def ZSMGetById(self, request : ZSMServiceID, context : grpc.ServicerContext) -> ZSMService: LOGGER.info('NOT IMPLEMENTED ZSMGetById') LOGGER.info("Received gRPC message object: {:}".format(request)) return ZSMService() zsm_id_to_search = request.uuid.uuid row = self.automation_db_obj.search_db_row_by_id(AutomationModel, 'zsm_id', zsm_id_to_search) if row is None: LOGGER.info('No matching row found zsm id: {:}'.format(zsm_id_to_search)) raise NotFoundException('ZsmID', zsm_id_to_search) response = AutomationModel.convert_row_to_Automation(row) return response @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) def ZSMGetByService(self, request : ServiceId, context : grpc.ServicerContext) -> ZSMService: def ZSMGetByService(self, request : ServiceId, context : grpc.ServicerContext) -> ZSMService: Loading
src/automation/service/__main__.py +17 −3 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,10 @@ from common.Settings import ( wait_for_environment_variables wait_for_environment_variables ) ) from .AutomationService import AutomationService from .AutomationService import AutomationService from common.tools.database.GenericDatabase import Database from automation.service.database.AutomationModel import AutomationModel from .database.Engine import Engine from .database.models._Base import rebuild_database LOG_LEVEL = get_log_level() LOG_LEVEL = get_log_level() logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") Loading Loading @@ -58,9 +62,19 @@ def main(): metrics_port = get_metrics_port() metrics_port = get_metrics_port() start_http_server(metrics_port) start_http_server(metrics_port) # Start Event Collection+Dispatching Engine # Get Database Engine instance and initialize database, if needed event_engine = EventEngine(terminate=terminate) LOGGER.info('Getting SQLAlchemy DB Engine...') event_engine.start() db_engine = Engine.get_engine() if db_engine is None: LOGGER.error('Unable to get SQLAlchemy DB Engine...') return -1 try: Engine.create_database(db_engine) except: # pylint: disable=bare-except # pragma: no cover LOGGER.exception('Failed to check/create the database: {:s}'.format(str(db_engine.url))) rebuild_database(db_engine) # Starting Automation service # Starting Automation service grpc_service = AutomationService() grpc_service = AutomationService() Loading
src/automation/service/database/AutomationDB.py 0 → 100644 +26 −0 Original line number Original line Diff line number Diff line # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging from common.method_wrappers.Decorator import MetricsPool from common.tools.database.GenericDatabase import Database from common.method_wrappers.ServiceExceptions import OperationFailedException LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Automation', 'Database') class AutomationDB(Database): def __init__(self, model) -> None: LOGGER.info('Init AutomationService') super().__init__(model)
src/automation/service/database/AutomationModel.py 0 → 100644 +59 −0 Original line number Original line Diff line number Diff line # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging from sqlalchemy.dialects.postgresql import UUID from sqlalchemy import Column, Integer, String, Text from sqlalchemy.orm import registry from .models._Base import _Base from common.proto.automation_pb2 import ZSMService logging.basicConfig(level=logging.INFO) LOGGER = logging.getLogger(__name__) # Create a base class for declarative models Base = registry().generate_base() class AutomationModel(_Base): __tablename__ = 'automation' zsm_id = Column(UUID(as_uuid=False), primary_key=True) zsm_description = Column(Text , nullable=False) # helps in logging the information def __repr__(self): return (f"<Automation(zsm_id='{self.zsm_id}', zsm_description='{self.zsm_description}'>") @classmethod def convert_Automation_to_row(cls, uuid , zsm_description): """ Create an instance of Automation from a request object. Args: request: The request object containing the data. Returns: An instance of Automation initialized with data from the request. """ return cls( zsm_id = uuid, zsm_description = zsm_description ) @classmethod def convert_row_to_Automation(cls, row): """ Create and return a dictionary representation of a Automation instance. Args: row: The Automation instance (row) containing the data. Returns: Automation object """ response = ZSMService() response.zsmServiceId.uuid.uuid = row.zsm_id return response