# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json, logging, requests from os import name from requests.auth import HTTPBasicAuth from typing import Dict, List, Optional GET_DEVICES_URL = '{:s}://{:s}:{:d}/v1.0/topology/switches' GET_LINKS_URL = '{:s}://{:s}:{:d}/v1.0/topology/links' TIMEOUT = 30 HTTP_OK_CODES = { 200, # OK 201, # Created 202, # Accepted 204, # No Content } MAPPING_STATUS = { 'DEVICEOPERATIONALSTATUS_UNDEFINED': 0, 'DEVICEOPERATIONALSTATUS_DISABLED' : 1, 'DEVICEOPERATIONALSTATUS_ENABLED' : 2, } MAPPING_DRIVER = { 'DEVICEDRIVER_UNDEFINED' : 0, 'DEVICEDRIVER_OPENCONFIG' : 1, 'DEVICEDRIVER_TRANSPORT_API' : 2, 'DEVICEDRIVER_P4' : 3, 'DEVICEDRIVER_IETF_NETWORK_TOPOLOGY': 4, 'DEVICEDRIVER_ONF_TR_532' : 5, 'DEVICEDRIVER_XR' : 6, 'DEVICEDRIVER_IETF_L2VPN' : 7, 'DEVICEDRIVER_GNMI_OPENCONFIG' : 8, 'DEVICEDRIVER_OPTICAL_TFS' : 9, 'DEVICEDRIVER_IETF_ACTN' : 10, 'DEVICEDRIVER_OC' : 11, 'DEVICEDRIVER_QKD' : 12, 'DEVICEDRIVER_RYU' : 13, } MSG_ERROR = 'Could not retrieve devices in remote TeraFlowSDN instance({:s}). status_code={:s} reply={:s}' LOGGER = logging.getLogger(__name__) class TfsApiClient: def __init__( self, address : str, port : int, scheme : str = 'http', username : Optional[str] = None, password : Optional[str] = None ) -> None: self._devices_url = GET_DEVICES_URL.format(scheme, address, port) LOGGER.info(f'self_devices_url{self._devices_url}') self._links_url = GET_LINKS_URL.format(scheme, address, port) self._auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None def get_devices_endpoints(self) -> List[Dict]: LOGGER.debug('[get_devices_endpoints] begin') reply_switches = requests.get(self._devices_url, timeout=TIMEOUT, verify=False, auth=self._auth) if reply_switches.status_code not in HTTP_OK_CODES: msg = MSG_ERROR.format(str(self._devices_url), str(reply_switches.status_code), str(reply_switches)) LOGGER.error(msg) raise Exception(msg) json_reply_switches = reply_switches.json() LOGGER.info('[get_devices_endpoints] json_reply_switches={:s}'.format(json.dumps(json_reply_switches))) result = list() for json_switch in json_reply_switches: device_uuid: str = json_switch['dpid'] device_ports = json_switch.get('ports', []) for port in device_ports: port_name = port.get('name', '') device_name = port_name.split('-')[0] port_no = port.get('port_no', '') hw_address = port.get('hw_addr', '') device_url = '/devices/device[{:s}]'.format(device_uuid) device_data = { 'uuid': device_uuid, 'name': device_uuid, 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU', } result.append((device_url, device_data)) for json_switch in json_reply_switches: device_uuid: str = json_switch['dpid'] device_ports = json_switch.get('ports', []) for port in device_ports: port_name = port.get('name', '') port_no = port.get('port_no','') endpoint_uuid = port_name endpoint_url = '/endpoints/endpoint[{:s}]'.format(endpoint_uuid) endpoint_data = { 'device_uuid': device_uuid, 'uuid': port_name, 'name': port_name, 'type': 'copper', } result.append((endpoint_url, endpoint_data)) # reply = requests.get(self._links_url, timeout=TIMEOUT, verify=False, auth=self._auth) if reply.status_code not in HTTP_OK_CODES: msg = MSG_ERROR.format(str(self._links_url), str(reply.status_code), str(reply)) LOGGER.error(msg) raise Exception(msg) for json_link in reply.json(): dpid_src = json_link.get('src', {}).get('dpid', '') dpid_dst = json_link.get('dst', {}).get('dpid', '') port_src_name = json_link.get('src', {}).get('name', '') port_name_secondpart = port_src_name.split('-')[1] port_dst_name = json_link.get('dst', {}).get('name', '') port_name_second = port_dst_name.split('-')[1] switch_name_src = port_src_name.split('-')[0] switch_name_dest = port_dst_name.split('-')[0] link_name = f"{dpid_src}-{port_src_name}==={dpid_dst}-{port_dst_name}" link_uuid = f"{port_src_name}=={port_dst_name}" link_endpoint_ids = [ (dpid_src,port_src_name), (dpid_dst,port_dst_name) ] LOGGER.info(f'link_endpoint_ids are {link_endpoint_ids}') link_url = '/links/link[{:s}]'.format(link_uuid) link_data = { 'uuid': link_uuid, 'name': link_name, 'endpoints': link_endpoint_ids, } result.append((link_url, link_data)) LOGGER.debug('[get_devices_endpoints] topology; returning') return result