diff --git a/src/device/service/drivers/ietf_l2vpn/IetfL2VpnDriver.py b/src/device/service/drivers/ietf_l2vpn/IetfL2VpnDriver.py index 1c9659c2b90efb1900dbe96af80f4f239f607c74..a5e9f80cfee9e60cf373f9b7d3c895c8afedcc73 100644 --- a/src/device/service/drivers/ietf_l2vpn/IetfL2VpnDriver.py +++ b/src/device/service/drivers/ietf_l2vpn/IetfL2VpnDriver.py @@ -14,6 +14,7 @@ import json, logging, threading from typing import Any, Iterator, List, Optional, Tuple, Union +from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method from common.tools.object_factory.Device import json_device_id from common.tools.object_factory.EndPoint import json_endpoint_id @@ -56,7 +57,12 @@ class IetfL2VpnDriver(_Driver): wim_account = {'user': username, 'password': password} # Mapping updated dynamically with each request config = {'mapping_not_needed': False, 'service_endpoint_mapping': []} - self.tac = TfsApiClient(self.address, int(self.port), scheme=scheme, username=username, password=password) + self.__context_uuid = self.settings.get('context_uuid', DEFAULT_CONTEXT_NAME) + self.__topology_uuid = self.settings.get('topology_uuid', DEFAULT_TOPOLOGY_NAME) + self.tac = TfsApiClient( + self.address, int(self.port), scheme=scheme, username=username, + password=password, context_uuid=self.__context_uuid, topology_uuid=self.__topology_uuid + ) self.wim = WimconnectorIETFL2VPN(wim, wim_account, config=config) self.conn_info = {} # internal database emulating OSM storage provided to WIM Connectors diff --git a/src/device/service/drivers/ietf_l2vpn/TfsApiClient.py b/src/device/service/drivers/ietf_l2vpn/TfsApiClient.py index 88ec07a09bc9427b18b2a913914b03b1028e4e4b..6d9e756ffe5ecc82f9e90a097e2be353a08c0657 100644 --- a/src/device/service/drivers/ietf_l2vpn/TfsApiClient.py +++ b/src/device/service/drivers/ietf_l2vpn/TfsApiClient.py @@ -14,6 +14,7 @@ import json, logging, requests from typing import Dict, List, Optional +from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME from common.tools.rest_api.client.RestApiClient import RestApiClient from device.service.driver_api.ImportTopologyEnum import ImportTopologyEnum @@ -21,6 +22,7 @@ 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' +TOPOLOGY_URL = '/tfs-api/context/{context_uuid:s}/topology_details/{topology_uuid:s}' MAPPING_STATUS = { 'DEVICEOPERATIONALSTATUS_UNDEFINED': 0, @@ -62,12 +64,16 @@ class TfsApiClient(RestApiClient): def __init__( self, address : str, port : int, scheme : str = 'http', username : Optional[str] = None, password : Optional[str] = None, - timeout : Optional[int] = 30 + timeout : Optional[int] = 30, + context_uuid : str = DEFAULT_CONTEXT_NAME, + topology_uuid : str = DEFAULT_TOPOLOGY_NAME ) -> None: super().__init__( address, port, scheme=scheme, username=username, password=password, timeout=timeout, verify_certs=False, allow_redirects=True, logger=LOGGER ) + self.context_uuid = context_uuid + self.topology_uuid = topology_uuid def check_credentials(self, raise_if_fail : bool = True) -> None: @@ -101,10 +107,12 @@ class TfsApiClient(RestApiClient): MSG = 'Unsupported import_topology mode: {:s}' raise Exception(MSG.format(str(import_topology))) - devices = self.get(GET_DEVICES_URL, expected_status_codes={requests.codes['OK']}) + topology = self.get(TOPOLOGY_URL.format( + context_uuid=self.context_uuid, topology_uuid=self.topology_uuid + )) result = list() - for json_device in devices['devices']: + for json_device in topology.get('devices', []): device_uuid : str = json_device['device_id']['device_uuid']['uuid'] device_type : str = json_device['device_type'] #if not device_type.startswith('emu-'): device_type = 'emu-' + device_type @@ -170,9 +178,7 @@ class TfsApiClient(RestApiClient): LOGGER.debug('[get_devices_endpoints] devices only; returning') return result - links = self.get(GET_LINKS_URL, expected_status_codes={requests.codes['OK']}) - - for json_link in links['links']: + for json_link in topology.get('links', []): link_uuid : str = json_link['link_id']['link_uuid']['uuid'] link_url = '/links/link[{:s}]'.format(link_uuid) link_endpoint_ids = [ diff --git a/src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py b/src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py index cc78bbbd30c9834a09b2bf577f0935e69c07ae85..20081e264448763fc67c048320570420ddad477e 100644 --- a/src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py +++ b/src/device/service/drivers/ietf_l3vpn/IetfL3VpnDriver.py @@ -15,6 +15,7 @@ import anytree, copy, json, logging, re, threading from typing import Any, Dict, Iterator, List, Optional, Tuple, Union +from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method from common.tools.rest_conf.client.RestConfClient import RestConfClient from common.type_checkers.Checkers import chk_length, chk_string, chk_type @@ -63,9 +64,14 @@ class IetfL3VpnDriver(_Driver): password=password, timeout=timeout ) + self.__context_uuid = self.settings.get('context_uuid', DEFAULT_CONTEXT_NAME) + self.__topology_uuid = self.settings.get('topology_uuid', DEFAULT_TOPOLOGY_NAME) + restconf_settings = copy.deepcopy(settings) restconf_settings.pop('base_url', None) restconf_settings.pop('import_topology', None) + restconf_settings.pop('context_uuid', None) + restconf_settings.pop('topology_uuid', None) restconf_settings['logger'] = logging.getLogger(__name__ + '.RestConfClient') self._rest_conf_client = RestConfClient(address, port=port, **restconf_settings) self._handler_subscription = SubscriptionHandler(self._rest_conf_client) @@ -163,7 +169,11 @@ class IetfL3VpnDriver(_Driver): chk_string(str_resource_name, resource_key, allow_empty=False) if resource_key == RESOURCE_ENDPOINTS: # return endpoints through TFS NBI API and list-devices method - results.extend(self.tac.get_devices_endpoints(self.__import_topology)) + results.extend(self.tac.get_devices_endpoints( + self.__import_topology, + context_uuid=self.__context_uuid, + topology_uuid=self.__topology_uuid + )) else: resource_key = SPECIAL_RESOURCE_MAPPINGS.get( resource_key, resource_key @@ -194,9 +204,9 @@ class IetfL3VpnDriver(_Driver): for resource in resources: if 'ipowdm' in str(resource): try: - create_request(resource) + status = create_request(resource) LOGGER.info('Request created successfully') - results.append((resource, True)) + results.append((resource, status)) except Exception as e: MSG = 'Invalid resource_value type: expected dict, got {:s}' results.append((resource, e)) diff --git a/src/device/service/drivers/ietf_l3vpn/TfsApiClient.py b/src/device/service/drivers/ietf_l3vpn/TfsApiClient.py index 947b3ca5c3c41aa4f928044fe834f76fd778f136..b5b5f21419e9638a67617b4f419c16f022461b4a 100644 --- a/src/device/service/drivers/ietf_l3vpn/TfsApiClient.py +++ b/src/device/service/drivers/ietf_l3vpn/TfsApiClient.py @@ -14,6 +14,7 @@ import json, logging, requests from typing import Dict, List, Optional +from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME from common.tools.rest_api.client.RestApiClient import RestApiClient from device.service.driver_api.ImportTopologyEnum import ImportTopologyEnum @@ -21,6 +22,7 @@ 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' +TOPOLOGY_URL = '/tfs-api/context/{context_uuid:s}/topology_details/{topology_uuid:s}' IETF_L3VPN_ALL_URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services' @@ -96,20 +98,24 @@ class TfsApiClient(RestApiClient): def get_devices_endpoints( - self, import_topology : ImportTopologyEnum = ImportTopologyEnum.DEVICES + self, import_topology : ImportTopologyEnum = ImportTopologyEnum.DEVICES, + context_uuid : str = DEFAULT_CONTEXT_NAME, + topology_uuid : str = DEFAULT_TOPOLOGY_NAME ) -> List[Dict]: LOGGER.debug('[get_devices_endpoints] begin') - MSG = '[get_devices_endpoints] import_topology={:s}' - LOGGER.debug(MSG.format(str(import_topology))) + MSG = '[get_devices_endpoints] import_topology={:s} context_uuid={:s} topology_uuid={:s}' + LOGGER.debug(MSG.format(str(import_topology), str(context_uuid), str(topology_uuid))) if import_topology == ImportTopologyEnum.DISABLED: MSG = 'Unsupported import_topology mode: {:s}' raise Exception(MSG.format(str(import_topology))) - devices = self.get(GET_DEVICES_URL, expected_status_codes={requests.codes['OK']}) + topology = self.get(TOPOLOGY_URL.format( + context_uuid=context_uuid, topology_uuid=topology_uuid + )) result = list() - for json_device in devices['devices']: + for json_device in topology.get('devices', []): device_uuid : str = json_device['device_id']['device_uuid']['uuid'] device_type : str = json_device['device_type'] #if not device_type.startswith('emu-'): device_type = 'emu-' + device_type @@ -175,9 +181,7 @@ class TfsApiClient(RestApiClient): LOGGER.debug('[get_devices_endpoints] devices only; returning') return result - links = self.get(GET_LINKS_URL, expected_status_codes={requests.codes['OK']}) - - for json_link in links['links']: + for json_link in topology.get('links', []): link_uuid : str = json_link['link_id']['link_uuid']['uuid'] link_url = '/links/link[{:s}]'.format(link_uuid) link_endpoint_ids = [ diff --git a/src/device/service/drivers/optical_tfs/OpticalTfsDriver.py b/src/device/service/drivers/optical_tfs/OpticalTfsDriver.py index 5defed63df3adc5e31349c8fee2f4c086f313478..d302ad53268893195a8825569a458d34f6af312c 100644 --- a/src/device/service/drivers/optical_tfs/OpticalTfsDriver.py +++ b/src/device/service/drivers/optical_tfs/OpticalTfsDriver.py @@ -17,6 +17,7 @@ import json, logging, threading from typing import Any, Iterator, List, Optional, Tuple, Union from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method from common.type_checkers.Checkers import chk_string, chk_type +from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME from device.service.driver_api._Driver import _Driver, RESOURCE_ENDPOINTS, RESOURCE_SERVICES from device.service.driver_api.ImportTopologyEnum import ImportTopologyEnum, get_import_topology from .TfsApiClient import TfsApiClient @@ -42,9 +43,12 @@ class OpticalTfsDriver(_Driver): password = self.settings.get('password') scheme = self.settings.get('scheme', 'http') timeout = int(self.settings.get('timeout', 60)) + self.__context_uuid = self.settings.get('context_uuid', DEFAULT_CONTEXT_NAME) + self.__topology_uuid = self.settings.get('topology_uuid', DEFAULT_TOPOLOGY_NAME) self.tac = TfsApiClient( self.address, self.port, scheme=scheme, username=username, - password=password, timeout=timeout + password=password, timeout=timeout, + context_uuid=self.__context_uuid, topology_uuid=self.__topology_uuid ) #self.toc = TfsOpticalClient( # self.address, int(self.port), scheme=scheme, username=username, diff --git a/src/device/service/drivers/optical_tfs/TfsApiClient.py b/src/device/service/drivers/optical_tfs/TfsApiClient.py index 5e1ece17f9645492a38463cada82dc9c38f043cf..faf1c0c30583e6fb3031891080f77564ff4e66b8 100644 --- a/src/device/service/drivers/optical_tfs/TfsApiClient.py +++ b/src/device/service/drivers/optical_tfs/TfsApiClient.py @@ -71,12 +71,16 @@ class TfsApiClient(RestApiClient): def __init__( self, address : str, port : int, scheme : str = 'http', username : Optional[str] = None, password : Optional[str] = None, - timeout : Optional[int] = 30 + timeout : Optional[int] = 30, + context_uuid : str = DEFAULT_CONTEXT_NAME, + topology_uuid : str = DEFAULT_TOPOLOGY_NAME ) -> None: super().__init__( address, port, scheme=scheme, username=username, password=password, timeout=timeout, verify_certs=False, allow_redirects=True, logger=LOGGER ) + self.context_uuid = context_uuid + self.topology_uuid = topology_uuid def check_credentials(self, raise_if_fail : bool = True) -> None: @@ -111,7 +115,7 @@ class TfsApiClient(RestApiClient): raise Exception(MSG.format(str(import_topology))) topology = self.get(TOPOLOGY_URL.format( - context_uuid=DEFAULT_CONTEXT_NAME, topology_uuid=DEFAULT_TOPOLOGY_NAME + context_uuid=self.context_uuid, topology_uuid=self.topology_uuid )) result = list() @@ -211,11 +215,11 @@ class TfsApiClient(RestApiClient): service_add = json_service( service_uuid, ServiceTypeEnum.Name(ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY), - context_id = json_context_id(DEFAULT_CONTEXT_NAME), + context_id = json_context_id(self.context_uuid), name = service_name, status = ServiceStatusEnum.Name(ServiceStatusEnum.SERVICESTATUS_PLANNED), ) - services_url = SERVICES_URL.format(context_uuid=DEFAULT_CONTEXT_NAME) + services_url = SERVICES_URL.format(context_uuid=self.context_uuid) service_ids = self.post(services_url, body=service_add) assert len(service_ids) == 1 service_id = service_ids[0] @@ -224,18 +228,18 @@ class TfsApiClient(RestApiClient): service_upd = json_service( service_uuid, ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY, - context_id = json_context_id(DEFAULT_CONTEXT_NAME), + context_id = json_context_id(self.context_uuid), name = service_name, endpoint_ids = endpoint_ids, constraints = constraints, status = ServiceStatusEnum.Name(ServiceStatusEnum.SERVICESTATUS_PLANNED), ) - service_url = SERVICE_URL.format(context_uuid=DEFAULT_CONTEXT_NAME, service_uuid=service_uuid) + service_url = SERVICE_URL.format(context_uuid=self.context_uuid, service_uuid=service_uuid) self.put(service_url, body=service_upd) def teardown_service(self, resource_value : Dict) -> None: service_uuid = resource_value['service_uuid'] service_name = resource_value['service_name'] - service_url = SERVICE_URL.format(context_uuid=DEFAULT_CONTEXT_NAME, service_uuid=service_uuid) + service_url = SERVICE_URL.format(context_uuid=self.context_uuid, service_uuid=service_uuid) self.delete(service_url) if service_name == 'IP1/PORT-xe1==IP2/PORT-xe1': self.delete(service_url) @@ -269,7 +273,7 @@ class TfsApiClient(RestApiClient): return resource_key, parsed_service def get_services(self) -> List[Tuple[str, Dict]]: - services_url = SERVICES_URL.format(context_uuid=DEFAULT_CONTEXT_NAME) + services_url = SERVICES_URL.format(context_uuid=self.context_uuid) _services = self.get(services_url) OPTICAL_CONNECTIVITY_SERVICE_TYPES = { 'SERVICETYPE_OPTICAL_CONNECTIVITY', @@ -282,6 +286,6 @@ class TfsApiClient(RestApiClient): ] def get_service(self, service_uuid : str) -> Tuple[str, Dict]: - service_url = SERVICE_URL.format(context_uuid=DEFAULT_CONTEXT_NAME, service_uuid=service_uuid) + service_url = SERVICE_URL.format(context_uuid=self.context_uuid, service_uuid=service_uuid) service = self.get(service_url) return TfsApiClient.parse_service(service)