diff --git a/src/service/service/service_handlers/l3nm_nce/ConfigRules.py b/src/service/service/service_handlers/l3nm_nce/ConfigRules.py index 471757bda762508e8086cd7933884d8f38e3352a..e74fb6630f8a78099c75ea123c2b9ae8f5f5d30d 100644 --- a/src/service/service/service_handlers/l3nm_nce/ConfigRules.py +++ b/src/service/service/service_handlers/l3nm_nce/ConfigRules.py @@ -18,7 +18,6 @@ from common.tools.object_factory.ConfigRule import ( json_config_rule_delete, json_config_rule_set, ) -from service.service.service_handler_api.AnyTreeTools import TreeNode def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: diff --git a/src/service/service/service_handlers/l3nm_nce/L3NMNCEServiceHandler.py b/src/service/service/service_handlers/l3nm_nce/L3NMNCEServiceHandler.py index 1ca908a40e8593f68d47d5945ce9a108b5f47d49..a93764ce7ceb4e7ded4ac6abffffe8f2a06c0a54 100644 --- a/src/service/service/service_handlers/l3nm_nce/L3NMNCEServiceHandler.py +++ b/src/service/service/service_handlers/l3nm_nce/L3NMNCEServiceHandler.py @@ -29,7 +29,6 @@ from service.service.service_handler_api._ServiceHandler import _ServiceHandler from service.service.service_handler_api.SettingsHandler import SettingsHandler from service.service.service_handler_api.Tools import ( get_device_endpoint_uuids, - get_endpoint_matching, ) from service.service.task_scheduler.TaskExecutor import TaskExecutor @@ -104,253 +103,273 @@ class L3NMNCEServiceHandler(_ServiceHandler): chk_type("endpoints", endpoints, list) if len(endpoints) == 0: return [] - context_client = ContextClient() - service_uuid = self.__service.service_id.service_uuid.uuid - service_name = self.__service.name - service_config = self.__service.service_config - settings = self.__settings_handler.get("/settings") - src_device_uuid, src_endpoint_uuid = get_device_endpoint_uuids(endpoints[0]) - src_device_obj = self.__task_executor.get_device( - DeviceId(**json_device_id(src_device_uuid)) - ) - controller = self.__task_executor.get_device_controller(src_device_obj) - list_devices = context_client.ListDevices(Empty()) - devices = list_devices.devices - device_name_device = {d.name: d for d in devices} - device_uuid_device = {d.device_id.device_uuid.uuid: d for d in devices} - running_candidate_diff, running_candidate_diff_no_order = ( - get_running_candidate_ietf_slice_data_diff(service_config) - ) - candidate_ietf_slice_cr = get_custom_config_rule( - service_config, CANDIDATE_RESOURCE_KEY - ) - candidate_resource_value_dict = json.loads( - candidate_ietf_slice_cr.custom.resource_value - ) - running_ietf_slice_cr = get_custom_config_rule( - service_config, RUNNING_RESOURCE_KEY - ) - running_resource_value_dict = json.loads( - running_ietf_slice_cr.custom.resource_value - ) - LOGGER.debug(f"P70: {running_candidate_diff}") - if not running_candidate_diff: # Slice Creation - operation_type = "create" - slice_services = candidate_resource_value_dict["network-slice-services"][ - "slice-service" - ] - slice_service = slice_services[0] - sdps = slice_service["sdps"]["sdp"] - connection_groups = slice_service["connection-groups"]["connection-group"] - sdp_ids = [sdp["id"] for sdp in sdps] - for sdp in sdps: - node_id = sdp["node-id"] - device_obj = device_name_device[node_id] - device_controller = self.__task_executor.get_device_controller( - device_obj - ) - LOGGER.debug(f"P71: {controller}") - LOGGER.debug(f"P72: {device_controller}") - if device_controller is None or controller.name != device_controller.name: - continue - src_sdp_idx = sdp_ids.pop(sdp_ids.index(sdp["id"])) - dst_sdp_idx = sdp_ids[0] - match_criteria = sdp["service-match-criteria"]["match-criterion"] + results = [] + try: + context_client = ContextClient() + service_name = self.__service.name + service_config = self.__service.service_config + settings = self.__settings_handler.get("/settings") + src_device_uuid, src_endpoint_uuid = get_device_endpoint_uuids(endpoints[0]) + src_device_obj = self.__task_executor.get_device( + DeviceId(**json_device_id(src_device_uuid)) + ) + controller = self.__task_executor.get_device_controller(src_device_obj) + list_devices = context_client.ListDevices(Empty()) + devices = list_devices.devices + device_name_device = {d.name: d for d in devices} + device_uuid_device = {d.device_id.device_uuid.uuid: d for d in devices} + running_candidate_diff, running_candidate_diff_no_order = ( + get_running_candidate_ietf_slice_data_diff(service_config) + ) + candidate_ietf_slice_cr = get_custom_config_rule( + service_config, CANDIDATE_RESOURCE_KEY + ) + candidate_resource_value_dict = json.loads( + candidate_ietf_slice_cr.custom.resource_value + ) + running_ietf_slice_cr = get_custom_config_rule( + service_config, RUNNING_RESOURCE_KEY + ) + running_resource_value_dict = json.loads( + running_ietf_slice_cr.custom.resource_value + ) + if not running_candidate_diff: # Slice Creation + operation_type = "create" + slice_services = candidate_resource_value_dict[ + "network-slice-services" + ]["slice-service"] + slice_service = slice_services[0] + sdps = slice_service["sdps"]["sdp"] + connection_groups = slice_service["connection-groups"][ + "connection-group" + ] + sdp_ids = [sdp["id"] for sdp in sdps] + for sdp in sdps: + node_id = sdp["node-id"] + device_obj = device_name_device[node_id] + device_controller = self.__task_executor.get_device_controller( + device_obj + ) + if ( + device_controller is None + or controller.name != device_controller.name + ): + continue + src_sdp_idx = sdp_ids.pop(sdp_ids.index(sdp["id"])) + dst_sdp_idx = sdp_ids[0] + match_criteria = sdp["service-match-criteria"]["match-criterion"] + match_criterion = match_criteria[0] + connection_grp_id = match_criterion["target-connection-group-id"] + break + else: + raise Exception("connection group id not found") + elif "iterable_item_added" in running_candidate_diff: # new SDP added + slice_services = candidate_resource_value_dict[ + "network-slice-services" + ]["slice-service"] + slice_service = slice_services[0] + sdps = slice_service["sdps"]["sdp"] + connection_groups = slice_service["connection-groups"][ + "connection-group" + ] + operation_type = "create" + added_items = { + "sdp": {"sdp_idx": None, "value": {}}, + "connection_group": {"connection_group_idx": None, "value": {}}, + "match_criterion": { + "sdp_idx": None, + "match_criterion_idx": None, + "value": {}, + }, + } + for added_key, added_value in running_candidate_diff[ + "iterable_item_added" + ].items(): + sdp_match = SDP_DIFF_RE.match(added_key) + connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key) + match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key) + if sdp_match: + added_items["sdp"] = { + "sdp_idx": int(sdp_match.groups()[0]), + "value": added_value, + } + elif connection_group_match: + added_items["connection_group"] = { + "connection_group_idx": int( + connection_group_match.groups()[0] + ), + "value": added_value, + } + elif match_criterion_match: + added_items["match_criterion"] = { + "sdp_idx": int(match_criterion_match.groups()[0]), + "match_criterion_idx": int( + match_criterion_match.groups()[1] + ), + "value": added_value, + } + new_sdp = sdps[added_items["sdp"]["sdp_idx"]] + src_sdp_idx = new_sdp["id"] + dst_sdp_idx = sdps[added_items["match_criterion"]["sdp_idx"]]["id"] + connection_grp_id = connection_groups[ + added_items["connection_group"]["connection_group_idx"] + ]["id"] + if ( + connection_grp_id + != added_items["match_criterion"]["value"][ + "target-connection-group-id" + ] + ): + raise Exception( + "connection group missmatch in destination sdp and added connection group" + ) + match_criteria = new_sdp["service-match-criteria"]["match-criterion"] match_criterion = match_criteria[0] - connection_grp_id = match_criterion["target-connection-group-id"] - break - else: - raise Exception("connection group id not found") - elif "iterable_item_added" in running_candidate_diff: # new SDP added - slice_services = candidate_resource_value_dict["network-slice-services"][ - "slice-service" - ] - slice_service = slice_services[0] - sdps = slice_service["sdps"]["sdp"] - connection_groups = slice_service["connection-groups"]["connection-group"] - operation_type = "create" - added_items = { - "sdp": {"sdp_idx": None, "value": {}}, - "connection_group": {"connection_group_idx": None, "value": {}}, - "match_criterion": { - "sdp_idx": None, - "match_criterion_idx": None, - "value": {}, - }, - } - for added_key, added_value in running_candidate_diff[ - "iterable_item_added" - ].items(): - sdp_match = SDP_DIFF_RE.match(added_key) - connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key) - match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key) - if sdp_match: - added_items["sdp"] = { - "sdp_idx": int(sdp_match.groups()[0]), - "value": added_value, - } - elif connection_group_match: - added_items["connection_group"] = { - "connection_group_idx": int(connection_group_match.groups()[0]), - "value": added_value, - } - elif match_criterion_match: - added_items["match_criterion"] = { - "sdp_idx": int(match_criterion_match.groups()[0]), - "match_criterion_idx": int(match_criterion_match.groups()[1]), - "value": added_value, - } - new_sdp = sdps[added_items["sdp"]["sdp_idx"]] - src_sdp_idx = new_sdp["id"] - dst_sdp_idx = sdps[added_items["match_criterion"]["sdp_idx"]]["id"] - connection_grp_id = connection_groups[ - added_items["connection_group"]["connection_group_idx"] - ]["id"] - if ( - connection_grp_id - != added_items["match_criterion"]["value"]["target-connection-group-id"] - ): - raise Exception( - "connection group missmatch in destination sdp and added connection group" - ) - match_criteria = new_sdp["service-match-criteria"]["match-criterion"] - match_criterion = match_criteria[0] - elif "iterable_item_removed" in running_candidate_diff: # new SDP added - slice_services = running_resource_value_dict["network-slice-services"][ - "slice-service" - ] - slice_service = slice_services[0] - sdps = slice_service["sdps"]["sdp"] - connection_groups = slice_service["connection-groups"]["connection-group"] - operation_type = "delete" - added_items = { - "sdp": {"sdp_idx": None, "value": {}}, - "connection_group": {"connection_group_idx": None, "value": {}}, - "match_criterion": { - "sdp_idx": None, - "match_criterion_idx": None, - "value": {}, - }, - } - for added_key, added_value in running_candidate_diff[ - "iterable_item_removed" - ].items(): - sdp_match = SDP_DIFF_RE.match(added_key) - connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key) - match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key) - if sdp_match: - added_items["sdp"] = { - "sdp_idx": int(sdp_match.groups()[0]), - "value": added_value, - } - elif connection_group_match: - added_items["connection_group"] = { - "connection_group_idx": int(connection_group_match.groups()[0]), - "value": added_value, - } - elif match_criterion_match: - added_items["match_criterion"] = { - "sdp_idx": int(match_criterion_match.groups()[0]), - "match_criterion_idx": int(match_criterion_match.groups()[1]), - "value": added_value, - } - new_sdp = sdps[added_items["sdp"]["sdp_idx"]] - src_sdp_idx = new_sdp["id"] - dst_sdp_idx = sdps[added_items["match_criterion"]["sdp_idx"]]["id"] - connection_grp_id = connection_groups[ - added_items["connection_group"]["connection_group_idx"] - ]["id"] - if ( - connection_grp_id - != added_items["match_criterion"]["value"][ - "target-connection-group-id" + elif "iterable_item_removed" in running_candidate_diff: # new SDP added + slice_services = running_resource_value_dict["network-slice-services"][ + "slice-service" ] - ): - raise Exception( - "connection group missmatch in destination sdp and added connection group" - ) - match_criteria = new_sdp["service-match-criteria"]["match-criterion"] - match_criterion = match_criteria[0] - for type_value in match_criterion["match-type"]: - if type_value["type"] == "ietf-network-slice-service:source-ip-prefix": - src_ip = type_value["value"][0].split("/")[0] - elif ( - type_value["type"] == "ietf-network-slice-service:destination-ip-prefix" - ): - dst_ip = type_value["value"][0].split("/")[0] - elif type_value["type"] == "ietf-network-slice-service:source-tcp-port": - src_port = type_value["value"][0] - elif ( - type_value["type"] == "ietf-network-slice-service:destination-tcp-port" - ): - dst_port = type_value["value"][0] - qos_info = { - "upstream": {"max_delay": "0", "bw": "0", "packet_loss": "0"}, - "downstream": {"max_delay": "0", "bw": "0", "packet_loss": "0"}, - } - for cg in connection_groups: - if cg["id"] != connection_grp_id: - continue - for cc in cg["connectivity-construct"]: + slice_service = slice_services[0] + sdps = slice_service["sdps"]["sdp"] + connection_groups = slice_service["connection-groups"][ + "connection-group" + ] + operation_type = "delete" + added_items = { + "sdp": {"sdp_idx": None, "value": {}}, + "connection_group": {"connection_group_idx": None, "value": {}}, + "match_criterion": { + "sdp_idx": None, + "match_criterion_idx": None, + "value": {}, + }, + } + for added_key, added_value in running_candidate_diff[ + "iterable_item_removed" + ].items(): + sdp_match = SDP_DIFF_RE.match(added_key) + connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key) + match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key) + if sdp_match: + added_items["sdp"] = { + "sdp_idx": int(sdp_match.groups()[0]), + "value": added_value, + } + elif connection_group_match: + added_items["connection_group"] = { + "connection_group_idx": int( + connection_group_match.groups()[0] + ), + "value": added_value, + } + elif match_criterion_match: + added_items["match_criterion"] = { + "sdp_idx": int(match_criterion_match.groups()[0]), + "match_criterion_idx": int( + match_criterion_match.groups()[1] + ), + "value": added_value, + } + new_sdp = sdps[added_items["sdp"]["sdp_idx"]] + src_sdp_idx = new_sdp["id"] + dst_sdp_idx = sdps[added_items["match_criterion"]["sdp_idx"]]["id"] + connection_grp_id = connection_groups[ + added_items["connection_group"]["connection_group_idx"] + ]["id"] if ( - cc["p2p-sender-sdp"] == src_sdp_idx - and cc["p2p-receiver-sdp"] == dst_sdp_idx + connection_grp_id + != added_items["match_criterion"]["value"][ + "target-connection-group-id" + ] ): - direction = "upstream" + raise Exception( + "connection group missmatch in destination sdp and added connection group" + ) + match_criteria = new_sdp["service-match-criteria"]["match-criterion"] + match_criterion = match_criteria[0] + for type_value in match_criterion["match-type"]: + if type_value["type"] == "ietf-network-slice-service:source-ip-prefix": + src_ip = type_value["value"][0].split("/")[0] elif ( - cc["p2p-sender-sdp"] == dst_sdp_idx - and cc["p2p-receiver-sdp"] == src_sdp_idx + type_value["type"] + == "ietf-network-slice-service:destination-ip-prefix" ): - direction = "downstream" - else: - raise Exception("invalid sender and receiver sdp ids") - for metric_bound in cc["service-slo-sle-policy"]["slo-policy"][ - "metric-bound" - ]: + dst_ip = type_value["value"][0].split("/")[0] + elif type_value["type"] == "ietf-network-slice-service:source-tcp-port": + src_port = type_value["value"][0] + elif ( + type_value["type"] + == "ietf-network-slice-service:destination-tcp-port" + ): + dst_port = type_value["value"][0] + qos_info = { + "upstream": {"max_delay": "0", "bw": "0", "packet_loss": "0"}, + "downstream": {"max_delay": "0", "bw": "0", "packet_loss": "0"}, + } + for cg in connection_groups: + if cg["id"] != connection_grp_id: + continue + for cc in cg["connectivity-construct"]: if ( - metric_bound["metric-type"] - == "ietf-network-slice-service:one-way-delay-maximum" - and metric_bound["metric-unit"] == "milliseconds" - ): - qos_info[direction]["max_delay"] = metric_bound["bound"] - elif ( - metric_bound["metric-type"] - == "ietf-network-slice-service:one-way-bandwidth" - and metric_bound["metric-unit"] == "Mbps" + cc["p2p-sender-sdp"] == src_sdp_idx + and cc["p2p-receiver-sdp"] == dst_sdp_idx ): - qos_info[direction]["bw"] = metric_bound["bound"] + direction = "upstream" elif ( - metric_bound["metric-type"] - == "ietf-network-slice-service:two-way-packet-loss" - and metric_bound["metric-unit"] == "percentage" + cc["p2p-sender-sdp"] == dst_sdp_idx + and cc["p2p-receiver-sdp"] == src_sdp_idx ): - qos_info[direction]["packet_loss"] = metric_bound[ - "percentile-value" - ] - break - results = [] - resource_value_dict = { - "uuid": service_uuid, - "operation_type": operation_type, - "app_flow_id": f"{src_sdp_idx}_{dst_sdp_idx}_{service_name}", - "app_flow_user_id": str(uuid4()), - "max_latency": int(qos_info["upstream"]["max_delay"]), - "max_jitter": 10, - "max_loss": float(qos_info["upstream"]["packet_loss"]), - "upstream_assure_bw": int(qos_info["upstream"]["bw"]) * 1e6, - "upstream_max_bw": 2 * int(qos_info["upstream"]["bw"]) * 1e6, - "downstream_assure_bw": int(qos_info["downstream"]["bw"]) * 1e6, - "downstream_max_bw": 2 * int(qos_info["downstream"]["bw"]) * 1e6, - "src_ip": src_ip, - "src_port": src_port, - "dst_ip": dst_ip, - "dst_port": dst_port, - } - json_config_rules = setup_config_rules(service_uuid, resource_value_dict) - del controller.device_config.config_rules[:] - for jcr in json_config_rules: - controller.device_config.config_rules.append(ConfigRule(**jcr)) - self.__task_executor.configure_device(controller) + direction = "downstream" + else: + raise Exception("invalid sender and receiver sdp ids") + for metric_bound in cc["service-slo-sle-policy"]["slo-policy"][ + "metric-bound" + ]: + if ( + metric_bound["metric-type"] + == "ietf-network-slice-service:one-way-delay-maximum" + and metric_bound["metric-unit"] == "milliseconds" + ): + qos_info[direction]["max_delay"] = metric_bound["bound"] + elif ( + metric_bound["metric-type"] + == "ietf-network-slice-service:one-way-bandwidth" + and metric_bound["metric-unit"] == "Mbps" + ): + qos_info[direction]["bw"] = metric_bound["bound"] + elif ( + metric_bound["metric-type"] + == "ietf-network-slice-service:two-way-packet-loss" + and metric_bound["metric-unit"] == "percentage" + ): + qos_info[direction]["packet_loss"] = metric_bound[ + "percentile-value" + ] + break + resource_value_dict = { + "uuid": service_name, + "operation_type": operation_type, + "app_flow_id": f"{src_sdp_idx}_{dst_sdp_idx}_{service_name}", + "app_flow_user_id": str(uuid4()), + "max_latency": int(qos_info["upstream"]["max_delay"]), + "max_jitter": 10, + "max_loss": float(qos_info["upstream"]["packet_loss"]), + "upstream_assure_bw": int(qos_info["upstream"]["bw"]) * 1e6, + "upstream_max_bw": 2 * int(qos_info["upstream"]["bw"]) * 1e6, + "downstream_assure_bw": int(qos_info["downstream"]["bw"]) * 1e6, + "downstream_max_bw": 2 * int(qos_info["downstream"]["bw"]) * 1e6, + "src_ip": src_ip, + "src_port": src_port, + "dst_ip": dst_ip, + "dst_port": dst_port, + } + json_config_rules = setup_config_rules(service_name, resource_value_dict) + del controller.device_config.config_rules[:] + for jcr in json_config_rules: + controller.device_config.config_rules.append(ConfigRule(**jcr)) + self.__task_executor.configure_device(controller) + except Exception as e: # pylint: disable=broad-except + results.append(e) return results @metered_subclass_method(METRICS_POOL)