diff --git a/proto/context.proto b/proto/context.proto index 866876175f108c056f7e35c6457a1bf48a226a9c..ab7dd5e699a9816daf3e3a180fffc6bfde0a8103 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 6e8cbac6a28c1b24d1999b0d8db1240905b10f2c..da907341f799def94694817242c106a913e03327 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 53754caf4f9d2621ed8a6fdfd325d42f77f44a4f..dfd0c8773b6a7d2dea7bafa12c12018d62b7cdb8 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 bb2a37467ce3ad451bd29f824a5092ec1ad43cee..a5f90788e4783edf1eba76cf6fe461aaa96476e6 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 17a9b52e980bf0eec44ea58edfb35eac5471d016..449dcedeeaf10686ece58607d3a5fa4f4bf6a070 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 d21868d3d5faaa945c9a4d8c5a8f5b336cdafae7..71c97bf9ffc65942993dbdd966925f27aafad9ec 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: