Loading src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py +40 −49 Original line number Diff line number Diff line Loading @@ -24,21 +24,23 @@ from .Constants import SPECIAL_RESOURCE_MAPPINGS from .TfsApiClient import TfsApiClient from .Tools import compose_resource_endpoint LOGGER = logging.getLogger(__name__) ALL_RESOURCE_KEYS = [ RESOURCE_ENDPOINTS, RESOURCE_SERVICES, ] 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$") 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}) class IetfL3VpnDriver(_Driver): def __init__(self, address : str, port : str, **settings) -> None: super().__init__(DRIVER_NAME, address, int(port), **settings) Loading @@ -54,7 +56,6 @@ class IetfL3VpnDriver(_Driver): self.address, self.port, scheme=scheme, username=username, password=password, timeout=timeout ) #self.__tfs_nbi_root = "{:s}://{:s}:{:d}".format(scheme, self.address, int(self.port)) # Options are: # disabled --> just import endpoints as usual Loading Loading @@ -90,7 +91,7 @@ class IetfL3VpnDriver(_Driver): resource_key, resource_value = resource chk_string(str_resource_name, resource_key, allow_empty=False) resource_path = resource_key.split("/") except Exception as e: # pylint: disable=broad-except except Exception as e: LOGGER.exception( "Exception validating {:s}: {:s}".format( str_resource_name, str(resource_key) Loading @@ -114,14 +115,9 @@ class IetfL3VpnDriver(_Driver): def Connect(self) -> bool: with self.__lock: if self.__started.is_set(): return True try: self.tac.check_credentials() except: # pylint: disable=bare-except LOGGER.exception('Exception checking credentials') return False else: self.__started.set() return True checked = self.tac.check_credentials(raise_if_fail=False) if checked: self.__started.set() return checked def Disconnect(self) -> bool: with self.__lock: Loading Loading @@ -179,12 +175,14 @@ class IetfL3VpnDriver(_Driver): for resource in resources: resource_key, resource_value = resource if RE_IETF_L3VPN_OPERATION.match(resource_key): operation_type = json.loads(resource_value)["type"] 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: raise Exception('operation type not found in resources') for i, resource in enumerate(resources): str_resource_name = 'resource_key[#{:d}]'.format(i) LOGGER.info('resource = {:s}'.format(str(resource))) resource_key, resource_value = resource if not RE_IETF_L3VPN_DATA.match(resource_key): Loading @@ -192,31 +190,24 @@ class IetfL3VpnDriver(_Driver): try: resource_value = json.loads(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["ietf-l3vpn-svc:l3vpn-svc"][ "vpn-services" ]["vpn-service"][0]["vpn-id"] service_uuid = resource_value['ietf-l3vpn-svc:l3vpn-svc'][ 'vpn-services' ]['vpn-service'][0]['vpn-id'] if operation_type == 'create': self.tac.create_connectivity_service(resource_value) elif operation_type == "update": service_id = resource_value["ietf-l3vpn-svc:l3vpn-svc"][ "vpn-services" ]["vpn-service"][0]["vpn-id"] elif operation_type == 'update': self.tac.update_connectivity_service(resource_value) elif operation_type == 'delete': self.tac.delete_connectivity_service(service_uuid) else: raise Exception("operation type not supported") MSG = 'OperationType({:s}) not supported' raise Exception(MSG.format(str(operation_type))) results.append((resource_key, True)) except Exception as e: # pylint: disable=broad-except LOGGER.exception( "Unhandled error processing resource_key({:s})".format( str(resource_key) ) ) except Exception as e: MSG = 'Unhandled error processing {:s}: resource_key({:s})' LOGGER.exception(MSG.format(str_resource_name, str(resource_key))) results.append((resource_key, e)) return results Loading @@ -228,24 +219,24 @@ class IetfL3VpnDriver(_Driver): if len(resources) == 0: return results with self.__lock: for resource in resources: LOGGER.info("resource = {:s}".format(str(resource))) for i, resource in enumerate(resources): str_resource_name = 'resource_key[#{:d}]'.format(i) 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_id = resource_value["id"] # if service_exists(self.__tfs_nbi_root, self.__auth, service_uuid): self.tac.delete_connectivity_service(service_id) service_uuid = resource_value['ietf-l3vpn-svc:l3vpn-svc'][ 'vpn-services' ]['vpn-service'][0]['vpn-id'] self.tac.delete_connectivity_service(service_uuid) results.append((resource_key, True)) except Exception as e: # pylint: disable=broad-except LOGGER.exception( "Unhandled error processing resource_key({:s})".format( str(resource_key) ) ) except Exception as e: MSG = 'Unhandled error processing {:s}: resource_key({:s})' LOGGER.exception(MSG.format(str_resource_name, str(resource_key))) results.append((resource_key, e)) return results Loading src/device/service/drivers/ietf_l3vpn/TfsApiClient.py +53 −19 Original line number Diff line number Diff line Loading @@ -17,10 +17,15 @@ from typing import Dict, List, Optional from common.tools.client.RestApiClient import RestApiClient from device.service.driver_api.ImportTopologyEnum import ImportTopologyEnum GET_CONTEXT_IDS_URL = '/tfs-api/context_ids' GET_DEVICES_URL = '/tfs-api/devices' GET_LINKS_URL = '/tfs-api/links' L3VPN_URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services' IETF_L3VPN_ALL_URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services' IETF_L3VPN_ONE_URL = IETF_L3VPN_ALL_URL + '/vpn-service={:s}' MAPPING_STATUS = { 'DEVICEOPERATIONALSTATUS_UNDEFINED': 0, Loading Loading @@ -50,8 +55,10 @@ MAPPING_DRIVER = { 'DEVICEDRIVER_RYU' : 18, } LOGGER = logging.getLogger(__name__) class TfsApiClient(RestApiClient): def __init__( self, address : str, port : int, scheme : str = 'http', Loading @@ -63,9 +70,26 @@ class TfsApiClient(RestApiClient): timeout=timeout, verify_certs=False, allow_redirects=True, logger=LOGGER ) def check_credentials(self) -> None: def check_credentials(self, raise_if_fail : bool = True) -> None: try: LOGGER.info('Checking credentials...') self.get(GET_CONTEXT_IDS_URL, expected_status_codes={requests.codes['OK']}) LOGGER.info('Credentials checked') return True except requests.exceptions.Timeout as e: MSG = 'Timeout connecting {:s}' msg = MSG.format(GET_CONTEXT_IDS_URL) LOGGER.exception(msg) if raise_if_fail: raise Exception(msg) from e return False except Exception as e: MSG = 'Exception connecting credentials: {:s}' msg = MSG.format(GET_CONTEXT_IDS_URL) LOGGER.exception(msg) if raise_if_fail: raise Exception(msg) from e return False def get_devices_endpoints( self, import_topology : ImportTopologyEnum = ImportTopologyEnum.DEVICES Loading Loading @@ -142,31 +166,41 @@ class TfsApiClient(RestApiClient): LOGGER.debug('[get_devices_endpoints] topology; returning') return result def create_connectivity_service(self, l3vpn_data : dict) -> None: MSG = '[create_connectivity_service] l3vpn_data={:s}' LOGGER.debug(MSG.format(str(l3vpn_data))) def create_connectivity_service(self, data : Dict) -> None: MSG = '[create_connectivity_service] data={:s}' LOGGER.debug(MSG.format(str(data))) try: self.post(L3VPN_URL, body=l3vpn_data) MSG = '[create_connectivity_service] POST {:s}: {:s}' LOGGER.info(MSG.format(str(IETF_L3VPN_ALL_URL), str(data))) self.post(IETF_L3VPN_ALL_URL, body=data) except requests.exceptions.ConnectionError as e: MSG = 'Failed to send POST request to TFS L3VPN NBI' MSG = 'Failed to send POST request to TFS IETF L3VPN NBI' raise Exception(MSG) from e def update_connectivity_service(self, l3vpn_data : dict) -> None: MSG = '[update_connectivity_service] l3vpn_data={:s}' LOGGER.debug(MSG.format(str(l3vpn_data))) vpn_id = l3vpn_data['ietf-l3vpn-svc:l3vpn-svc']['vpn-services']['vpn-service'][0]['vpn-id'] def update_connectivity_service(self, data : Dict) -> None: MSG = '[update_connectivity_service] data={:s}' LOGGER.debug(MSG.format(str(data))) vpn_id = data['ietf-l3vpn-svc:l3vpn-svc']['vpn-services']['vpn-service'][0]['vpn-id'] url = IETF_L3VPN_ONE_URL.format(vpn_id) try: self.put(L3VPN_URL + f'/vpn-service={vpn_id}', body=l3vpn_data) MSG = '[update_connectivity_service] PUT {:s}: {:s}' LOGGER.info(MSG.format(str(url), str(data))) self.put(url, body=data) except requests.exceptions.ConnectionError as e: MSG = 'Failed to send PUT request to TFS L3VPN NBI' MSG = 'Failed to send PUT request to TFS IETF L3VPN NBI' raise Exception(MSG) from e def delete_connectivity_service(self, service_uuid : str) -> None: url = L3VPN_URL + f'/vpn-service={service_uuid}' MSG = '[delete_connectivity_service] url={:s}' LOGGER.debug(MSG.format(str(url))) MSG = '[delete_connectivity_service] service_uuid={:s}' LOGGER.debug(MSG.format(str(service_uuid))) url = IETF_L3VPN_ONE_URL.format(service_uuid) try: MSG = '[delete_connectivity_service] DELETE {:s}' LOGGER.info(MSG.format(str(url))) self.delete(url) except requests.exceptions.ConnectionError as e: MSG = 'Failed to send DELETE request to TFS L3VPN NBI' MSG = 'Failed to send DELETE request to TFS IETF L3VPN NBI' raise Exception(MSG) from e Loading
src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py +40 −49 Original line number Diff line number Diff line Loading @@ -24,21 +24,23 @@ from .Constants import SPECIAL_RESOURCE_MAPPINGS from .TfsApiClient import TfsApiClient from .Tools import compose_resource_endpoint LOGGER = logging.getLogger(__name__) ALL_RESOURCE_KEYS = [ RESOURCE_ENDPOINTS, RESOURCE_SERVICES, ] 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$") 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}) class IetfL3VpnDriver(_Driver): def __init__(self, address : str, port : str, **settings) -> None: super().__init__(DRIVER_NAME, address, int(port), **settings) Loading @@ -54,7 +56,6 @@ class IetfL3VpnDriver(_Driver): self.address, self.port, scheme=scheme, username=username, password=password, timeout=timeout ) #self.__tfs_nbi_root = "{:s}://{:s}:{:d}".format(scheme, self.address, int(self.port)) # Options are: # disabled --> just import endpoints as usual Loading Loading @@ -90,7 +91,7 @@ class IetfL3VpnDriver(_Driver): resource_key, resource_value = resource chk_string(str_resource_name, resource_key, allow_empty=False) resource_path = resource_key.split("/") except Exception as e: # pylint: disable=broad-except except Exception as e: LOGGER.exception( "Exception validating {:s}: {:s}".format( str_resource_name, str(resource_key) Loading @@ -114,14 +115,9 @@ class IetfL3VpnDriver(_Driver): def Connect(self) -> bool: with self.__lock: if self.__started.is_set(): return True try: self.tac.check_credentials() except: # pylint: disable=bare-except LOGGER.exception('Exception checking credentials') return False else: self.__started.set() return True checked = self.tac.check_credentials(raise_if_fail=False) if checked: self.__started.set() return checked def Disconnect(self) -> bool: with self.__lock: Loading Loading @@ -179,12 +175,14 @@ class IetfL3VpnDriver(_Driver): for resource in resources: resource_key, resource_value = resource if RE_IETF_L3VPN_OPERATION.match(resource_key): operation_type = json.loads(resource_value)["type"] 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: raise Exception('operation type not found in resources') for i, resource in enumerate(resources): str_resource_name = 'resource_key[#{:d}]'.format(i) LOGGER.info('resource = {:s}'.format(str(resource))) resource_key, resource_value = resource if not RE_IETF_L3VPN_DATA.match(resource_key): Loading @@ -192,31 +190,24 @@ class IetfL3VpnDriver(_Driver): try: resource_value = json.loads(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["ietf-l3vpn-svc:l3vpn-svc"][ "vpn-services" ]["vpn-service"][0]["vpn-id"] service_uuid = resource_value['ietf-l3vpn-svc:l3vpn-svc'][ 'vpn-services' ]['vpn-service'][0]['vpn-id'] if operation_type == 'create': self.tac.create_connectivity_service(resource_value) elif operation_type == "update": service_id = resource_value["ietf-l3vpn-svc:l3vpn-svc"][ "vpn-services" ]["vpn-service"][0]["vpn-id"] elif operation_type == 'update': self.tac.update_connectivity_service(resource_value) elif operation_type == 'delete': self.tac.delete_connectivity_service(service_uuid) else: raise Exception("operation type not supported") MSG = 'OperationType({:s}) not supported' raise Exception(MSG.format(str(operation_type))) results.append((resource_key, True)) except Exception as e: # pylint: disable=broad-except LOGGER.exception( "Unhandled error processing resource_key({:s})".format( str(resource_key) ) ) except Exception as e: MSG = 'Unhandled error processing {:s}: resource_key({:s})' LOGGER.exception(MSG.format(str_resource_name, str(resource_key))) results.append((resource_key, e)) return results Loading @@ -228,24 +219,24 @@ class IetfL3VpnDriver(_Driver): if len(resources) == 0: return results with self.__lock: for resource in resources: LOGGER.info("resource = {:s}".format(str(resource))) for i, resource in enumerate(resources): str_resource_name = 'resource_key[#{:d}]'.format(i) 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_id = resource_value["id"] # if service_exists(self.__tfs_nbi_root, self.__auth, service_uuid): self.tac.delete_connectivity_service(service_id) service_uuid = resource_value['ietf-l3vpn-svc:l3vpn-svc'][ 'vpn-services' ]['vpn-service'][0]['vpn-id'] self.tac.delete_connectivity_service(service_uuid) results.append((resource_key, True)) except Exception as e: # pylint: disable=broad-except LOGGER.exception( "Unhandled error processing resource_key({:s})".format( str(resource_key) ) ) except Exception as e: MSG = 'Unhandled error processing {:s}: resource_key({:s})' LOGGER.exception(MSG.format(str_resource_name, str(resource_key))) results.append((resource_key, e)) return results Loading
src/device/service/drivers/ietf_l3vpn/TfsApiClient.py +53 −19 Original line number Diff line number Diff line Loading @@ -17,10 +17,15 @@ from typing import Dict, List, Optional from common.tools.client.RestApiClient import RestApiClient from device.service.driver_api.ImportTopologyEnum import ImportTopologyEnum GET_CONTEXT_IDS_URL = '/tfs-api/context_ids' GET_DEVICES_URL = '/tfs-api/devices' GET_LINKS_URL = '/tfs-api/links' L3VPN_URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services' IETF_L3VPN_ALL_URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services' IETF_L3VPN_ONE_URL = IETF_L3VPN_ALL_URL + '/vpn-service={:s}' MAPPING_STATUS = { 'DEVICEOPERATIONALSTATUS_UNDEFINED': 0, Loading Loading @@ -50,8 +55,10 @@ MAPPING_DRIVER = { 'DEVICEDRIVER_RYU' : 18, } LOGGER = logging.getLogger(__name__) class TfsApiClient(RestApiClient): def __init__( self, address : str, port : int, scheme : str = 'http', Loading @@ -63,9 +70,26 @@ class TfsApiClient(RestApiClient): timeout=timeout, verify_certs=False, allow_redirects=True, logger=LOGGER ) def check_credentials(self) -> None: def check_credentials(self, raise_if_fail : bool = True) -> None: try: LOGGER.info('Checking credentials...') self.get(GET_CONTEXT_IDS_URL, expected_status_codes={requests.codes['OK']}) LOGGER.info('Credentials checked') return True except requests.exceptions.Timeout as e: MSG = 'Timeout connecting {:s}' msg = MSG.format(GET_CONTEXT_IDS_URL) LOGGER.exception(msg) if raise_if_fail: raise Exception(msg) from e return False except Exception as e: MSG = 'Exception connecting credentials: {:s}' msg = MSG.format(GET_CONTEXT_IDS_URL) LOGGER.exception(msg) if raise_if_fail: raise Exception(msg) from e return False def get_devices_endpoints( self, import_topology : ImportTopologyEnum = ImportTopologyEnum.DEVICES Loading Loading @@ -142,31 +166,41 @@ class TfsApiClient(RestApiClient): LOGGER.debug('[get_devices_endpoints] topology; returning') return result def create_connectivity_service(self, l3vpn_data : dict) -> None: MSG = '[create_connectivity_service] l3vpn_data={:s}' LOGGER.debug(MSG.format(str(l3vpn_data))) def create_connectivity_service(self, data : Dict) -> None: MSG = '[create_connectivity_service] data={:s}' LOGGER.debug(MSG.format(str(data))) try: self.post(L3VPN_URL, body=l3vpn_data) MSG = '[create_connectivity_service] POST {:s}: {:s}' LOGGER.info(MSG.format(str(IETF_L3VPN_ALL_URL), str(data))) self.post(IETF_L3VPN_ALL_URL, body=data) except requests.exceptions.ConnectionError as e: MSG = 'Failed to send POST request to TFS L3VPN NBI' MSG = 'Failed to send POST request to TFS IETF L3VPN NBI' raise Exception(MSG) from e def update_connectivity_service(self, l3vpn_data : dict) -> None: MSG = '[update_connectivity_service] l3vpn_data={:s}' LOGGER.debug(MSG.format(str(l3vpn_data))) vpn_id = l3vpn_data['ietf-l3vpn-svc:l3vpn-svc']['vpn-services']['vpn-service'][0]['vpn-id'] def update_connectivity_service(self, data : Dict) -> None: MSG = '[update_connectivity_service] data={:s}' LOGGER.debug(MSG.format(str(data))) vpn_id = data['ietf-l3vpn-svc:l3vpn-svc']['vpn-services']['vpn-service'][0]['vpn-id'] url = IETF_L3VPN_ONE_URL.format(vpn_id) try: self.put(L3VPN_URL + f'/vpn-service={vpn_id}', body=l3vpn_data) MSG = '[update_connectivity_service] PUT {:s}: {:s}' LOGGER.info(MSG.format(str(url), str(data))) self.put(url, body=data) except requests.exceptions.ConnectionError as e: MSG = 'Failed to send PUT request to TFS L3VPN NBI' MSG = 'Failed to send PUT request to TFS IETF L3VPN NBI' raise Exception(MSG) from e def delete_connectivity_service(self, service_uuid : str) -> None: url = L3VPN_URL + f'/vpn-service={service_uuid}' MSG = '[delete_connectivity_service] url={:s}' LOGGER.debug(MSG.format(str(url))) MSG = '[delete_connectivity_service] service_uuid={:s}' LOGGER.debug(MSG.format(str(service_uuid))) url = IETF_L3VPN_ONE_URL.format(service_uuid) try: MSG = '[delete_connectivity_service] DELETE {:s}' LOGGER.info(MSG.format(str(url))) self.delete(url) except requests.exceptions.ConnectionError as e: MSG = 'Failed to send DELETE request to TFS L3VPN NBI' MSG = 'Failed to send DELETE request to TFS IETF L3VPN NBI' raise Exception(MSG) from e