From 5dfa664e22f2c4c85b4c1b05dfc8d05e9cea9402 Mon Sep 17 00:00:00 2001 From: Lluis Gifre <lluis.gifre@cttc.es> Date: Tue, 13 Sep 2022 14:40:26 +0200 Subject: [PATCH] Multiple changes in Context component: Common: - Extended context proto with 2 methods: UnsetService and UnsetSlice Context component: - Added timestamp to logs - Added methods UnsetService and UnsetSlice to Context client - Implemented methods UnsetService and UnsetSlice in Context servicer - Resolved conflict between service and slice entities with constraints and configrules --- proto/context.proto | 2 + src/context/client/ContextClient.py | 14 ++++ src/context/service/__main__.py | 2 +- src/context/service/database/ConfigModel.py | 2 +- .../service/database/ConstraintModel.py | 2 +- .../grpc_server/ContextServiceServicerImpl.py | 66 ++++++++++++++++--- 6 files changed, 77 insertions(+), 11 deletions(-) diff --git a/proto/context.proto b/proto/context.proto index 866876175..ab7dd5e69 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -51,6 +51,7 @@ service ContextService { rpc ListServices (ContextId ) returns ( ServiceList ) {} rpc GetService (ServiceId ) returns ( Service ) {} rpc SetService (Service ) returns ( ServiceId ) {} + rpc UnsetService (Service ) returns ( ServiceId ) {} rpc RemoveService (ServiceId ) returns ( Empty ) {} rpc GetServiceEvents (Empty ) returns (stream ServiceEvent ) {} @@ -58,6 +59,7 @@ service ContextService { rpc ListSlices (ContextId ) returns ( SliceList ) {} rpc GetSlice (SliceId ) returns ( Slice ) {} rpc SetSlice (Slice ) returns ( SliceId ) {} + rpc UnsetSlice (Slice ) returns ( SliceId ) {} rpc RemoveSlice (SliceId ) returns ( Empty ) {} rpc GetSliceEvents (Empty ) returns (stream SliceEvent ) {} diff --git a/src/context/client/ContextClient.py b/src/context/client/ContextClient.py index 6e8cbac6a..da907341f 100644 --- a/src/context/client/ContextClient.py +++ b/src/context/client/ContextClient.py @@ -250,6 +250,13 @@ class ContextClient: LOGGER.debug('SetService result: {:s}'.format(grpc_message_to_json_string(response))) return response + @RETRY_DECORATOR + def UnsetService(self, request: Service) -> ServiceId: + LOGGER.debug('UnsetService request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.UnsetService(request) + LOGGER.debug('UnsetService result: {:s}'.format(grpc_message_to_json_string(response))) + return response + @RETRY_DECORATOR def RemoveService(self, request: ServiceId) -> Empty: LOGGER.debug('RemoveService request: {:s}'.format(grpc_message_to_json_string(request))) @@ -292,6 +299,13 @@ class ContextClient: LOGGER.debug('SetSlice result: {:s}'.format(grpc_message_to_json_string(response))) return response + @RETRY_DECORATOR + def UnsetSlice(self, request: Slice) -> SliceId: + LOGGER.debug('UnsetSlice request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.UnsetSlice(request) + LOGGER.debug('UnsetSlice result: {:s}'.format(grpc_message_to_json_string(response))) + return response + @RETRY_DECORATOR def RemoveSlice(self, request: SliceId) -> Empty: LOGGER.debug('RemoveSlice request: {:s}'.format(grpc_message_to_json_string(request))) diff --git a/src/context/service/__main__.py b/src/context/service/__main__.py index 53754caf4..dfd0c8773 100644 --- a/src/context/service/__main__.py +++ b/src/context/service/__main__.py @@ -36,7 +36,7 @@ def main(): global LOGGER # pylint: disable=global-statement log_level = get_log_level() - logging.basicConfig(level=log_level) + logging.basicConfig(level=log_level, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") LOGGER = logging.getLogger(__name__) signal.signal(signal.SIGINT, signal_handler) diff --git a/src/context/service/database/ConfigModel.py b/src/context/service/database/ConfigModel.py index bb2a37467..a5f90788e 100644 --- a/src/context/service/database/ConfigModel.py +++ b/src/context/service/database/ConfigModel.py @@ -116,7 +116,7 @@ def update_config( raw_config_rules : List[Tuple[ORM_ConfigActionEnum, str, str]] ) -> List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]]: - str_config_key = key_to_str([db_parent_pk, config_name], separator=':') + str_config_key = key_to_str([config_name, db_parent_pk], separator=':') result : Tuple[ConfigModel, bool] = get_or_create_object(database, ConfigModel, str_config_key) db_config, created = result diff --git a/src/context/service/database/ConstraintModel.py b/src/context/service/database/ConstraintModel.py index 17a9b52e9..449dcedee 100644 --- a/src/context/service/database/ConstraintModel.py +++ b/src/context/service/database/ConstraintModel.py @@ -231,7 +231,7 @@ def set_constraints( database : Database, db_parent_pk : str, constraints_name : str, grpc_constraints ) -> List[Tuple[Union[ConstraintsModel, ConstraintModel], bool]]: - str_constraints_key = key_to_str([db_parent_pk, constraints_name], separator=':') + str_constraints_key = key_to_str([constraints_name, db_parent_pk], separator=':') result : Tuple[ConstraintsModel, bool] = get_or_create_object(database, ConstraintsModel, str_constraints_key) db_constraints, created = result diff --git a/src/context/service/grpc_server/ContextServiceServicerImpl.py b/src/context/service/grpc_server/ContextServiceServicerImpl.py index d21868d3d..71c97bf9f 100644 --- a/src/context/service/grpc_server/ContextServiceServicerImpl.py +++ b/src/context/service/grpc_server/ContextServiceServicerImpl.py @@ -61,6 +61,7 @@ METHOD_NAMES = [ 'ListLinkIds', 'ListLinks', 'GetLink', 'SetLink', 'RemoveLink', 'GetLinkEvents', 'ListServiceIds', 'ListServices', 'GetService', 'SetService', 'RemoveService', 'GetServiceEvents', 'ListSliceIds', 'ListSlices', 'GetSlice', 'SetSlice', 'RemoveSlice', 'GetSliceEvents', + 'UnsetService', 'UnsetSlice', ] METRICS = create_metrics(SERVICE_NAME, METHOD_NAMES) @@ -277,8 +278,8 @@ class ContextServiceServicerImpl(ContextServiceServicer): ['should be == {:s}({:s})'.format('request.device_id.device_uuid.uuid', device_uuid)]) config_rules = grpc_config_rules_to_raw(request.device_config.config_rules) - running_config_result = update_config(self.database, device_uuid, 'running', config_rules) - db_running_config = running_config_result[0][0] + running_config_rules = update_config(self.database, device_uuid, 'device', config_rules) + db_running_config = running_config_rules[0][0] result : Tuple[DeviceModel, bool] = update_or_create_object(self.database, DeviceModel, device_uuid, { 'device_uuid' : device_uuid, @@ -483,12 +484,12 @@ class ContextServiceServicerImpl(ContextServiceServicer): str_service_key = key_to_str([context_uuid, service_uuid]) constraints_result = set_constraints( - self.database, str_service_key, 'constraints', request.service_constraints) + self.database, str_service_key, 'service', request.service_constraints) db_constraints = constraints_result[0][0] config_rules = grpc_config_rules_to_raw(request.service_config.config_rules) - running_config_result = update_config(self.database, str_service_key, 'running', config_rules) - db_running_config = running_config_result[0][0] + running_config_rules = update_config(self.database, str_service_key, 'service', config_rules) + db_running_config = running_config_rules[0][0] result : Tuple[ServiceModel, bool] = update_or_create_object(self.database, ServiceModel, str_service_key, { 'context_fk' : db_context, @@ -592,12 +593,12 @@ class ContextServiceServicerImpl(ContextServiceServicer): str_slice_key = key_to_str([context_uuid, slice_uuid]) constraints_result = set_constraints( - self.database, str_slice_key, 'constraints', request.slice_constraints) + self.database, str_slice_key, 'slice', request.slice_constraints) db_constraints = constraints_result[0][0] config_rules = grpc_config_rules_to_raw(request.slice_config.config_rules) - running_config_result = update_config(self.database, str_slice_key, 'running', config_rules) - db_running_config = running_config_result[0][0] + running_config_rules = update_config(self.database, str_slice_key, 'slice', config_rules) + db_running_config = running_config_rules[0][0] result : Tuple[SliceModel, bool] = update_or_create_object(self.database, SliceModel, str_slice_key, { 'context_fk' : db_context, @@ -656,6 +657,55 @@ class ContextServiceServicerImpl(ContextServiceServicer): notify_event(self.messagebroker, TOPIC_SLICE, event_type, {'slice_id': dict_slice_id}) return SliceId(**dict_slice_id) + @safe_and_metered_rpc_method(METRICS, LOGGER) + def UnsetSlice(self, request: Slice, context : grpc.ServicerContext) -> SliceId: + with self.lock: + context_uuid = request.slice_id.context_id.context_uuid.uuid + db_context : ContextModel = get_object(self.database, ContextModel, context_uuid) + + for i,endpoint_id in enumerate(request.slice_endpoint_ids): + endpoint_topology_context_uuid = endpoint_id.topology_id.context_id.context_uuid.uuid + if len(endpoint_topology_context_uuid) > 0 and context_uuid != endpoint_topology_context_uuid: + raise InvalidArgumentException( + 'request.slice_endpoint_ids[{:d}].topology_id.context_id.context_uuid.uuid'.format(i), + endpoint_topology_context_uuid, + ['should be == {:s}({:s})'.format( + 'request.slice_id.context_id.context_uuid.uuid', context_uuid)]) + + slice_uuid = request.slice_id.slice_uuid.uuid + str_slice_key = key_to_str([context_uuid, slice_uuid]) + + if len(request.slice_constraints) > 0: + raise NotImplementedError('UnsetSlice: removal of constraints') + if len(request.slice_config.config_rules) > 0: + raise NotImplementedError('UnsetSlice: removal of config rules') + if len(request.slice_endpoint_ids) > 0: + raise NotImplementedError('UnsetSlice: removal of endpoints') + + updated = False + + for service_id in request.slice_service_ids: + service_uuid = service_id.service_uuid.uuid + service_context_uuid = service_id.context_id.context_uuid.uuid + str_service_key = key_to_str([service_context_uuid, service_uuid]) + str_slice_service_key = key_to_str([str_slice_key, str_service_key], separator='--') + SliceServiceModel(self.database, str_slice_service_key).delete() + updated = True + + for subslice_id in request.slice_subslice_ids: + subslice_uuid = subslice_id.slice_uuid.uuid + subslice_context_uuid = subslice_id.context_id.context_uuid.uuid + str_subslice_key = key_to_str([subslice_context_uuid, subslice_uuid]) + str_slice_subslice_key = key_to_str([str_slice_key, str_subslice_key], separator='--') + SliceSubSliceModel(self.database, str_slice_subslice_key).delete() + updated = True + + event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE + db_slice : SliceModel = get_object(self.database, SliceModel, str_slice_key) + dict_slice_id = db_slice.dump_id() + notify_event(self.messagebroker, TOPIC_SLICE, event_type, {'slice_id': dict_slice_id}) + return SliceId(**dict_slice_id) + @safe_and_metered_rpc_method(METRICS, LOGGER) def RemoveSlice(self, request: SliceId, context : grpc.ServicerContext) -> Empty: with self.lock: -- GitLab