diff --git a/src/device/service/drivers/ietf_l3vpn/TfsApiClient.py b/src/device/service/drivers/ietf_l3vpn/TfsApiClient.py index f635f1a75aba78fb3d54b9fb46275e6f2f2e2c29..b05278fa0c437a76b2abbed194d2069bd5f78c17 100644 --- a/src/device/service/drivers/ietf_l3vpn/TfsApiClient.py +++ b/src/device/service/drivers/ietf_l3vpn/TfsApiClient.py @@ -160,13 +160,26 @@ class TfsApiClient: def create_connectivity_service(self, l3vpn_data: dict) -> None: try: - requests.post(self._l3vpn_url, json=l3vpn_data) + # requests.post(self._l3vpn_url, json=l3vpn_data) + LOGGER.debug( + "[create_connectivity_service] l3vpn_data={:s}".format(str(l3vpn_data)) + ) + except requests.exceptions.ConnectionError: + raise Exception("faild to send post request to TFS L3VPN NBI") + + def update_connectivity_service(self, l3vpn_data: dict) -> None: + try: + # requests.post(self._l3vpn_url, json=l3vpn_data) + LOGGER.debug( + "[update_connectivity_service] l3vpn_data={:s}".format(str(l3vpn_data)) + ) except requests.exceptions.ConnectionError: raise Exception("faild to send post request to TFS L3VPN NBI") def delete_connectivity_service(self, service_uuid: str) -> None: url = self._l3vpn_url + f"/vpn-service={service_uuid}" try: - requests.delete(url, auth=self._auth) + # requests.delete(url, auth=self._auth) + LOGGER.debug("[delete_connectivity_service] url={:s}".format(str(url))) except requests.exceptions.ConnectionError: raise Exception("faild to send delete request to TFS L3VPN NBI") diff --git a/src/device/service/drivers/ietf_l3vpn/driver.py b/src/device/service/drivers/ietf_l3vpn/driver.py index 25d8f9319d5cc14b14f843c7d06a75cc59212560..45542527a5a51e6f09f1ccfc052d30ce440e8546 100644 --- a/src/device/service/drivers/ietf_l3vpn/driver.py +++ b/src/device/service/drivers/ietf_l3vpn/driver.py @@ -58,6 +58,9 @@ ALL_RESOURCE_KEYS = [ RE_GET_ENDPOINT_FROM_INTERFACE = re.compile(r"^\/interface\[([^\]]+)\].*") +RE_IETF_L3VPN_DATA = re.compile(r"^\/service\[[^\]]+\]\/IETFL3VPN$") +RE_IETF_L3VPN_OPERATION = re.compile(r"^\/service\[[^\]]+\]\/IETFL3VPN\/operation$") + DRIVER_NAME = "ietf_l3vpn" METRICS_POOL = MetricsPool("Device", "Driver", labels={"driver": DRIVER_NAME}) @@ -147,7 +150,8 @@ class IetfL3VpnDriver(_Driver): if self.__started.is_set(): return True try: - requests.get(url, timeout=self.__timeout, auth=self.__auth) + # requests.get(url, timeout=self.__timeout, auth=self.__auth) + ... except requests.exceptions.Timeout: LOGGER.exception("Timeout connecting {:s}".format(url)) return False @@ -215,25 +219,43 @@ class IetfL3VpnDriver(_Driver): if len(resources) == 0: return results with self.__lock: + for resource in resources: + resource_key, resource_value = resource + if RE_IETF_L3VPN_OPERATION.match(resource_key): + operation_type = json.loads(resource_value)["type"] + results.append((resource_key, True)) + break + else: + raise Exception("operation type not found in resources") for resource in resources: LOGGER.info("resource = {:s}".format(str(resource))) resource_key, resource_value = resource + if not RE_IETF_L3VPN_DATA.match(resource_key): + continue try: resource_value = json.loads(resource_value) - service_uuid = resource_value["uuid"] - - if service_exists(self.__tfs_nbi_root, self.__auth, service_uuid): - exc = NotImplementedError( - "IETF L3VPN Service Update is still not supported" - ) - results.append((resource[0], exc)) - continue - l3vpn_datamodel = create_l3vpn_datamodel( - service_uuid, resource_value + # if service_exists(self.__tfs_nbi_root, self.__auth, service_uuid): + # exc = NotImplementedError( + # "IETF L3VPN Service Update is still not supported" + # ) + # results.append((resource[0], exc)) + # continue + if operation_type == "create": + service_id = resource_value["network-slice-services"]["slice-service"][0]["id"] + l3vpn_datamodel = create_l3vpn_datamodel( + service_id, resource_value, operation_type ) - self.tac.create_connectivity_service(l3vpn_datamodel) + self.tac.create_connectivity_service(l3vpn_datamodel) + elif operation_type == "update": + service_id = resource_value["network-slice-services"]["slice-service"][0]["id"] + l3vpn_datamodel = create_l3vpn_datamodel( + service_id, resource_value, operation_type + ) + self.tac.update_connectivity_service(l3vpn_datamodel) + else: + raise Exception("operation type not supported") results.append((resource_key, True)) except Exception as e: # pylint: disable=broad-except LOGGER.exception( @@ -255,12 +277,14 @@ class IetfL3VpnDriver(_Driver): for resource in resources: LOGGER.info("resource = {:s}".format(str(resource))) resource_key, resource_value = resource + if not RE_IETF_L3VPN_DATA.match(resource_key): + continue try: resource_value = json.loads(resource_value) - service_uuid = resource_value["uuid"] + service_id = resource_value["id"] - if service_exists(self.__tfs_nbi_root, self.__auth, service_uuid): - self.tac.delete_connectivity_service(service_uuid) + # if service_exists(self.__tfs_nbi_root, self.__auth, service_uuid): + self.tac.delete_connectivity_service(service_id) results.append((resource_key, True)) except Exception as e: # pylint: disable=broad-except LOGGER.exception( diff --git a/src/service/service/service_handlers/l3nm_ietfl3vpn/ConfigRules.py b/src/service/service/service_handlers/l3nm_ietfl3vpn/ConfigRules.py index 73fe9c269b26e11d160434005927803cd89973b6..72f0dfd3153e219d235a6a45c4ee450ad7fbf3d8 100644 --- a/src/service/service/service_handlers/l3nm_ietfl3vpn/ConfigRules.py +++ b/src/service/service/service_handlers/l3nm_ietfl3vpn/ConfigRules.py @@ -15,7 +15,10 @@ from typing import Dict, List, Tuple, TypedDict from common.proto.context_pb2 import Link -from common.tools.object_factory.ConfigRule import json_config_rule_delete +from common.tools.object_factory.ConfigRule import ( + json_config_rule_delete, + json_config_rule_set, +) from context.client.ContextClient import ContextClient @@ -27,7 +30,9 @@ class LANPrefixesDict(TypedDict): SITE_NETWORK_ACCESS_TYPE = "ietf-l3vpn-svc:multipoint" -def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: +def setup_config_rules( + service_uuid: str, json_settings: Dict, operation_type: str +) -> List[Dict]: src_device_uuid: str = json_settings["src_device_name"] src_endpoint_uuid: str = json_settings["src_endpoint_name"] src_site_location: str = json_settings["src_site_location"] @@ -239,18 +244,27 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: "sites": sites, } } - - return l3_vpn_data_model + json_config_rules = [ + json_config_rule_set( + "/service[{:s}]/IETFL3VPN".format(service_uuid), + l3_vpn_data_model, + ), + json_config_rule_set( + "/service[{:s}]/IETFL3VPN/operation".format(service_uuid), + {"type": operation_type}, + ), + ] + return json_config_rules def teardown_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: json_config_rules = [ json_config_rule_delete( - "/service[{:s}]/IETFSlice".format(service_uuid), - {}, + "/service[{:s}]/IETFL3VPN".format(service_uuid), + {"id": service_uuid}, ), json_config_rule_delete( - "/service[{:s}]/IETFSlice/operation".format(service_uuid), + "/service[{:s}]/IETFL3VPN/operation".format(service_uuid), {}, ), ] diff --git a/src/service/service/service_handlers/l3nm_ietfl3vpn/L3NM_IETFL3VPN_ServiceHandler.py b/src/service/service/service_handlers/l3nm_ietfl3vpn/L3NM_IETFL3VPN_ServiceHandler.py index 4b4e9add563de81c6228b74a9494cb86326c9276..e1d8b5c50791251e0e835a75edd8da137501467a 100644 --- a/src/service/service/service_handlers/l3nm_ietfl3vpn/L3NM_IETFL3VPN_ServiceHandler.py +++ b/src/service/service/service_handlers/l3nm_ietfl3vpn/L3NM_IETFL3VPN_ServiceHandler.py @@ -104,13 +104,13 @@ def extract_match_criterion_ipv4_info( dst_port = type_value["value"][0] elif type_value["type"] == "ietf-network-slice-service:vlan": vlan = type_value["value"][0] - return Ipv4Info( - src_ip=src_ip, - dst_ip=dst_ip, - src_port=src_port, - dst_port=dst_port, - vlan=vlan, - ) + return Ipv4Info( + src_ip=src_ip, + dst_ip=dst_ip, + src_port=src_port, + dst_port=dst_port, + vlan=vlan, + ) class L3NM_IETFL3VPN_ServiceHandler(_ServiceHandler): @@ -130,7 +130,7 @@ class L3NM_IETFL3VPN_ServiceHandler(_ServiceHandler): DeviceId(**json_device_id(device_uuid)) ) device_controller = self.__task_executor.get_device_controller(device_obj) - if device_controller.device_type == DeviceTypeEnum.IP_SDN_CONTROLLER: + if device_controller.device_type == DeviceTypeEnum.IP_SDN_CONTROLLER.value: src_device_uuid, src_endpoint_uuid = device_uuid, endpoint_uuid src_device_controller = device_controller break @@ -142,7 +142,7 @@ class L3NM_IETFL3VPN_ServiceHandler(_ServiceHandler): DeviceId(**json_device_id(device_uuid)) ) device_controller = self.__task_executor.get_device_controller(device_obj) - if device_controller.device_type == DeviceTypeEnum.IP_SDN_CONTROLLER: + if device_controller.device_type == DeviceTypeEnum.IP_SDN_CONTROLLER.value: dst_device_uuid, dst_endpoint_uuid = device_uuid, endpoint_uuid dst_device_controller = device_controller break @@ -216,63 +216,63 @@ class L3NM_IETFL3VPN_ServiceHandler(_ServiceHandler): ietf_slice_candidate_cr = get_custom_config_rule( service_config, CANDIDATE_RESOURCE_KEY ) - if ( + if not ( ietf_slice_running_cr and ietf_slice_candidate_cr ): # The request comes from the IETF Slice NBI - running_resource_value_dict = json.loads( - ietf_slice_running_cr.custom.resource_value - ) - candidate_resource_value_dict = json.loads( - ietf_slice_candidate_cr.custom.resource_value - ) - running_candidate_diff = get_running_candidate_ietf_slice_data_diff( - service_config - ) - 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" - ] - connection_group = connection_groups[0] - connecitivity_constructs = connection_group["connectivity-construct"] - connecitivity_construct = connecitivity_constructs[0] - src_sdp_idx = connecitivity_construct["p2p-sender-sdp"] - dst_sdp_idx = connecitivity_construct["p2p-receiver-sdp"] - src_sdp = next(sdp for sdp in sdps if sdp["id"] == src_sdp_idx) - dst_sdp = next(sdp for sdp in sdps if sdp["id"] == dst_sdp_idx) - src_match_criterion = src_sdp["service-match-criteria"][ - "match-criterion" - ][0] - dst_match_criterion = dst_sdp["service-match-criteria"][ - "match-criterion" - ][0] - src_match_criterion_ipv4_info = extract_match_criterion_ipv4_info( - src_match_criterion + raise Exception("IETF Slice data not found") + running_resource_value_dict = json.loads( + ietf_slice_running_cr.custom.resource_value + ) + candidate_resource_value_dict = json.loads( + ietf_slice_candidate_cr.custom.resource_value + ) + running_candidate_diff = get_running_candidate_ietf_slice_data_diff( + service_config + ) + LOGGER.debug("running_candidate_diff: %s", running_candidate_diff) + 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"] + connection_group = connection_groups[0] + connecitivity_constructs = connection_group["connectivity-construct"] + connecitivity_construct = connecitivity_constructs[0] + src_sdp_idx = connecitivity_construct["p2p-sender-sdp"] + dst_sdp_idx = connecitivity_construct["p2p-receiver-sdp"] + src_sdp = next(sdp for sdp in sdps if sdp["id"] == src_sdp_idx) + dst_sdp = next(sdp for sdp in sdps if sdp["id"] == dst_sdp_idx) + src_match_criterion = src_sdp["service-match-criteria"]["match-criterion"][ + 0 + ] + dst_match_criterion = dst_sdp["service-match-criteria"]["match-criterion"][ + 0 + ] + src_match_criterion_ipv4_info = extract_match_criterion_ipv4_info( + src_match_criterion + ) + dst_match_criterion_ipv4_info = extract_match_criterion_ipv4_info( + dst_match_criterion + ) + src_ipv4_lan_prefixes = [ + LANPrefixesDict( + lan=src_match_criterion_ipv4_info["dst_ip"], + lan_tag=src_match_criterion_ipv4_info["vlan"], ) - dst_match_criterion_ipv4_info = extract_match_criterion_ipv4_info( - dst_match_criterion + ] + dst_ipv4_lan_prefixes = [ + LANPrefixesDict( + lan=dst_match_criterion_ipv4_info["dst_ip"], + lan_tag=dst_match_criterion_ipv4_info["vlan"], ) - src_ipv4_lan_prefixes = [ - LANPrefixesDict( - lan=src_match_criterion_ipv4_info["dst_ip"], - lan_tag=src_match_criterion_ipv4_info["vlan"], - ) - ] - dst_ipv4_lan_prefixes = [ - LANPrefixesDict( - lan=dst_match_criterion_ipv4_info["dst_ip"], - lan_tag=dst_match_criterion_ipv4_info["vlan"], - ) - ] - src_ce_address = src_endpoint_settings["address_ip"] - src_pe_address = src_ce_address - src_ce_address_prefix = src_endpoint_settings["address_prefix"] - dst_ce_address = dst_endpoint_settings["address_ip"] - dst_pe_address = dst_ce_address - dst_ce_address_prefix = dst_endpoint_settings["address_prefix"] + ] + src_ce_address = src_endpoint_settings["address_ip"] + src_pe_address = src_ce_address + src_ce_address_prefix = src_endpoint_settings["address_prefix"] + dst_ce_address = dst_endpoint_settings["address_ip"] + dst_pe_address = dst_ce_address + dst_ce_address_prefix = dst_endpoint_settings["address_prefix"] resource_value_dict = { "uuid": service_uuid, "src_device_name": src_device_name,