From df552ea6b001fe25e0d20887d95f020577586699 Mon Sep 17 00:00:00 2001 From: rahhal Date: Fri, 22 Nov 2024 10:01:53 +0000 Subject: [PATCH 1/7] Device component - Ryu Driver: - Added Topology discovery functionality --- manifests/deviceservice.yaml | 2 +- my_deploy.sh | 4 +- proto/context.proto | 1 + scripts/run_openflow.sh | 8 + src/common/DeviceTypes.py | 4 +- .../database/models/enums/DeviceDriver.py | 1 + .../drivers/OpenFlow/OpenFlowDriver.py | 196 +++++ .../service/drivers/OpenFlow/TfsApiClient.py | 144 ++++ src/device/service/drivers/OpenFlow/Tools.py | 174 +++++ .../service/drivers/OpenFlow/__init__.py | 20 + src/device/service/drivers/__init__.py | 12 +- src/device/tests/test_OpenFlow.py | 85 +++ .../openflow-ryu-controller.png | Bin 0 -> 51312 bytes tmp-code/DeviceTypes.py | 55 ++ tmp-code/OpenFlow/OpenFlowDriver.py | 173 +++++ tmp-code/OpenFlow/Tools.py | 174 +++++ tmp-code/OpenFlow/__init__.py | 20 + tmp-code/__init__.py | 202 +++++ tmp-code/context.proto | 698 ++++++++++++++++++ tmp-code/run_openflow.sh | 8 + tmp-code/test_OpenFlow.py | 77 ++ 21 files changed, 2052 insertions(+), 6 deletions(-) create mode 100755 scripts/run_openflow.sh create mode 100644 src/device/service/drivers/OpenFlow/OpenFlowDriver.py create mode 100644 src/device/service/drivers/OpenFlow/TfsApiClient.py create mode 100644 src/device/service/drivers/OpenFlow/Tools.py create mode 100644 src/device/service/drivers/OpenFlow/__init__.py create mode 100644 src/device/tests/test_OpenFlow.py create mode 100644 src/webui/service/static/topology_icons/openflow-ryu-controller.png create mode 100644 tmp-code/DeviceTypes.py create mode 100644 tmp-code/OpenFlow/OpenFlowDriver.py create mode 100644 tmp-code/OpenFlow/Tools.py create mode 100644 tmp-code/OpenFlow/__init__.py create mode 100644 tmp-code/__init__.py create mode 100644 tmp-code/context.proto create mode 100755 tmp-code/run_openflow.sh create mode 100644 tmp-code/test_OpenFlow.py diff --git a/manifests/deviceservice.yaml b/manifests/deviceservice.yaml index 950b98442..ef5195eae 100644 --- a/manifests/deviceservice.yaml +++ b/manifests/deviceservice.yaml @@ -39,7 +39,7 @@ spec: - containerPort: 9192 env: - name: LOG_LEVEL - value: "INFO" + value: "DEBUG" startupProbe: exec: command: ["/bin/grpc_health_probe", "-addr=:2020"] diff --git a/my_deploy.sh b/my_deploy.sh index a048edb30..59c7c0a9a 100755 --- a/my_deploy.sh +++ b/my_deploy.sh @@ -20,7 +20,7 @@ export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/" # Set the list of components, separated by spaces, you want to build images for, and deploy. -export TFS_COMPONENTS="context device pathcomp service slice nbi webui" +export TFS_COMPONENTS="context device pathcomp service webui" # Uncomment to activate Monitoring (old) #export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" @@ -134,7 +134,7 @@ export CRDB_PASSWORD="tfs123" export CRDB_DEPLOY_MODE="single" # Disable flag for dropping database, if it exists. -export CRDB_DROP_DATABASE_IF_EXISTS="" +export CRDB_DROP_DATABASE_IF_EXISTS="YES" # Disable flag for re-deploying CockroachDB from scratch. export CRDB_REDEPLOY="" diff --git a/proto/context.proto b/proto/context.proto index 9f06d32ee..80281f833 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -223,6 +223,7 @@ enum DeviceDriverEnum { DEVICEDRIVER_IETF_ACTN = 10; DEVICEDRIVER_OC = 11; DEVICEDRIVER_QKD = 12; + DEVICEDRIVER_RYU = 13; } enum DeviceOperationalStatusEnum { diff --git a/scripts/run_openflow.sh b/scripts/run_openflow.sh new file mode 100755 index 000000000..2c525ca70 --- /dev/null +++ b/scripts/run_openflow.sh @@ -0,0 +1,8 @@ +PROJECTDIR=`pwd` + +cd $PROJECTDIR/src +RCFILE=$PROJECTDIR/coverage/.coveragerc + +# Run unitary tests and analyze coverage of code at same time +coverage run --rcfile=$RCFILE --append -m pytest --log-level=DEBUG --verbose \ + device/tests/test_OpenFlow.py \ No newline at end of file diff --git a/src/common/DeviceTypes.py b/src/common/DeviceTypes.py index eb315352b..ccc83c9a6 100644 --- a/src/common/DeviceTypes.py +++ b/src/common/DeviceTypes.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# Copyright 2022-2024 ETSI OSG/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. @@ -48,7 +48,7 @@ class DeviceTypeEnum(Enum): PACKET_SWITCH = 'packet-switch' XR_CONSTELLATION = 'xr-constellation' QKD_NODE = 'qkd-node' - OPEN_ROADM = 'openroadm' + OPENFLOW_RYU_CONTROLLER = 'openflow-ryu-controller' # ETSI TeraFlowSDN controller TERAFLOWSDN_CONTROLLER = 'teraflowsdn' diff --git a/src/context/service/database/models/enums/DeviceDriver.py b/src/context/service/database/models/enums/DeviceDriver.py index 5342f788a..691a7c05d 100644 --- a/src/context/service/database/models/enums/DeviceDriver.py +++ b/src/context/service/database/models/enums/DeviceDriver.py @@ -35,6 +35,7 @@ class ORM_DeviceDriverEnum(enum.Enum): IETF_ACTN = DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN OC = DeviceDriverEnum.DEVICEDRIVER_OC QKD = DeviceDriverEnum.DEVICEDRIVER_QKD + RYU = DeviceDriverEnum.DEVICEDRIVER_RYU grpc_to_enum__device_driver = functools.partial( grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum) diff --git a/src/device/service/drivers/OpenFlow/OpenFlowDriver.py b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py new file mode 100644 index 000000000..7e70d11fb --- /dev/null +++ b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py @@ -0,0 +1,196 @@ +# Copyright 2022-2024 ETSI OSG/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 +import logging, requests, threading +from requests.auth import HTTPBasicAuth +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 device.service.driver_api._Driver import _Driver,RESOURCE_ENDPOINTS +from device.service.drivers.OpenFlow.TfsApiClient import TfsApiClient +from device.service.drivers.OpenFlow.Tools import find_key, get_switches, get_flows , add_flow , delete_flow , get_desc,get_port_desc, get_links_information,get_switches_information,del_flow_entry +LOGGER = logging.getLogger(__name__) + +DRIVER_NAME = 'ryu' +METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME}) + +ALL_RESOURCE_KEYS = [ + RESOURCE_ENDPOINTS, +] + +class OpenFlowDriver(_Driver): + def __init__(self, address: str, port: int, **settings) -> None: + super().__init__(DRIVER_NAME, address, port, **settings) + self.__lock = threading.Lock() + self.__started = threading.Event() + self.__terminate = threading.Event() + username = self.settings.get('username') + password = self.settings.get('password') + self.__auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None + scheme = self.settings.get('scheme', 'http') + self.__base_url = '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port)) + self.__timeout = int(self.settings.get('timeout', 120)) + config = {'mapping_not_needed': False, 'service_endpoint_mapping': []} + self.tac = TfsApiClient(self.address, int(self.port), scheme=scheme, username=username, password=password) + + def Connect(self) -> bool: + url = f"{self.__base_url}" + with self.__lock: + try: + response = requests.get(url, timeout=self.__timeout, verify=False, auth=self.__auth) + response.raise_for_status() + except requests.exceptions.Timeout: + LOGGER.exception(f"Timeout connecting to {self.__base_url}") + return False + except requests.exceptions.RequestException as e: + LOGGER.exception(f"Exception connecting to {self.__base_url}: {e}") + return False + else: + self.__started.set() + return True + + def Disconnect(self) -> bool: + with self.__lock: + self.__terminate.set() + return True + + @metered_subclass_method(METRICS_POOL) + def GetInitialConfig(self) -> List[Tuple[str, Any]]: + with self.__lock: + return [] + + @metered_subclass_method(METRICS_POOL) + def GetConfig(self, resource_keys: List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: + chk_type('resources', resource_keys, list) + results = [] + with self.__lock: + if len(resource_keys) == 0:resource_keys = ALL_RESOURCE_KEYS + LOGGER.info(f'resource_key:{ALL_RESOURCE_KEYS}') + for i, resource_key in enumerate(resource_keys): + str_resource_name = 'resource_key[#{:d}]'.format(i) + try: + chk_string(str_resource_name, resource_key, allow_empty=False) + if resource_key == RESOURCE_ENDPOINTS: + LOGGER.info(f'resource_key:{RESOURCE_ENDPOINTS}') + results.extend(self.tac.get_devices_endpoints()) + except Exception as e: + LOGGER.exception('Unhandled error processing resource_key({:s})'.format(str(resource_key))) + results.append((resource_key, e)) + return results + + +# @metered_subclass_method(METRICS_POOL) +# def GetConfig(self, resource_keys: List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: +# chk_type('resources', resource_keys, list) +# results = [] +# with self.__lock: +# for key in resource_keys: +# try: +# if key.startswith('flows:'): +# dpid = key.split(':', 1)[1] +# flows = get_flows(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) +# results.append((key, flows)) +# elif key.startswith('description:'): +# dpid = key.split(':', 1)[1] +# desc = get_desc(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) +# results.append((key, desc)) +# elif key.startswith('switches'): +# switches = get_switches(self.__base_url, auth=self.__auth, timeout=self.__timeout) +# results.append((key, switches)) +# elif key.startswith('port_description:'): +# dpid = key.split(':', 1)[1] +# desc = get_port_desc(self.__base_url,dpid, auth=self.__auth, timeout=self.__timeout) +# results.append((key, desc)) +# elif key.startswith('switch_info'): +# sin = get_switches_information(self.__base_url, auth=self.__auth, timeout=self.__timeout) +# results.append((key, sin)) +# elif key.startswith('links_info'): +# lin = get_links_information(self.__base_url, auth=self.__auth, timeout=self.__timeout) +# results.append((key, lin)) +# else: +# results.append((key, None)) # If key not handled, append None +# except Exception as e: +# results.append((key, e)) +# return results +# +# @metered_subclass_method(METRICS_POOL) +# def DeleteConfig(self, resource_keys: List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: +# chk_type('resources', resource_keys, list) +# results = [] +# with self.__lock: +# for item in resource_keys: +# try: +# if isinstance(item, tuple): +# key, data = item +# else: +# key, data = item, None +# if key.startswith('flowentry_delete:'): +# dpid = key.split(':', 1)[1] +# flows = del_flow_entry(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) +# results.append((key, flows)) +# elif key=='flow_data' and data: +# flow_del = delete_flow (self.__base_url,data,auth=self.__auth, timeout=self.__timeout) +# results.append((key, flow_del)) +# else: +# results.append((key, None)) +# except Exception as e: +# results.append((key, e)) +# return results +# +# @metered_subclass_method(METRICS_POOL) +# def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: +# results = [] +# if not resources: +# return results +# with self.__lock: +# for item in resources: +# LOGGER.info('resources contains: %s', item) +# try: +# if isinstance(item, tuple) and len(item) == 2: +# key, flow_data = item +# else: +# LOGGER.warning("Resource format invalid. Each item should be a tuple with (key, data).") +# results.append(False) +# continue +# if key == "flow_data" and isinstance(flow_data, dict): +# LOGGER.info(f"Found valid flow_data entry: {flow_data}") +# success = add_flow(self.__base_url, flow_data, auth=self.__auth, timeout=self.__timeout) +# results.append(success) +# else: +# LOGGER.warning(f"Skipping item with key: {key} due to invalid format or missing data.") +# results.append(False) +# +# except Exception as e: +# LOGGER.error(f"Exception while setting configuration for item {item}: {str(e)}") +# results.append(e) +# +# return results +# +# +# +# @metered_subclass_method(METRICS_POOL) +# def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: +# # TODO: TAPI does not support monitoring by now +# return [False for _ in subscriptions] +# +# @metered_subclass_method(METRICS_POOL) +# def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: +# # TODO: TAPI does not support monitoring by now +# return [False for _ in subscriptions] +# +# def GetState( +# self, blocking=False, terminate : Optional[threading.Event] = None +# ) -> Iterator[Tuple[float, str, Any]]: +# # TODO: TAPI does not support monitoring by now +# return [] diff --git a/src/device/service/drivers/OpenFlow/TfsApiClient.py b/src/device/service/drivers/OpenFlow/TfsApiClient.py new file mode 100644 index 000000000..5db9c202c --- /dev/null +++ b/src/device/service/drivers/OpenFlow/TfsApiClient.py @@ -0,0 +1,144 @@ +# 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_name, + 'type': 'packet-switch', + 'status': 2, # Uncomment if device_status is included + '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_no, + '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_dst_name = json_link.get('dst', {}).get('name', '') + link_name = f"{port_src_name}=={port_dst_name}" + link_uuid = f"{dpid_src}-{port_src_name}==={dpid_dst}-{port_dst_name}" + link_endpoint_ids = [ + (dpid_src, port_src_name), + (dpid_dst, port_dst_name), + ] + LOGGER.info('link_endpoint_ids [{:s}]'.format(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 diff --git a/src/device/service/drivers/OpenFlow/Tools.py b/src/device/service/drivers/OpenFlow/Tools.py new file mode 100644 index 000000000..d68347087 --- /dev/null +++ b/src/device/service/drivers/OpenFlow/Tools.py @@ -0,0 +1,174 @@ +# Copyright 2022-2024 ETSI OSG/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, operator, requests +from requests.auth import HTTPBasicAuth +from typing import Optional +from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_SERVICES +from typing import List, Dict, Optional, Tuple, Union + +LOGGER = logging.getLogger(__name__) + +RESOURCE_ENDPOINTS = { + #get configurations + "switches": "/stats/switches", + "description": "/stats/desc", + "flows": "/stats/flow", + "port_description":"/stats/portdesc", + "switch_info":"/v1.0/topology/switches", + "links_info":"/v1.0/topology/links", + #add flow + "flow_add": "/stats/flowentry/add", + #Delete all matching flow entries of the switch. + "flow_delete": "/stats/flowentry/delete", + "flowentry_delete":"/stats/flowentry/clear", #according to dpid + +} + +HTTP_OK_CODES = { + 200, # OK + 201, # Created + 202, # Accepted + 204, # No Content +} + +# Utility function to find and extract a specific key from a resource. +def find_key(resource: Tuple[str, str], key: str) -> Union[dict, str, None]: + try: + return json.loads(resource[1])[key] + except KeyError: + LOGGER.warning(f"Key '{key}' not found in resource.") + return None + +def get_switches(root_url: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: + url = f"{root_url}{RESOURCE_ENDPOINTS['switches']}" + result = [] + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + switches = response.json() + LOGGER.info(f"Successfully retrieved switches: {switches}") + result = switches + except requests.exceptions.Timeout: + LOGGER.exception(f"Timeout connecting to {url}") + except requests.exceptions.RequestException as e: + LOGGER.exception(f"Error retrieving switches: {str(e)}") + return result + +def get_switches_information(root_url: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: + url = f"{root_url}{RESOURCE_ENDPOINTS['switch_info']}" + result = [] + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + switches_info = response.json() + LOGGER.info(f"Successfully retrieved switches: {switches_info}") + result = switches_info + except requests.exceptions.Timeout: + LOGGER.exception(f"Timeout connecting to {url}") + except requests.exceptions.RequestException as e: + LOGGER.exception(f"Error retrieving switches: {str(e)}") + return result + +def get_links_information(root_url: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: + url = f"{root_url}{RESOURCE_ENDPOINTS['links_info']}" + result = [] + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + links_info = response.json() + LOGGER.info(f"Successfully retrieved switches: {links_info}") + result = links_info + except requests.exceptions.Timeout: + LOGGER.exception(f"Timeout connecting to {url}") + except requests.exceptions.RequestException as e: + LOGGER.exception(f"Error retrieving switches: {str(e)}") + return result + +def get_flows(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: + url = f"{root_url}{RESOURCE_ENDPOINTS['flows']}/{dpid}" + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + flows = response.json() + LOGGER.info(f"Successfully retrieved flow rules for DPID {dpid}") + return flows + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to retrieve flow rules for DPID {dpid}: {str(e)}") + return [] + +#get description +def get_desc(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> Dict: + url = f"{root_url}{RESOURCE_ENDPOINTS['description']}/{dpid}" + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + desc = response.json() + LOGGER.info(f"Successfully retrieved description for DPID {dpid}: {desc}") + return desc + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to retrieve description for DPID {dpid}: {str(e)}") + return {} + +def get_port_desc(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> Dict: + url = f"{root_url}{RESOURCE_ENDPOINTS['port_description']}/{dpid}" + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + port_desc = response.json() + LOGGER.info(f"Successfully retrieved description for DPID {dpid}: {port_desc}") + return port_desc + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to retrieve description for DPID {dpid}: {str(e)}") + return {} + +##according to dpid +def del_flow_entry(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> Dict: + url = f"{root_url}{RESOURCE_ENDPOINTS['flowentry_delete']}/{dpid}" + try: + response = requests.delete(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + flow_desc = response.json() + LOGGER.info(f"Successfully retrieved description for DPID {dpid}: {flow_desc}") + return flow_desc + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to retrieve description for DPID {dpid}: {str(e)}") + return {} + +# to delete a flow based on match criteria. +def delete_flow(root_url: str, flow_data: dict, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> bool: + url = f"{root_url}{RESOURCE_ENDPOINTS['flow_delete']}" + try: + response = requests.post(url, json=flow_data, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + LOGGER.info(f"Flow configuration deleted successfully for DPID {flow_data.get('dpid')}.") + return True + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to delete flow configuration for DPID {flow_data.get('dpid')}: {str(e)}") + return False + +def add_flow(root_url: str, flow_data: dict, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> bool: + url = f"{root_url}{RESOURCE_ENDPOINTS['flow_add']}" + LOGGER.info(f"Posting flow data: {flow_data} (type: {type(flow_data)}) to URL: {url}") + try: + response = requests.post(url, json=flow_data, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + LOGGER.info("Flow configuration added successfully.") + return True + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to add flow configuration: {str(e)}") + return False + + + diff --git a/src/device/service/drivers/OpenFlow/__init__.py b/src/device/service/drivers/OpenFlow/__init__.py new file mode 100644 index 000000000..4f3d1a042 --- /dev/null +++ b/src/device/service/drivers/OpenFlow/__init__.py @@ -0,0 +1,20 @@ +# Copyright 2022-2024 ETSI OSG/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. + +from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_SERVICES + +ALL_RESOURCE_KEYS = [ + RESOURCE_ENDPOINTS, + RESOURCE_SERVICES, +] diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py index b99ee50ca..837d83d53 100644 --- a/src/device/service/drivers/__init__.py +++ b/src/device/service/drivers/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# Copyright 2022-2024 ETSI OSG/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. @@ -143,6 +143,16 @@ if LOAD_ALL_DEVICE_DRIVERS: FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY, } ])) +if LOAD_ALL_DEVICE_DRIVERS: + from.OpenFlow.OpenFlowDriver import OpenFlowDriver + DRIVERS.append( + (OpenFlowDriver, [ + { + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPENFLOW_RYU_CONTROLLER , + FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_RYU , + } + ]) + ) if LOAD_ALL_DEVICE_DRIVERS: from .xr.XrDriver import XrDriver # pylint: disable=wrong-import-position diff --git a/src/device/tests/test_OpenFlow.py b/src/device/tests/test_OpenFlow.py new file mode 100644 index 000000000..c1d3919ea --- /dev/null +++ b/src/device/tests/test_OpenFlow.py @@ -0,0 +1,85 @@ +import json +from re import A +import resource +import logging, os, sys, time + +from joblib import Logger +#from typing import Dict, Self, Tuple +os.environ['DEVICE_EMULATED_ONLY'] = 'YES' +from device.service.drivers.OpenFlow.OpenFlowDriver import OpenFlowDriver +logging.basicConfig(level=logging.DEBUG) +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + + +def test_main(): + driver_settings = { + 'protocol': 'http', + 'username': None, + 'password': None, + 'use_tls': False, + } + driver = OpenFlowDriver('127.0.0.1', 8080 , **driver_settings) + driver.Connect() + + import requests + + response = requests.get("http://127.0.0.1:8080/v1.0/topology/switches", timeout=10) + LOGGER.info(f'the response is{response}') + + + + # Test: GetConfig + #resource_keys = [ 'flows:1','description:1','switches','port_description:1','switch_info','links_info'] + # config = driver.GetConfig(resource_keys ) + # LOGGER.info('Specific configuration: %s', config) + + #resource_delete=["flowentry_delete:1"] + #config = driver.DeleteConfig(resource_delete) + #LOGGER.info('Specific configuration: %s', config) + #a=driver.GetConfig(["flows:1"]) + #LOGGER.info('flow 1 = {:s}'.format(str(a))) +# delete_data = { +# "dpid": 2, +# "cookie": 1, +# "cookie_mask": 1, +# "table_id": 0, +# "idle_timeout": 30, +# "hard_timeout": 30, +# "priority": 11111, +# "flags": 1, +# "match":{ +# "in_port":2 +# }, +# "actions":[ +# { +# "type":"ddf", +# "port": 1 +# } +# ] +# } +# delete_result = driver.DeleteConfig([("flow_data", delete_data)]) +# LOGGER.info('resources_to_delete = {:s}'.format(str(delete_result))) +# a=driver.GetConfig(["flows:1"]) +# LOGGER.info('flow 2 = {:s}'.format(str(a))) +# flow_data = { +# "dpid": 2, +# "priority": 22224, +# "match": { +# "in_port": 1 +# }, +# "actions": [ +# { +# "type": "GOTO_TABLE", +# "table_id": 1 +# } +# ] +# } +# set_result = driver.SetConfig([('flow_data',flow_data)]) +# LOGGER.info(set_result) +# driver.Disconnect() +# + raise Exception () + +if __name__ == '__main__': + sys.exit(test_main()) diff --git a/src/webui/service/static/topology_icons/openflow-ryu-controller.png b/src/webui/service/static/topology_icons/openflow-ryu-controller.png new file mode 100644 index 0000000000000000000000000000000000000000..2982c57308983b367f1fa13c559fb702edcbadfe GIT binary patch literal 51312 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�!K`ff0Ma9w~W(#SH$!z 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 None: + super().__init__(DRIVER_NAME, address, port, **settings) + self.__lock = threading.Lock() + self.__started = threading.Event() + self.__terminate = threading.Event() + username = self.settings.get('username') + password = self.settings.get('password') + self.__auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None + scheme = self.settings.get('scheme', 'http') + self.__base_url = '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port)) + self.__timeout = int(self.settings.get('timeout', 120)) + + def Connect(self) -> bool: + url = f"{self.__base_url}/stats/desc/1" + with self.__lock: + if self.__started.is_set(): + return True + try: + response = requests.get(url, timeout=self.__timeout, verify=False, auth=self.__auth) + response.raise_for_status() + except requests.exceptions.Timeout: + LOGGER.exception(f"Timeout connecting to {self.__base_url}") + return False + except requests.exceptions.RequestException as e: + LOGGER.exception(f"Exception connecting to {self.__base_url}: {e}") + return False + else: + self.__started.set() + return True + + def Disconnect(self) -> bool: + with self.__lock: + self.__terminate.set() + return True + + #@metered_subclass_method(METRICS_POOL) + #def GetInitialConfig(self) -> List[Tuple[str, Any]]: + # with self.__lock: + # switches = get_switches(self.__base_url, auth=self.__auth, timeout=self.__timeout) + # return [("switches", switches)] + + @metered_subclass_method(METRICS_POOL) + def GetConfig(self, resource_keys: List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: + chk_type('resources', resource_keys, list) + results = [] + with self.__lock: + for key in resource_keys: + try: + if key.startswith('flows:'): + dpid = key.split(':', 1)[1] + flows = get_flows(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) + results.append((key, flows)) + elif key.startswith('description:'): + dpid = key.split(':', 1)[1] + desc = get_desc(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) + results.append((key, desc)) + elif key.startswith('switches'): + switches = get_switches(self.__base_url, auth=self.__auth, timeout=self.__timeout) + results.append((key, switches)) + elif key.startswith('port_description:'): + dpid = key.split(':', 1)[1] + desc = get_port_desc(self.__base_url,dpid, auth=self.__auth, timeout=self.__timeout) + results.append((key, desc)) + elif key.startswith('switch_info'): + sin = get_switches_information(self.__base_url, auth=self.__auth, timeout=self.__timeout) + results.append((key, sin)) + elif key.startswith('links_info'): + lin = get_links_information(self.__base_url, auth=self.__auth, timeout=self.__timeout) + results.append((key, lin)) + else: + results.append((key, None)) # If key not handled, append None + except Exception as e: + results.append((key, e)) + return results + + @metered_subclass_method(METRICS_POOL) + def DeleteConfig(self, resource_keys: List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: + chk_type('resources', resource_keys, list) + results = [] + with self.__lock: + for item in resource_keys: + try: + if isinstance(item, tuple): + key, data = item + else: + key, data = item, None + if key.startswith('flowentry_delete:'): + dpid = key.split(':', 1)[1] + flows = del_flow_entry(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) + results.append((key, flows)) + elif key=='flow_data' and data: + flow_del = delete_flow (self.__base_url,data,auth=self.__auth, timeout=self.__timeout) + results.append((key, flow_del)) + else: + results.append((key, None)) + except Exception as e: + results.append((key, e)) + return results + + @metered_subclass_method(METRICS_POOL) + def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + results = [] + if not resources: + return results + with self.__lock: + for item in resources: + LOGGER.info('resources contains: %s', item) + try: + if isinstance(item, tuple) and len(item) == 2: + key, flow_data = item + else: + LOGGER.warning("Resource format invalid. Each item should be a tuple with (key, data).") + results.append(False) + continue + if key == "flow_data" and isinstance(flow_data, dict): + LOGGER.info(f"Found valid flow_data entry: {flow_data}") + success = add_flow(self.__base_url, flow_data, auth=self.__auth, timeout=self.__timeout) + results.append(success) + else: + LOGGER.warning(f"Skipping item with key: {key} due to invalid format or missing data.") + results.append(False) + + except Exception as e: + LOGGER.error(f"Exception while setting configuration for item {item}: {str(e)}") + results.append(e) + + return results + + + + @metered_subclass_method(METRICS_POOL) + def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: + # TODO: TAPI does not support monitoring by now + return [False for _ in subscriptions] + + @metered_subclass_method(METRICS_POOL) + def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: + # TODO: TAPI does not support monitoring by now + return [False for _ in subscriptions] + + def GetState( + self, blocking=False, terminate : Optional[threading.Event] = None + ) -> Iterator[Tuple[float, str, Any]]: + # TODO: TAPI does not support monitoring by now + return [] diff --git a/tmp-code/OpenFlow/Tools.py b/tmp-code/OpenFlow/Tools.py new file mode 100644 index 000000000..d68347087 --- /dev/null +++ b/tmp-code/OpenFlow/Tools.py @@ -0,0 +1,174 @@ +# Copyright 2022-2024 ETSI OSG/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, operator, requests +from requests.auth import HTTPBasicAuth +from typing import Optional +from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_SERVICES +from typing import List, Dict, Optional, Tuple, Union + +LOGGER = logging.getLogger(__name__) + +RESOURCE_ENDPOINTS = { + #get configurations + "switches": "/stats/switches", + "description": "/stats/desc", + "flows": "/stats/flow", + "port_description":"/stats/portdesc", + "switch_info":"/v1.0/topology/switches", + "links_info":"/v1.0/topology/links", + #add flow + "flow_add": "/stats/flowentry/add", + #Delete all matching flow entries of the switch. + "flow_delete": "/stats/flowentry/delete", + "flowentry_delete":"/stats/flowentry/clear", #according to dpid + +} + +HTTP_OK_CODES = { + 200, # OK + 201, # Created + 202, # Accepted + 204, # No Content +} + +# Utility function to find and extract a specific key from a resource. +def find_key(resource: Tuple[str, str], key: str) -> Union[dict, str, None]: + try: + return json.loads(resource[1])[key] + except KeyError: + LOGGER.warning(f"Key '{key}' not found in resource.") + return None + +def get_switches(root_url: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: + url = f"{root_url}{RESOURCE_ENDPOINTS['switches']}" + result = [] + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + switches = response.json() + LOGGER.info(f"Successfully retrieved switches: {switches}") + result = switches + except requests.exceptions.Timeout: + LOGGER.exception(f"Timeout connecting to {url}") + except requests.exceptions.RequestException as e: + LOGGER.exception(f"Error retrieving switches: {str(e)}") + return result + +def get_switches_information(root_url: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: + url = f"{root_url}{RESOURCE_ENDPOINTS['switch_info']}" + result = [] + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + switches_info = response.json() + LOGGER.info(f"Successfully retrieved switches: {switches_info}") + result = switches_info + except requests.exceptions.Timeout: + LOGGER.exception(f"Timeout connecting to {url}") + except requests.exceptions.RequestException as e: + LOGGER.exception(f"Error retrieving switches: {str(e)}") + return result + +def get_links_information(root_url: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: + url = f"{root_url}{RESOURCE_ENDPOINTS['links_info']}" + result = [] + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + links_info = response.json() + LOGGER.info(f"Successfully retrieved switches: {links_info}") + result = links_info + except requests.exceptions.Timeout: + LOGGER.exception(f"Timeout connecting to {url}") + except requests.exceptions.RequestException as e: + LOGGER.exception(f"Error retrieving switches: {str(e)}") + return result + +def get_flows(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: + url = f"{root_url}{RESOURCE_ENDPOINTS['flows']}/{dpid}" + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + flows = response.json() + LOGGER.info(f"Successfully retrieved flow rules for DPID {dpid}") + return flows + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to retrieve flow rules for DPID {dpid}: {str(e)}") + return [] + +#get description +def get_desc(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> Dict: + url = f"{root_url}{RESOURCE_ENDPOINTS['description']}/{dpid}" + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + desc = response.json() + LOGGER.info(f"Successfully retrieved description for DPID {dpid}: {desc}") + return desc + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to retrieve description for DPID {dpid}: {str(e)}") + return {} + +def get_port_desc(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> Dict: + url = f"{root_url}{RESOURCE_ENDPOINTS['port_description']}/{dpid}" + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + port_desc = response.json() + LOGGER.info(f"Successfully retrieved description for DPID {dpid}: {port_desc}") + return port_desc + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to retrieve description for DPID {dpid}: {str(e)}") + return {} + +##according to dpid +def del_flow_entry(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> Dict: + url = f"{root_url}{RESOURCE_ENDPOINTS['flowentry_delete']}/{dpid}" + try: + response = requests.delete(url, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + flow_desc = response.json() + LOGGER.info(f"Successfully retrieved description for DPID {dpid}: {flow_desc}") + return flow_desc + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to retrieve description for DPID {dpid}: {str(e)}") + return {} + +# to delete a flow based on match criteria. +def delete_flow(root_url: str, flow_data: dict, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> bool: + url = f"{root_url}{RESOURCE_ENDPOINTS['flow_delete']}" + try: + response = requests.post(url, json=flow_data, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + LOGGER.info(f"Flow configuration deleted successfully for DPID {flow_data.get('dpid')}.") + return True + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to delete flow configuration for DPID {flow_data.get('dpid')}: {str(e)}") + return False + +def add_flow(root_url: str, flow_data: dict, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> bool: + url = f"{root_url}{RESOURCE_ENDPOINTS['flow_add']}" + LOGGER.info(f"Posting flow data: {flow_data} (type: {type(flow_data)}) to URL: {url}") + try: + response = requests.post(url, json=flow_data, timeout=timeout, verify=False, auth=auth) + response.raise_for_status() + LOGGER.info("Flow configuration added successfully.") + return True + except requests.exceptions.RequestException as e: + LOGGER.error(f"Failed to add flow configuration: {str(e)}") + return False + + + diff --git a/tmp-code/OpenFlow/__init__.py b/tmp-code/OpenFlow/__init__.py new file mode 100644 index 000000000..4f3d1a042 --- /dev/null +++ b/tmp-code/OpenFlow/__init__.py @@ -0,0 +1,20 @@ +# Copyright 2022-2024 ETSI OSG/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. + +from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_SERVICES + +ALL_RESOURCE_KEYS = [ + RESOURCE_ENDPOINTS, + RESOURCE_SERVICES, +] diff --git a/tmp-code/__init__.py b/tmp-code/__init__.py new file mode 100644 index 000000000..487cf7d40 --- /dev/null +++ b/tmp-code/__init__.py @@ -0,0 +1,202 @@ +# Copyright 2022-2024 ETSI OSG/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 os +from common.DeviceTypes import DeviceTypeEnum +from common.proto.context_pb2 import DeviceDriverEnum +from device.Config import LOAD_ALL_DEVICE_DRIVERS +from ..driver_api.FilterFields import FilterFieldEnum + +DRIVERS = [] + +from .emulated.EmulatedDriver import EmulatedDriver # pylint: disable=wrong-import-position +DRIVERS.append( + (EmulatedDriver, [ + # TODO: multi-filter is not working + { + FilterFieldEnum.DEVICE_TYPE: [ + DeviceTypeEnum.EMULATED_DATACENTER, + DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM, + DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM, + DeviceTypeEnum.EMULATED_OPTICAL_ROADM, + DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER, + DeviceTypeEnum.EMULATED_P4_SWITCH, + DeviceTypeEnum.EMULATED_PACKET_ROUTER, + DeviceTypeEnum.EMULATED_PACKET_SWITCH, + + #DeviceTypeEnum.DATACENTER, + #DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM, + #DeviceTypeEnum.OPEN_LINE_SYSTEM, + #DeviceTypeEnum.OPTICAL_ROADM, + #DeviceTypeEnum.OPTICAL_TRANSPONDER, + #DeviceTypeEnum.P4_SWITCH, + #DeviceTypeEnum.PACKET_ROUTER, + #DeviceTypeEnum.PACKET_SWITCH, + ], + FilterFieldEnum.DRIVER: [ + DeviceDriverEnum.DEVICEDRIVER_UNDEFINED, + ], + }, + #{ + # # Emulated devices, all drivers => use Emulated + # FilterFieldEnum.DEVICE_TYPE: [ + # DeviceTypeEnum.EMULATED_DATACENTER, + # DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM, + # DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM, + # DeviceTypeEnum.EMULATED_OPTICAL_ROADM, + # DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER, + # DeviceTypeEnum.EMULATED_P4_SWITCH, + # DeviceTypeEnum.EMULATED_PACKET_ROUTER, + # DeviceTypeEnum.EMULATED_PACKET_SWITCH, + # ], + # FilterFieldEnum.DRIVER: [ + # DeviceDriverEnum.DEVICEDRIVER_UNDEFINED, + # DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, + # DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API, + # DeviceDriverEnum.DEVICEDRIVER_P4, + # DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY, + # DeviceDriverEnum.DEVICEDRIVER_ONF_TR_532, + # DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, + # ], + #} + ])) + +from .ietf_l2vpn.IetfL2VpnDriver import IetfL2VpnDriver # pylint: disable=wrong-import-position +DRIVERS.append( + (IetfL2VpnDriver, [ + { + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.TERAFLOWSDN_CONTROLLER, + FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN, + } + ])) + +from .ietf_actn.IetfActnDriver import IetfActnDriver # pylint: disable=wrong-import-position +DRIVERS.append( + (IetfActnDriver, [ + { + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPEN_LINE_SYSTEM, + FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN, + } + ])) + +if LOAD_ALL_DEVICE_DRIVERS: + from .openconfig.OpenConfigDriver import OpenConfigDriver # pylint: disable=wrong-import-position + DRIVERS.append( + (OpenConfigDriver, [ + { + # Real Packet Router, specifying OpenConfig Driver => use OpenConfigDriver + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.PACKET_ROUTER, + FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, + } + ])) + +if LOAD_ALL_DEVICE_DRIVERS: + from .gnmi_openconfig.GnmiOpenConfigDriver import GnmiOpenConfigDriver # pylint: disable=wrong-import-position + DRIVERS.append( + (GnmiOpenConfigDriver, [ + { + # Real Packet Router, specifying gNMI OpenConfig Driver => use GnmiOpenConfigDriver + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.PACKET_ROUTER, + FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, + } + ])) + +if LOAD_ALL_DEVICE_DRIVERS: + from .transport_api.TransportApiDriver import TransportApiDriver # pylint: disable=wrong-import-position + DRIVERS.append( + (TransportApiDriver, [ + { + # Real OLS, specifying TAPI Driver => use TransportApiDriver + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPEN_LINE_SYSTEM, + FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API, + } + ])) + +if LOAD_ALL_DEVICE_DRIVERS: + from .p4.p4_driver import P4Driver # pylint: disable=wrong-import-position + DRIVERS.append( + (P4Driver, [ + { + # Real P4 Switch, specifying P4 Driver => use P4Driver + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.P4_SWITCH, + FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_P4, + } + ])) + +if LOAD_ALL_DEVICE_DRIVERS: + from .microwave.IETFApiDriver import IETFApiDriver # pylint: disable=wrong-import-position + DRIVERS.append( + (IETFApiDriver, [ + { + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM, + FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY, + } + ])) +if LOAD_ALL_DEVICE_DRIVERS: + from.OpenFlow.OpenFlowDriver import OpenFlowDriver + DRIVERS.append( + (OpenFlowDriver, [ + { + # Specify the device type and driver that should use OpenFlowDriver + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPENFLOW_RYU_CONTROLLER , + FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_OPENFLOW, + } + ]) + ) + +if LOAD_ALL_DEVICE_DRIVERS: + from .xr.XrDriver import XrDriver # pylint: disable=wrong-import-position + DRIVERS.append( + (XrDriver, [ + { + # Close enough, it does optical switching + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.XR_CONSTELLATION, + FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_XR, + } + ])) + +if LOAD_ALL_DEVICE_DRIVERS: + from .optical_tfs.OpticalTfsDriver import OpticalTfsDriver # pylint: disable=wrong-import-position + DRIVERS.append( + (OpticalTfsDriver, [ + { + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPEN_LINE_SYSTEM, + FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_OPTICAL_TFS, + } + ])) + +if LOAD_ALL_DEVICE_DRIVERS: + from .oc_driver.OCDriver import OCDriver # pylint: disable=wrong-import-position + DRIVERS.append( + (OCDriver, [ + { + # Real Packet Router, specifying OpenConfig Driver => use OpenConfigDriver + FilterFieldEnum.DEVICE_TYPE: [ + DeviceTypeEnum.OPTICAL_ROADM, + DeviceTypeEnum.OPTICAL_TRANSPONDER + ], + FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_OC, + } + ])) + +if LOAD_ALL_DEVICE_DRIVERS: + from .qkd.QKDDriver2 import QKDDriver # pylint: disable=wrong-import-position + DRIVERS.append( + (QKDDriver, [ + { + # Close enough, it does optical switching + FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.QKD_NODE, + FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_QKD, + } + ])) diff --git a/tmp-code/context.proto b/tmp-code/context.proto new file mode 100644 index 000000000..2ab6f0aea --- /dev/null +++ b/tmp-code/context.proto @@ -0,0 +1,698 @@ +// Copyright 2022-2024 ETSI OSG/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. + +syntax = "proto3"; +package context; + +import "acl.proto"; +import "kpi_sample_types.proto"; + +service ContextService { + rpc ListContextIds (Empty ) returns ( ContextIdList ) {} + rpc ListContexts (Empty ) returns ( ContextList ) {} + rpc GetContext (ContextId ) returns ( Context ) {} + rpc SetContext (Context ) returns ( ContextId ) {} + rpc RemoveContext (ContextId ) returns ( Empty ) {} + rpc GetContextEvents (Empty ) returns (stream ContextEvent ) {} + + rpc ListTopologyIds (ContextId ) returns ( TopologyIdList ) {} + rpc ListTopologies (ContextId ) returns ( TopologyList ) {} + rpc GetTopology (TopologyId ) returns ( Topology ) {} + rpc GetTopologyDetails (TopologyId ) returns ( TopologyDetails ) {} + rpc SetTopology (Topology ) returns ( TopologyId ) {} + rpc RemoveTopology (TopologyId ) returns ( Empty ) {} + rpc GetTopologyEvents (Empty ) returns (stream TopologyEvent ) {} + + rpc ListDeviceIds (Empty ) returns ( DeviceIdList ) {} + rpc ListDevices (Empty ) returns ( DeviceList ) {} + rpc GetDevice (DeviceId ) returns ( Device ) {} + rpc SetDevice (Device ) returns ( DeviceId ) {} + rpc RemoveDevice (DeviceId ) returns ( Empty ) {} + rpc GetDeviceEvents (Empty ) returns (stream DeviceEvent ) {} + rpc SelectDevice (DeviceFilter ) returns ( DeviceList ) {} + rpc ListEndPointNames (EndPointIdList) returns ( EndPointNameList) {} + + rpc ListLinkIds (Empty ) returns ( LinkIdList ) {} + rpc ListLinks (Empty ) returns ( LinkList ) {} + rpc GetLink (LinkId ) returns ( Link ) {} + rpc SetLink (Link ) returns ( LinkId ) {} + rpc RemoveLink (LinkId ) returns ( Empty ) {} + rpc GetLinkEvents (Empty ) returns (stream LinkEvent ) {} + + rpc ListServiceIds (ContextId ) returns ( ServiceIdList ) {} + rpc ListServices (ContextId ) returns ( ServiceList ) {} + rpc GetService (ServiceId ) returns ( Service ) {} + rpc SetService (Service ) returns ( ServiceId ) {} + rpc UnsetService (Service ) returns ( ServiceId ) {} + rpc RemoveService (ServiceId ) returns ( Empty ) {} + rpc GetServiceEvents (Empty ) returns (stream ServiceEvent ) {} + rpc SelectService (ServiceFilter ) returns ( ServiceList ) {} + + rpc ListSliceIds (ContextId ) returns ( SliceIdList ) {} + rpc ListSlices (ContextId ) returns ( SliceList ) {} + rpc GetSlice (SliceId ) returns ( Slice ) {} + rpc SetSlice (Slice ) returns ( SliceId ) {} + rpc UnsetSlice (Slice ) returns ( SliceId ) {} + rpc RemoveSlice (SliceId ) returns ( Empty ) {} + rpc GetSliceEvents (Empty ) returns (stream SliceEvent ) {} + rpc SelectSlice (SliceFilter ) returns ( SliceList ) {} + + rpc ListConnectionIds (ServiceId ) returns ( ConnectionIdList) {} + rpc ListConnections (ServiceId ) returns ( ConnectionList ) {} + rpc GetConnection (ConnectionId ) returns ( Connection ) {} + rpc SetConnection (Connection ) returns ( ConnectionId ) {} + rpc RemoveConnection (ConnectionId ) returns ( Empty ) {} + rpc GetConnectionEvents(Empty ) returns (stream ConnectionEvent ) {} + + + // ------------------------------ Experimental ----------------------------- + rpc GetOpticalConfig (Empty ) returns (OpticalConfigList ) {} + rpc SetOpticalConfig (OpticalConfig ) returns (OpticalConfigId ) {} + rpc SelectOpticalConfig(OpticalConfigId) returns (OpticalConfig ) {} + + rpc SetOpticalLink (OpticalLink ) returns (Empty ) {} + rpc GetOpticalLink (OpticalLinkId ) returns (OpticalLink ) {} + rpc GetFiber (FiberId ) returns (Fiber ) {} +} + +// ----- Generic ------------------------------------------------------------------------------------------------------- +message Empty {} + +message Uuid { + string uuid = 1; +} + +enum EventTypeEnum { + EVENTTYPE_UNDEFINED = 0; + EVENTTYPE_CREATE = 1; + EVENTTYPE_UPDATE = 2; + EVENTTYPE_REMOVE = 3; +} + +message Timestamp { + double timestamp = 1; +} + +message Event { + Timestamp timestamp = 1; + EventTypeEnum event_type = 2; +} + +// ----- Context ------------------------------------------------------------------------------------------------------- +message ContextId { + Uuid context_uuid = 1; +} + +message Context { + ContextId context_id = 1; + string name = 2; + repeated TopologyId topology_ids = 3; + repeated ServiceId service_ids = 4; + repeated SliceId slice_ids = 5; + TeraFlowController controller = 6; +} + +message ContextIdList { + repeated ContextId context_ids = 1; +} + +message ContextList { + repeated Context contexts = 1; +} + +message ContextEvent { + Event event = 1; + ContextId context_id = 2; +} + + +// ----- Topology ------------------------------------------------------------------------------------------------------ +message TopologyId { + ContextId context_id = 1; + Uuid topology_uuid = 2; +} + +message Topology { + TopologyId topology_id = 1; + string name = 2; + repeated DeviceId device_ids = 3; + repeated LinkId link_ids = 4; +} + +message TopologyDetails { + TopologyId topology_id = 1; + string name = 2; + repeated Device devices = 3; + repeated Link links = 4; +} + +message TopologyIdList { + repeated TopologyId topology_ids = 1; +} + +message TopologyList { + repeated Topology topologies = 1; +} + +message TopologyEvent { + Event event = 1; + TopologyId topology_id = 2; +} + + +// ----- Device -------------------------------------------------------------------------------------------------------- +message DeviceId { + Uuid device_uuid = 1; +} + +message Device { + DeviceId device_id = 1; + string name = 2; + string device_type = 3; + DeviceConfig device_config = 4; + DeviceOperationalStatusEnum device_operational_status = 5; + repeated DeviceDriverEnum device_drivers = 6; + repeated EndPoint device_endpoints = 7; + repeated Component components = 8; // Used for inventory + DeviceId controller_id = 9; // Identifier of node controlling the actual device +} + +message Component { //Defined previously to this section - Tested OK + Uuid component_uuid = 1; + string name = 2; + string type = 3; + + map attributes = 4; // dict[attr.name => json.dumps(attr.value)] + string parent = 5; +} + +message DeviceConfig { + repeated ConfigRule config_rules = 1; +} + +enum DeviceDriverEnum { + DEVICEDRIVER_UNDEFINED = 0; // also used for emulated + 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; +} + +enum DeviceOperationalStatusEnum { + DEVICEOPERATIONALSTATUS_UNDEFINED = 0; + DEVICEOPERATIONALSTATUS_DISABLED = 1; + DEVICEOPERATIONALSTATUS_ENABLED = 2; +} + +message DeviceIdList { + repeated DeviceId device_ids = 1; +} + +message DeviceList { + repeated Device devices = 1; +} + +message DeviceFilter { + DeviceIdList device_ids = 1; + bool include_endpoints = 2; + bool include_config_rules = 3; + bool include_components = 4; +} + +message DeviceEvent { + Event event = 1; + DeviceId device_id = 2; + DeviceConfig device_config = 3; +} + + +// ----- Link ---------------------------------------------------------------------------------------------------------- +message LinkId { + Uuid link_uuid = 1; +} + +message LinkAttributes { + float total_capacity_gbps = 1; + float used_capacity_gbps = 2; +} + +message Link { + LinkId link_id = 1; + string name = 2; + repeated EndPointId link_endpoint_ids = 3; + LinkAttributes attributes = 4; + LinkTypeEnum link_type = 5; +} + +message LinkIdList { + repeated LinkId link_ids = 1; +} + +message LinkList { + repeated Link links = 1; +} + +message LinkEvent { + Event event = 1; + LinkId link_id = 2; +} + +enum LinkTypeEnum { + LINKTYPE_UNKNOWN = 0; + LINKTYPE_COPPER = 1; + LINKTYPE_VIRTUAL_COPPER = 2; + LINKTYPE_OPTICAL = 3; + LINKTYPE_VIRTUAL_OPTICAL = 4; +} + +// ----- Service ------------------------------------------------------------------------------------------------------- +message ServiceId { + ContextId context_id = 1; + Uuid service_uuid = 2; +} + +message Service { + ServiceId service_id = 1; + string name = 2; + ServiceTypeEnum service_type = 3; + repeated EndPointId service_endpoint_ids = 4; + repeated Constraint service_constraints = 5; + ServiceStatus service_status = 6; + ServiceConfig service_config = 7; + Timestamp timestamp = 8; +} + +enum ServiceTypeEnum { + SERVICETYPE_UNKNOWN = 0; + SERVICETYPE_L3NM = 1; + SERVICETYPE_L2NM = 2; + SERVICETYPE_TAPI_CONNECTIVITY_SERVICE = 3; + SERVICETYPE_TE = 4; + SERVICETYPE_E2E = 5; + SERVICETYPE_OPTICAL_CONNECTIVITY = 6; + SERVICETYPE_QKD = 7; +} + +enum ServiceStatusEnum { + SERVICESTATUS_UNDEFINED = 0; + SERVICESTATUS_PLANNED = 1; + SERVICESTATUS_ACTIVE = 2; + SERVICESTATUS_UPDATING = 3; + SERVICESTATUS_PENDING_REMOVAL = 4; + SERVICESTATUS_SLA_VIOLATED = 5; +} + +message ServiceStatus { + ServiceStatusEnum service_status = 1; +} + +message ServiceConfig { + repeated ConfigRule config_rules = 1; +} + +message ServiceIdList { + repeated ServiceId service_ids = 1; +} + +message ServiceList { + repeated Service services = 1; +} + +message ServiceFilter { + ServiceIdList service_ids = 1; + bool include_endpoint_ids = 2; + bool include_constraints = 3; + bool include_config_rules = 4; +} + +message ServiceEvent { + Event event = 1; + ServiceId service_id = 2; +} + +// ----- Slice --------------------------------------------------------------------------------------------------------- +message SliceId { + ContextId context_id = 1; + Uuid slice_uuid = 2; +} + +message Slice { + SliceId slice_id = 1; + string name = 2; + repeated EndPointId slice_endpoint_ids = 3; + repeated Constraint slice_constraints = 4; + repeated ServiceId slice_service_ids = 5; + repeated SliceId slice_subslice_ids = 6; + SliceStatus slice_status = 7; + SliceConfig slice_config = 8; + SliceOwner slice_owner = 9; + Timestamp timestamp = 10; +} + +message SliceOwner { + Uuid owner_uuid = 1; + string owner_string = 2; +} + +enum SliceStatusEnum { + SLICESTATUS_UNDEFINED = 0; + SLICESTATUS_PLANNED = 1; + SLICESTATUS_INIT = 2; + SLICESTATUS_ACTIVE = 3; + SLICESTATUS_DEINIT = 4; + SLICESTATUS_SLA_VIOLATED = 5; +} + +message SliceStatus { + SliceStatusEnum slice_status = 1; +} + +message SliceConfig { + repeated ConfigRule config_rules = 1; +} + +message SliceIdList { + repeated SliceId slice_ids = 1; +} + +message SliceList { + repeated Slice slices = 1; +} + +message SliceFilter { + SliceIdList slice_ids = 1; + bool include_endpoint_ids = 2; + bool include_constraints = 3; + bool include_service_ids = 4; + bool include_subslice_ids = 5; + bool include_config_rules = 6; +} + +message SliceEvent { + Event event = 1; + SliceId slice_id = 2; +} + +// ----- Connection ---------------------------------------------------------------------------------------------------- +message ConnectionId { + Uuid connection_uuid = 1; +} + +message ConnectionSettings_L0 { + string lsp_symbolic_name = 1; +} + +message ConnectionSettings_L2 { + string src_mac_address = 1; + string dst_mac_address = 2; + uint32 ether_type = 3; + uint32 vlan_id = 4; + uint32 mpls_label = 5; + uint32 mpls_traffic_class = 6; +} + +message ConnectionSettings_L3 { + string src_ip_address = 1; + string dst_ip_address = 2; + uint32 dscp = 3; + uint32 protocol = 4; + uint32 ttl = 5; +} + +message ConnectionSettings_L4 { + uint32 src_port = 1; + uint32 dst_port = 2; + uint32 tcp_flags = 3; + uint32 ttl = 4; +} + +message ConnectionSettings { + ConnectionSettings_L0 l0 = 1; + ConnectionSettings_L2 l2 = 2; + ConnectionSettings_L3 l3 = 3; + ConnectionSettings_L4 l4 = 4; +} + +message Connection { + ConnectionId connection_id = 1; + ServiceId service_id = 2; + repeated EndPointId path_hops_endpoint_ids = 3; + repeated ServiceId sub_service_ids = 4; + ConnectionSettings settings = 5; +} + +message ConnectionIdList { + repeated ConnectionId connection_ids = 1; +} + +message ConnectionList { + repeated Connection connections = 1; +} + +message ConnectionEvent { + Event event = 1; + ConnectionId connection_id = 2; +} + + +// ----- Endpoint ------------------------------------------------------------------------------------------------------ +message EndPointId { + TopologyId topology_id = 1; + DeviceId device_id = 2; + Uuid endpoint_uuid = 3; +} + +message EndPoint { + EndPointId endpoint_id = 1; + string name = 2; + string endpoint_type = 3; + repeated kpi_sample_types.KpiSampleType kpi_sample_types = 4; + Location endpoint_location = 5; +} + +message EndPointName { + EndPointId endpoint_id = 1; + string device_name = 2; + string endpoint_name = 3; + string endpoint_type = 4; +} + +message EndPointIdList { + repeated EndPointId endpoint_ids = 1; +} + +message EndPointNameList { + repeated EndPointName endpoint_names = 1; +} + + +// ----- Configuration ------------------------------------------------------------------------------------------------- +enum ConfigActionEnum { + CONFIGACTION_UNDEFINED = 0; + CONFIGACTION_SET = 1; + CONFIGACTION_DELETE = 2; +} + +message ConfigRule_Custom { + string resource_key = 1; + string resource_value = 2; +} + +message ConfigRule_ACL { + EndPointId endpoint_id = 1; + acl.AclRuleSet rule_set = 2; +} + +message ConfigRule { + ConfigActionEnum action = 1; + oneof config_rule { + ConfigRule_Custom custom = 2; + ConfigRule_ACL acl = 3; + } +} + + +// ----- Constraint ---------------------------------------------------------------------------------------------------- +enum ConstraintActionEnum { + CONSTRAINTACTION_UNDEFINED = 0; + CONSTRAINTACTION_SET = 1; + CONSTRAINTACTION_DELETE = 2; +} + +message Constraint_Custom { + string constraint_type = 1; + string constraint_value = 2; +} + +message Constraint_Schedule { + double start_timestamp = 1; + float duration_days = 2; +} + +message GPS_Position { + float latitude = 1; + float longitude = 2; +} + +message Location { + oneof location { + string region = 1; + GPS_Position gps_position = 2; + } +} + +message Constraint_EndPointLocation { + EndPointId endpoint_id = 1; + Location location = 2; +} + +message Constraint_EndPointPriority { + EndPointId endpoint_id = 1; + uint32 priority = 2; +} + +message Constraint_SLA_Latency { + float e2e_latency_ms = 1; +} + +message Constraint_SLA_Capacity { + float capacity_gbps = 1; +} + +message Constraint_SLA_Availability { + uint32 num_disjoint_paths = 1; + bool all_active = 2; + float availability = 3; // 0.0 .. 100.0 percentage of availability +} + +enum IsolationLevelEnum { + NO_ISOLATION = 0; + PHYSICAL_ISOLATION = 1; + LOGICAL_ISOLATION = 2; + PROCESS_ISOLATION = 3; + PHYSICAL_MEMORY_ISOLATION = 4; + PHYSICAL_NETWORK_ISOLATION = 5; + VIRTUAL_RESOURCE_ISOLATION = 6; + NETWORK_FUNCTIONS_ISOLATION = 7; + SERVICE_ISOLATION = 8; +} + +message Constraint_SLA_Isolation_level { + repeated IsolationLevelEnum isolation_level = 1; +} + +message Constraint_Exclusions { + bool is_permanent = 1; + repeated DeviceId device_ids = 2; + repeated EndPointId endpoint_ids = 3; + repeated LinkId link_ids = 4; +} + + +message QoSProfileId { + context.Uuid qos_profile_id = 1; +} + +message Constraint_QoSProfile { + QoSProfileId qos_profile_id = 1; + string qos_profile_name = 2; +} + +message Constraint { + ConstraintActionEnum action = 1; + oneof constraint { + Constraint_Custom custom = 2; + Constraint_Schedule schedule = 3; + Constraint_EndPointLocation endpoint_location = 4; + Constraint_EndPointPriority endpoint_priority = 5; + Constraint_SLA_Capacity sla_capacity = 6; + Constraint_SLA_Latency sla_latency = 7; + Constraint_SLA_Availability sla_availability = 8; + Constraint_SLA_Isolation_level sla_isolation = 9; + Constraint_Exclusions exclusions = 10; + Constraint_QoSProfile qos_profile = 11; + } +} + + +// ----- Miscellaneous ------------------------------------------------------------------------------------------------- +message TeraFlowController { + ContextId context_id = 1; + string ip_address = 2; + uint32 port = 3; +} + +message AuthenticationResult { + ContextId context_id = 1; + bool authenticated = 2; +} + +// ---------------- Experimental ------------------------ +message OpticalConfigId { + string opticalconfig_uuid = 1; +} +message OpticalConfig { + OpticalConfigId opticalconfig_id = 1; + string config = 2; +} + +message OpticalConfigList { + repeated OpticalConfig opticalconfigs = 1; +} + +// ---- Optical Link ---- + +message OpticalLinkId { + Uuid optical_link_uuid = 1; +} + +message FiberId { + Uuid fiber_uuid = 1; +} + +message Fiber { + string ID = 10; + string src_port = 1; + string dst_port = 2; + string local_peer_port = 3; + string remote_peer_port = 4; + repeated int32 c_slots = 5; + repeated int32 l_slots = 6; + repeated int32 s_slots = 7; + float length = 8; + bool used = 9; + FiberId fiber_uuid = 11; + +} +message OpticalLinkDetails { + float length = 1; + string source = 2; + string target = 3; + repeated Fiber fibers = 4; +} + +message OpticalLink { + string name = 1; + OpticalLinkDetails details = 2; + OpticalLinkId optical_link_uuid = 3; +} diff --git a/tmp-code/run_openflow.sh b/tmp-code/run_openflow.sh new file mode 100755 index 000000000..2c525ca70 --- /dev/null +++ b/tmp-code/run_openflow.sh @@ -0,0 +1,8 @@ +PROJECTDIR=`pwd` + +cd $PROJECTDIR/src +RCFILE=$PROJECTDIR/coverage/.coveragerc + +# Run unitary tests and analyze coverage of code at same time +coverage run --rcfile=$RCFILE --append -m pytest --log-level=DEBUG --verbose \ + device/tests/test_OpenFlow.py \ No newline at end of file diff --git a/tmp-code/test_OpenFlow.py b/tmp-code/test_OpenFlow.py new file mode 100644 index 000000000..60ee4542c --- /dev/null +++ b/tmp-code/test_OpenFlow.py @@ -0,0 +1,77 @@ +import json +from re import A +import resource +import logging, os, sys, time +#from typing import Dict, Self, Tuple +os.environ['DEVICE_EMULATED_ONLY'] = 'YES' +from device.service.drivers.OpenFlow.OpenFlowDriver import OpenFlowDriver +logging.basicConfig(level=logging.DEBUG) +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + + +def test_main(): + driver_settings = { + 'protocol': 'http', + 'username': None, + 'password': None, + 'use_tls': False, + } + driver = OpenFlowDriver('127.0.0.1', 8080 , **driver_settings) + driver.Connect() + + + # Test: GetConfig + #resource_keys = [ 'flows:1','description:1','switches','port_description:1','switch_info','links_info'] + # config = driver.GetConfig(resource_keys ) + # LOGGER.info('Specific configuration: %s', config) + + #resource_delete=["flowentry_delete:1"] + #config = driver.DeleteConfig(resource_delete) + #LOGGER.info('Specific configuration: %s', config) + #a=driver.GetConfig(["flows:1"]) + #LOGGER.info('flow 1 = {:s}'.format(str(a))) +# delete_data = { +# "dpid": 2, +# "cookie": 1, +# "cookie_mask": 1, +# "table_id": 0, +# "idle_timeout": 30, +# "hard_timeout": 30, +# "priority": 11111, +# "flags": 1, +# "match":{ +# "in_port":2 +# }, +# "actions":[ +# { +# "type":"ddf", +# "port": 1 +# } +# ] +# } +# delete_result = driver.DeleteConfig([("flow_data", delete_data)]) +# LOGGER.info('resources_to_delete = {:s}'.format(str(delete_result))) +# a=driver.GetConfig(["flows:1"]) +# LOGGER.info('flow 2 = {:s}'.format(str(a))) + flow_data = { + "dpid": 2, + "priority": 22224, + "match": { + "in_port": 1 + }, + "actions": [ + { + "type": "GOTO_TABLE", + "table_id": 1 + } + ] + } + set_result = driver.SetConfig([('flow_data',flow_data)]) + LOGGER.info(set_result) + driver.Disconnect() + + raise Exception () + +if __name__ == '__main__': + sys.exit(test_main()) -- GitLab From 15c8a21b21f3404f7ce5c54d42e619563d48c2ee Mon Sep 17 00:00:00 2001 From: rahhal Date: Thu, 28 Nov 2024 09:42:31 +0000 Subject: [PATCH 2/7] Device component - Ryu Driver: - Added Topology discovery functionality ( Completed ) --- .../service/drivers/OpenFlow/TfsApiClient.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/device/service/drivers/OpenFlow/TfsApiClient.py b/src/device/service/drivers/OpenFlow/TfsApiClient.py index 5db9c202c..aab5f0645 100644 --- a/src/device/service/drivers/OpenFlow/TfsApiClient.py +++ b/src/device/service/drivers/OpenFlow/TfsApiClient.py @@ -92,7 +92,7 @@ class TfsApiClient: device_url = '/devices/device[{:s}]'.format(device_uuid) device_data = { 'uuid': device_uuid, - 'name': device_name, + 'name': device_uuid, 'type': 'packet-switch', 'status': 2, # Uncomment if device_status is included 'drivers': 'DEVICEDRIVER_RYU', @@ -109,7 +109,7 @@ class TfsApiClient: endpoint_url = '/endpoints/endpoint[{:s}]'.format(endpoint_uuid) endpoint_data = { 'device_uuid': device_uuid, - 'uuid': port_no, + 'uuid': port_name, 'name': port_name, 'type': 'copper', } @@ -120,18 +120,23 @@ class TfsApiClient: 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', '') - link_name = f"{port_src_name}=={port_dst_name}" - link_uuid = f"{dpid_src}-{port_src_name}==={dpid_dst}-{port_dst_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('link_endpoint_ids [{:s}]'.format(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, -- GitLab From 691c1efc6578fd01132489b3cc76055be89ee0ff Mon Sep 17 00:00:00 2001 From: rahhal Date: Wed, 11 Dec 2024 16:57:15 +0000 Subject: [PATCH 3/7] Backup --- manifests/serviceservice.yaml | 2 +- src/common/DeviceTypes.py | 3 +- .../drivers/OpenFlow/OpenFlowDriver.py | 1 - .../service/drivers/OpenFlow/TfsApiClient.py | 2 +- src/device/service/drivers/OpenFlow/Tools.py | 3 - src/device/service/drivers/__init__.py | 2 +- .../service_handler_api/FilterFields.py | 1 + .../ServiceHandlerFactory.py | 6 +- .../service/service_handlers/__init__.py | 8 + .../l3nm_ryu/L3NMryuServiceHandler.py | 91 +++ .../service_handlers/l3nm_ryu}/__init__.py | 8 +- tmp-code/DeviceTypes.py | 55 -- tmp-code/OpenFlow/OpenFlowDriver.py | 173 ----- tmp-code/OpenFlow/Tools.py | 174 ----- tmp-code/__init__.py | 202 ----- tmp-code/context.proto | 698 ------------------ tmp-code/run_openflow.sh | 8 - tmp-code/test_OpenFlow.py | 77 -- 18 files changed, 109 insertions(+), 1405 deletions(-) create mode 100644 src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py rename {tmp-code/OpenFlow => src/service/service/service_handlers/l3nm_ryu}/__init__.py (70%) delete mode 100644 tmp-code/DeviceTypes.py delete mode 100644 tmp-code/OpenFlow/OpenFlowDriver.py delete mode 100644 tmp-code/OpenFlow/Tools.py delete mode 100644 tmp-code/__init__.py delete mode 100644 tmp-code/context.proto delete mode 100755 tmp-code/run_openflow.sh delete mode 100644 tmp-code/test_OpenFlow.py diff --git a/manifests/serviceservice.yaml b/manifests/serviceservice.yaml index aa94e4269..72c3015b3 100644 --- a/manifests/serviceservice.yaml +++ b/manifests/serviceservice.yaml @@ -36,7 +36,7 @@ spec: - containerPort: 9192 env: - name: LOG_LEVEL - value: "INFO" + value: "DEBUG" readinessProbe: exec: command: ["/bin/grpc_health_probe", "-addr=:3030"] diff --git a/src/common/DeviceTypes.py b/src/common/DeviceTypes.py index ccc83c9a6..b357c32be 100644 --- a/src/common/DeviceTypes.py +++ b/src/common/DeviceTypes.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# 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. @@ -48,6 +48,7 @@ class DeviceTypeEnum(Enum): PACKET_SWITCH = 'packet-switch' XR_CONSTELLATION = 'xr-constellation' QKD_NODE = 'qkd-node' + OPEN_ROADM = 'openroadm' OPENFLOW_RYU_CONTROLLER = 'openflow-ryu-controller' # ETSI TeraFlowSDN controller diff --git a/src/device/service/drivers/OpenFlow/OpenFlowDriver.py b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py index 7e70d11fb..a425943e4 100644 --- a/src/device/service/drivers/OpenFlow/OpenFlowDriver.py +++ b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py @@ -41,7 +41,6 @@ class OpenFlowDriver(_Driver): scheme = self.settings.get('scheme', 'http') self.__base_url = '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port)) self.__timeout = int(self.settings.get('timeout', 120)) - config = {'mapping_not_needed': False, 'service_endpoint_mapping': []} self.tac = TfsApiClient(self.address, int(self.port), scheme=scheme, username=username, password=password) def Connect(self) -> bool: diff --git a/src/device/service/drivers/OpenFlow/TfsApiClient.py b/src/device/service/drivers/OpenFlow/TfsApiClient.py index aab5f0645..bc95fe9ff 100644 --- a/src/device/service/drivers/OpenFlow/TfsApiClient.py +++ b/src/device/service/drivers/OpenFlow/TfsApiClient.py @@ -94,7 +94,7 @@ class TfsApiClient: 'uuid': device_uuid, 'name': device_uuid, 'type': 'packet-switch', - 'status': 2, # Uncomment if device_status is included + 'status': 2, 'drivers': 'DEVICEDRIVER_RYU', } result.append((device_url, device_data)) diff --git a/src/device/service/drivers/OpenFlow/Tools.py b/src/device/service/drivers/OpenFlow/Tools.py index d68347087..e68a47f3a 100644 --- a/src/device/service/drivers/OpenFlow/Tools.py +++ b/src/device/service/drivers/OpenFlow/Tools.py @@ -1,11 +1,8 @@ -# Copyright 2022-2024 ETSI OSG/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. diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py index 837d83d53..62942cd88 100644 --- a/src/device/service/drivers/__init__.py +++ b/src/device/service/drivers/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# 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. diff --git a/src/service/service/service_handler_api/FilterFields.py b/src/service/service/service_handler_api/FilterFields.py index 78f084605..6cd9f3bc4 100644 --- a/src/service/service/service_handler_api/FilterFields.py +++ b/src/service/service/service_handler_api/FilterFields.py @@ -44,6 +44,7 @@ DEVICE_DRIVER_VALUES = { DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN, DeviceDriverEnum.DEVICEDRIVER_OC, DeviceDriverEnum.DEVICEDRIVER_QKD, + DeviceDriverEnum.DEVICEDRIVER_RYU, } # Map allowed filter fields to allowed values per Filter field. If no restriction (free text) None is specified diff --git a/src/service/service/service_handler_api/ServiceHandlerFactory.py b/src/service/service/service_handler_api/ServiceHandlerFactory.py index e692a9e77..5ced40233 100644 --- a/src/service/service/service_handler_api/ServiceHandlerFactory.py +++ b/src/service/service/service_handler_api/ServiceHandlerFactory.py @@ -11,7 +11,6 @@ # 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 logging, operator from enum import Enum from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Set, Tuple @@ -26,7 +25,6 @@ if TYPE_CHECKING: from service.service.service_handler_api._ServiceHandler import _ServiceHandler LOGGER = logging.getLogger(__name__) - class ServiceHandlerFactory: def __init__(self, service_handlers : List[Tuple[type, List[Dict[FilterFieldEnum, Any]]]]) -> None: # Dict{field_name => Dict{field_value => Set{ServiceHandler}}} @@ -41,7 +39,6 @@ class ServiceHandlerFactory: from service.service.service_handler_api._ServiceHandler import _ServiceHandler if not issubclass(service_handler_class, _ServiceHandler): raise UnsupportedServiceHandlerClassException(str(service_handler_class)) - service_handler_name = service_handler_class.__name__ supported_filter_fields = set(FILTER_FIELD_ALLOWED_VALUES.keys()) unsupported_filter_fields = set(filter_fields.keys()).difference(supported_filter_fields) @@ -80,6 +77,9 @@ class ServiceHandlerFactory: field_enum_values = FILTER_FIELD_ALLOWED_VALUES.get(field_name) field_candidate_service_handler_classes = set() + #LOGGER.debug(f"Filter fields: {filter_fields}") + #LOGGER.debug(f"Field indices: {self.__indices}") + #LOGGER.debug(f"Candidate handlers after each field: {candidate_service_handler_classes}") for field_value in field_values: if field_enum_values is not None and field_value not in field_enum_values: raise UnsupportedFilterFieldValueException(field_name, field_value, field_enum_values) diff --git a/src/service/service/service_handlers/__init__.py b/src/service/service/service_handlers/__init__.py index f93cf011f..0be5fb6d7 100644 --- a/src/service/service/service_handlers/__init__.py +++ b/src/service/service/service_handlers/__init__.py @@ -28,6 +28,7 @@ from .tapi_xr.TapiXrServiceHandler import TapiXrServiceHandler from .e2e_orch.E2EOrchestratorServiceHandler import E2EOrchestratorServiceHandler from .oc.OCServiceHandler import OCServiceHandler from .qkd.qkd_service_handler import QKDServiceHandler +from .l3nm_ryu.L3NMryuServiceHandler import RYUServiceHandler SERVICE_HANDLERS = [ (L2NMEmulatedServiceHandler, [ @@ -113,5 +114,12 @@ SERVICE_HANDLERS = [ FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_QKD, FilterFieldEnum.DEVICE_DRIVER : [DeviceDriverEnum.DEVICEDRIVER_QKD], } + ]), + + (RYUServiceHandler, [ + { + FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_L3NM, + FilterFieldEnum.DEVICE_DRIVER : [DeviceDriverEnum.DEVICEDRIVER_RYU], + } ]) ] diff --git a/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py b/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py new file mode 100644 index 000000000..536f3997d --- /dev/null +++ b/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py @@ -0,0 +1,91 @@ +# 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, netaddr +from re import L +from typing import Any, Dict, List, Optional, Tuple, Union +from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method +from common.proto.context_pb2 import ConfigRule, Device, DeviceId, EndPoint, Service +from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set +from common.tools.object_factory.Device import json_device_id +from common.type_checkers.Checkers import chk_type +from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching +from service.service.service_handler_api._ServiceHandler import _ServiceHandler +from service.service.service_handler_api.SettingsHandler import SettingsHandler +from service.service.task_scheduler.TaskExecutor import TaskExecutor +import requests + +logging.basicConfig(level=logging.DEBUG) +LOGGER = logging.getLogger(__name__) + +METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'l3nm_ryu'}) + +class RYUServiceHandler(_ServiceHandler): + def __init__( # pylint: disable=super-init-not-called + self, service : Service, task_executor : TaskExecutor, **settings + ) -> None: + self.__service = service + self.__task_executor = task_executor + self.__settings_handler = SettingsHandler(service.service_config, **settings) + + + #def _get_endpoint_details( + # self, endpoint : Tuple[str, str, Optional[str]] + #) -> Tuple[Device, EndPoint, Dict]: + # device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) + # LOGGER.debug('device_uuid = {:s}'.format(str(device_uuid))) + # LOGGER.debug('endpoint_uuid = {:s}'.format(str(endpoint_uuid))) + # device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + # LOGGER.debug('device_obj = {:s}'.format(str(grpc_message_to_json_string(device_obj)))) + # endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + # LOGGER.debug('endpoint_obj = {:s}'.format(str(grpc_message_to_json_string(endpoint_obj)))) + # endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) + # device_name = device_obj.name + # endpoint_name = endpoint_obj.name + # if endpoint_settings is None: + # MSG = 'Settings not found for Endpoint(device=[uuid={:s}, name={:s}], endpoint=[uuid={:s}, name={:s}])' + # raise Exception(MSG.format(device_uuid, device_name, endpoint_uuid, endpoint_name)) + # endpoint_settings_dict : Dict = endpoint_settings.value + # LOGGER.debug('endpoint_settings_dict = {:s}'.format(str(endpoint_settings_dict))) + # return device_obj, endpoint_obj, endpoint_settings_dict + + + @metered_subclass_method(METRICS_POOL) + def SetEndpoint( + self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None + ) -> List[Union[bool, Exception]]: + LOGGER.debug('endpoints = {:s}'.format(str(endpoints))) + chk_type('endpoints', endpoints, list) + if len(endpoints) < 2: + LOGGER.warning('nothing done: not enough endpoints') + return [] + service_uuid = self.__service.service_id.service_uuid.uuid + LOGGER.debug('service_uuid = {:s}'.format(str(service_uuid))) + LOGGER.debug('self.__settings_handler = {:s}'.format(str(self.__settings_handler.dump_config_rules()))) + results = [] + try: + # Get endpoint details + src_device, src_endpoint, src_settings = self._get_endpoint_details(endpoints[0]) + dst_device, dst_endpoint, dst_settings = self._get_endpoint_details(endpoints[-1]) + LOGGER.debug(f"Source settings: {src_settings}") + LOGGER.debug(f"Destination settings: {dst_settings}") + + return results + + except Exception as e: + LOGGER.error(f"Error in SetEndpoint: {e}") + return [e] + + diff --git a/tmp-code/OpenFlow/__init__.py b/src/service/service/service_handlers/l3nm_ryu/__init__.py similarity index 70% rename from tmp-code/OpenFlow/__init__.py rename to src/service/service/service_handlers/l3nm_ryu/__init__.py index 4f3d1a042..53d5157f7 100644 --- a/tmp-code/OpenFlow/__init__.py +++ b/src/service/service/service_handlers/l3nm_ryu/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# 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. @@ -12,9 +12,3 @@ # See the License for the specific language governing permissions and # limitations under the License. -from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_SERVICES - -ALL_RESOURCE_KEYS = [ - RESOURCE_ENDPOINTS, - RESOURCE_SERVICES, -] diff --git a/tmp-code/DeviceTypes.py b/tmp-code/DeviceTypes.py deleted file mode 100644 index f88ec8bb4..000000000 --- a/tmp-code/DeviceTypes.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2022-2024 ETSI OSG/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. - -from enum import Enum - -class DeviceTypeEnum(Enum): - - # Abstractions - NETWORK = 'network' - - # Emulated device types - EMULATED_CLIENT = 'emu-client' - EMULATED_DATACENTER = 'emu-datacenter' - EMULATED_IP_SDN_CONTROLLER = 'emu-ip-sdn-controller' - EMULATED_MICROWAVE_RADIO_SYSTEM = 'emu-microwave-radio-system' - EMULATED_OPEN_LINE_SYSTEM = 'emu-open-line-system' - EMULATED_OPTICAL_ROADM = 'emu-optical-roadm' - EMULATED_OPTICAL_TRANSPONDER = 'emu-optical-transponder' - EMULATED_OPTICAL_SPLITTER = 'emu-optical-splitter' # passive component required for XR Constellation - EMULATED_P4_SWITCH = 'emu-p4-switch' - EMULATED_PACKET_RADIO_ROUTER = 'emu-packet-radio-router' - EMULATED_PACKET_ROUTER = 'emu-packet-router' - EMULATED_PACKET_SWITCH = 'emu-packet-switch' - EMULATED_XR_CONSTELLATION = 'emu-xr-constellation' - EMULATED_OPEN_FLOW_CONTROLLER = 'open-flow-controller' - - # Real device types - CLIENT = 'client' - DATACENTER = 'datacenter' - IP_SDN_CONTROLLER = 'ip-sdn-controller' - MICROWAVE_RADIO_SYSTEM = 'microwave-radio-system' - OPEN_LINE_SYSTEM = 'open-line-system' - OPTICAL_ROADM = 'optical-roadm' - OPTICAL_TRANSPONDER = 'optical-transponder' - P4_SWITCH = 'p4-switch' - PACKET_RADIO_ROUTER = 'packet-radio-router' - PACKET_ROUTER = 'packet-router' - PACKET_SWITCH = 'packet-switch' - XR_CONSTELLATION = 'xr-constellation' - QKD_NODE = 'qkd-node' - OPENFLOW_RYU_CONTROLLER = 'openflow-ryu-controller' - - # ETSI TeraFlowSDN controller - TERAFLOWSDN_CONTROLLER = 'teraflowsdn' diff --git a/tmp-code/OpenFlow/OpenFlowDriver.py b/tmp-code/OpenFlow/OpenFlowDriver.py deleted file mode 100644 index 2aee0cd29..000000000 --- a/tmp-code/OpenFlow/OpenFlowDriver.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright 2022-2024 ETSI OSG/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 -import logging, requests, threading -from requests.auth import HTTPBasicAuth -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 device.service.driver_api._Driver import _Driver -from . import ALL_RESOURCE_KEYS -from device.service.drivers.OpenFlow.Tools import find_key, get_switches, get_flows , add_flow , delete_flow , get_desc,get_port_desc, get_links_information,get_switches_information,del_flow_entry -LOGGER = logging.getLogger(__name__) - -DRIVER_NAME = 'openflow_api' -METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME}) - -class OpenFlowDriver(_Driver): - def __init__(self, address: str, port: int, **settings) -> None: - super().__init__(DRIVER_NAME, address, port, **settings) - self.__lock = threading.Lock() - self.__started = threading.Event() - self.__terminate = threading.Event() - username = self.settings.get('username') - password = self.settings.get('password') - self.__auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None - scheme = self.settings.get('scheme', 'http') - self.__base_url = '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port)) - self.__timeout = int(self.settings.get('timeout', 120)) - - def Connect(self) -> bool: - url = f"{self.__base_url}/stats/desc/1" - with self.__lock: - if self.__started.is_set(): - return True - try: - response = requests.get(url, timeout=self.__timeout, verify=False, auth=self.__auth) - response.raise_for_status() - except requests.exceptions.Timeout: - LOGGER.exception(f"Timeout connecting to {self.__base_url}") - return False - except requests.exceptions.RequestException as e: - LOGGER.exception(f"Exception connecting to {self.__base_url}: {e}") - return False - else: - self.__started.set() - return True - - def Disconnect(self) -> bool: - with self.__lock: - self.__terminate.set() - return True - - #@metered_subclass_method(METRICS_POOL) - #def GetInitialConfig(self) -> List[Tuple[str, Any]]: - # with self.__lock: - # switches = get_switches(self.__base_url, auth=self.__auth, timeout=self.__timeout) - # return [("switches", switches)] - - @metered_subclass_method(METRICS_POOL) - def GetConfig(self, resource_keys: List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: - chk_type('resources', resource_keys, list) - results = [] - with self.__lock: - for key in resource_keys: - try: - if key.startswith('flows:'): - dpid = key.split(':', 1)[1] - flows = get_flows(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) - results.append((key, flows)) - elif key.startswith('description:'): - dpid = key.split(':', 1)[1] - desc = get_desc(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) - results.append((key, desc)) - elif key.startswith('switches'): - switches = get_switches(self.__base_url, auth=self.__auth, timeout=self.__timeout) - results.append((key, switches)) - elif key.startswith('port_description:'): - dpid = key.split(':', 1)[1] - desc = get_port_desc(self.__base_url,dpid, auth=self.__auth, timeout=self.__timeout) - results.append((key, desc)) - elif key.startswith('switch_info'): - sin = get_switches_information(self.__base_url, auth=self.__auth, timeout=self.__timeout) - results.append((key, sin)) - elif key.startswith('links_info'): - lin = get_links_information(self.__base_url, auth=self.__auth, timeout=self.__timeout) - results.append((key, lin)) - else: - results.append((key, None)) # If key not handled, append None - except Exception as e: - results.append((key, e)) - return results - - @metered_subclass_method(METRICS_POOL) - def DeleteConfig(self, resource_keys: List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: - chk_type('resources', resource_keys, list) - results = [] - with self.__lock: - for item in resource_keys: - try: - if isinstance(item, tuple): - key, data = item - else: - key, data = item, None - if key.startswith('flowentry_delete:'): - dpid = key.split(':', 1)[1] - flows = del_flow_entry(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) - results.append((key, flows)) - elif key=='flow_data' and data: - flow_del = delete_flow (self.__base_url,data,auth=self.__auth, timeout=self.__timeout) - results.append((key, flow_del)) - else: - results.append((key, None)) - except Exception as e: - results.append((key, e)) - return results - - @metered_subclass_method(METRICS_POOL) - def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: - results = [] - if not resources: - return results - with self.__lock: - for item in resources: - LOGGER.info('resources contains: %s', item) - try: - if isinstance(item, tuple) and len(item) == 2: - key, flow_data = item - else: - LOGGER.warning("Resource format invalid. Each item should be a tuple with (key, data).") - results.append(False) - continue - if key == "flow_data" and isinstance(flow_data, dict): - LOGGER.info(f"Found valid flow_data entry: {flow_data}") - success = add_flow(self.__base_url, flow_data, auth=self.__auth, timeout=self.__timeout) - results.append(success) - else: - LOGGER.warning(f"Skipping item with key: {key} due to invalid format or missing data.") - results.append(False) - - except Exception as e: - LOGGER.error(f"Exception while setting configuration for item {item}: {str(e)}") - results.append(e) - - return results - - - - @metered_subclass_method(METRICS_POOL) - def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: - # TODO: TAPI does not support monitoring by now - return [False for _ in subscriptions] - - @metered_subclass_method(METRICS_POOL) - def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: - # TODO: TAPI does not support monitoring by now - return [False for _ in subscriptions] - - def GetState( - self, blocking=False, terminate : Optional[threading.Event] = None - ) -> Iterator[Tuple[float, str, Any]]: - # TODO: TAPI does not support monitoring by now - return [] diff --git a/tmp-code/OpenFlow/Tools.py b/tmp-code/OpenFlow/Tools.py deleted file mode 100644 index d68347087..000000000 --- a/tmp-code/OpenFlow/Tools.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2022-2024 ETSI OSG/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, operator, requests -from requests.auth import HTTPBasicAuth -from typing import Optional -from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_SERVICES -from typing import List, Dict, Optional, Tuple, Union - -LOGGER = logging.getLogger(__name__) - -RESOURCE_ENDPOINTS = { - #get configurations - "switches": "/stats/switches", - "description": "/stats/desc", - "flows": "/stats/flow", - "port_description":"/stats/portdesc", - "switch_info":"/v1.0/topology/switches", - "links_info":"/v1.0/topology/links", - #add flow - "flow_add": "/stats/flowentry/add", - #Delete all matching flow entries of the switch. - "flow_delete": "/stats/flowentry/delete", - "flowentry_delete":"/stats/flowentry/clear", #according to dpid - -} - -HTTP_OK_CODES = { - 200, # OK - 201, # Created - 202, # Accepted - 204, # No Content -} - -# Utility function to find and extract a specific key from a resource. -def find_key(resource: Tuple[str, str], key: str) -> Union[dict, str, None]: - try: - return json.loads(resource[1])[key] - except KeyError: - LOGGER.warning(f"Key '{key}' not found in resource.") - return None - -def get_switches(root_url: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: - url = f"{root_url}{RESOURCE_ENDPOINTS['switches']}" - result = [] - try: - response = requests.get(url, timeout=timeout, verify=False, auth=auth) - response.raise_for_status() - switches = response.json() - LOGGER.info(f"Successfully retrieved switches: {switches}") - result = switches - except requests.exceptions.Timeout: - LOGGER.exception(f"Timeout connecting to {url}") - except requests.exceptions.RequestException as e: - LOGGER.exception(f"Error retrieving switches: {str(e)}") - return result - -def get_switches_information(root_url: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: - url = f"{root_url}{RESOURCE_ENDPOINTS['switch_info']}" - result = [] - try: - response = requests.get(url, timeout=timeout, verify=False, auth=auth) - response.raise_for_status() - switches_info = response.json() - LOGGER.info(f"Successfully retrieved switches: {switches_info}") - result = switches_info - except requests.exceptions.Timeout: - LOGGER.exception(f"Timeout connecting to {url}") - except requests.exceptions.RequestException as e: - LOGGER.exception(f"Error retrieving switches: {str(e)}") - return result - -def get_links_information(root_url: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: - url = f"{root_url}{RESOURCE_ENDPOINTS['links_info']}" - result = [] - try: - response = requests.get(url, timeout=timeout, verify=False, auth=auth) - response.raise_for_status() - links_info = response.json() - LOGGER.info(f"Successfully retrieved switches: {links_info}") - result = links_info - except requests.exceptions.Timeout: - LOGGER.exception(f"Timeout connecting to {url}") - except requests.exceptions.RequestException as e: - LOGGER.exception(f"Error retrieving switches: {str(e)}") - return result - -def get_flows(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> List[Dict]: - url = f"{root_url}{RESOURCE_ENDPOINTS['flows']}/{dpid}" - try: - response = requests.get(url, timeout=timeout, verify=False, auth=auth) - response.raise_for_status() - flows = response.json() - LOGGER.info(f"Successfully retrieved flow rules for DPID {dpid}") - return flows - except requests.exceptions.RequestException as e: - LOGGER.error(f"Failed to retrieve flow rules for DPID {dpid}: {str(e)}") - return [] - -#get description -def get_desc(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> Dict: - url = f"{root_url}{RESOURCE_ENDPOINTS['description']}/{dpid}" - try: - response = requests.get(url, timeout=timeout, verify=False, auth=auth) - response.raise_for_status() - desc = response.json() - LOGGER.info(f"Successfully retrieved description for DPID {dpid}: {desc}") - return desc - except requests.exceptions.RequestException as e: - LOGGER.error(f"Failed to retrieve description for DPID {dpid}: {str(e)}") - return {} - -def get_port_desc(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> Dict: - url = f"{root_url}{RESOURCE_ENDPOINTS['port_description']}/{dpid}" - try: - response = requests.get(url, timeout=timeout, verify=False, auth=auth) - response.raise_for_status() - port_desc = response.json() - LOGGER.info(f"Successfully retrieved description for DPID {dpid}: {port_desc}") - return port_desc - except requests.exceptions.RequestException as e: - LOGGER.error(f"Failed to retrieve description for DPID {dpid}: {str(e)}") - return {} - -##according to dpid -def del_flow_entry(root_url: str, dpid: str, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> Dict: - url = f"{root_url}{RESOURCE_ENDPOINTS['flowentry_delete']}/{dpid}" - try: - response = requests.delete(url, timeout=timeout, verify=False, auth=auth) - response.raise_for_status() - flow_desc = response.json() - LOGGER.info(f"Successfully retrieved description for DPID {dpid}: {flow_desc}") - return flow_desc - except requests.exceptions.RequestException as e: - LOGGER.error(f"Failed to retrieve description for DPID {dpid}: {str(e)}") - return {} - -# to delete a flow based on match criteria. -def delete_flow(root_url: str, flow_data: dict, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> bool: - url = f"{root_url}{RESOURCE_ENDPOINTS['flow_delete']}" - try: - response = requests.post(url, json=flow_data, timeout=timeout, verify=False, auth=auth) - response.raise_for_status() - LOGGER.info(f"Flow configuration deleted successfully for DPID {flow_data.get('dpid')}.") - return True - except requests.exceptions.RequestException as e: - LOGGER.error(f"Failed to delete flow configuration for DPID {flow_data.get('dpid')}: {str(e)}") - return False - -def add_flow(root_url: str, flow_data: dict, auth: Optional[HTTPBasicAuth] = None, timeout: Optional[int] = None) -> bool: - url = f"{root_url}{RESOURCE_ENDPOINTS['flow_add']}" - LOGGER.info(f"Posting flow data: {flow_data} (type: {type(flow_data)}) to URL: {url}") - try: - response = requests.post(url, json=flow_data, timeout=timeout, verify=False, auth=auth) - response.raise_for_status() - LOGGER.info("Flow configuration added successfully.") - return True - except requests.exceptions.RequestException as e: - LOGGER.error(f"Failed to add flow configuration: {str(e)}") - return False - - - diff --git a/tmp-code/__init__.py b/tmp-code/__init__.py deleted file mode 100644 index 487cf7d40..000000000 --- a/tmp-code/__init__.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright 2022-2024 ETSI OSG/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 os -from common.DeviceTypes import DeviceTypeEnum -from common.proto.context_pb2 import DeviceDriverEnum -from device.Config import LOAD_ALL_DEVICE_DRIVERS -from ..driver_api.FilterFields import FilterFieldEnum - -DRIVERS = [] - -from .emulated.EmulatedDriver import EmulatedDriver # pylint: disable=wrong-import-position -DRIVERS.append( - (EmulatedDriver, [ - # TODO: multi-filter is not working - { - FilterFieldEnum.DEVICE_TYPE: [ - DeviceTypeEnum.EMULATED_DATACENTER, - DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM, - DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM, - DeviceTypeEnum.EMULATED_OPTICAL_ROADM, - DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER, - DeviceTypeEnum.EMULATED_P4_SWITCH, - DeviceTypeEnum.EMULATED_PACKET_ROUTER, - DeviceTypeEnum.EMULATED_PACKET_SWITCH, - - #DeviceTypeEnum.DATACENTER, - #DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM, - #DeviceTypeEnum.OPEN_LINE_SYSTEM, - #DeviceTypeEnum.OPTICAL_ROADM, - #DeviceTypeEnum.OPTICAL_TRANSPONDER, - #DeviceTypeEnum.P4_SWITCH, - #DeviceTypeEnum.PACKET_ROUTER, - #DeviceTypeEnum.PACKET_SWITCH, - ], - FilterFieldEnum.DRIVER: [ - DeviceDriverEnum.DEVICEDRIVER_UNDEFINED, - ], - }, - #{ - # # Emulated devices, all drivers => use Emulated - # FilterFieldEnum.DEVICE_TYPE: [ - # DeviceTypeEnum.EMULATED_DATACENTER, - # DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM, - # DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM, - # DeviceTypeEnum.EMULATED_OPTICAL_ROADM, - # DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER, - # DeviceTypeEnum.EMULATED_P4_SWITCH, - # DeviceTypeEnum.EMULATED_PACKET_ROUTER, - # DeviceTypeEnum.EMULATED_PACKET_SWITCH, - # ], - # FilterFieldEnum.DRIVER: [ - # DeviceDriverEnum.DEVICEDRIVER_UNDEFINED, - # DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, - # DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API, - # DeviceDriverEnum.DEVICEDRIVER_P4, - # DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY, - # DeviceDriverEnum.DEVICEDRIVER_ONF_TR_532, - # DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, - # ], - #} - ])) - -from .ietf_l2vpn.IetfL2VpnDriver import IetfL2VpnDriver # pylint: disable=wrong-import-position -DRIVERS.append( - (IetfL2VpnDriver, [ - { - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.TERAFLOWSDN_CONTROLLER, - FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN, - } - ])) - -from .ietf_actn.IetfActnDriver import IetfActnDriver # pylint: disable=wrong-import-position -DRIVERS.append( - (IetfActnDriver, [ - { - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPEN_LINE_SYSTEM, - FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN, - } - ])) - -if LOAD_ALL_DEVICE_DRIVERS: - from .openconfig.OpenConfigDriver import OpenConfigDriver # pylint: disable=wrong-import-position - DRIVERS.append( - (OpenConfigDriver, [ - { - # Real Packet Router, specifying OpenConfig Driver => use OpenConfigDriver - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.PACKET_ROUTER, - FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, - } - ])) - -if LOAD_ALL_DEVICE_DRIVERS: - from .gnmi_openconfig.GnmiOpenConfigDriver import GnmiOpenConfigDriver # pylint: disable=wrong-import-position - DRIVERS.append( - (GnmiOpenConfigDriver, [ - { - # Real Packet Router, specifying gNMI OpenConfig Driver => use GnmiOpenConfigDriver - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.PACKET_ROUTER, - FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, - } - ])) - -if LOAD_ALL_DEVICE_DRIVERS: - from .transport_api.TransportApiDriver import TransportApiDriver # pylint: disable=wrong-import-position - DRIVERS.append( - (TransportApiDriver, [ - { - # Real OLS, specifying TAPI Driver => use TransportApiDriver - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPEN_LINE_SYSTEM, - FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API, - } - ])) - -if LOAD_ALL_DEVICE_DRIVERS: - from .p4.p4_driver import P4Driver # pylint: disable=wrong-import-position - DRIVERS.append( - (P4Driver, [ - { - # Real P4 Switch, specifying P4 Driver => use P4Driver - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.P4_SWITCH, - FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_P4, - } - ])) - -if LOAD_ALL_DEVICE_DRIVERS: - from .microwave.IETFApiDriver import IETFApiDriver # pylint: disable=wrong-import-position - DRIVERS.append( - (IETFApiDriver, [ - { - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM, - FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY, - } - ])) -if LOAD_ALL_DEVICE_DRIVERS: - from.OpenFlow.OpenFlowDriver import OpenFlowDriver - DRIVERS.append( - (OpenFlowDriver, [ - { - # Specify the device type and driver that should use OpenFlowDriver - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPENFLOW_RYU_CONTROLLER , - FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_OPENFLOW, - } - ]) - ) - -if LOAD_ALL_DEVICE_DRIVERS: - from .xr.XrDriver import XrDriver # pylint: disable=wrong-import-position - DRIVERS.append( - (XrDriver, [ - { - # Close enough, it does optical switching - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.XR_CONSTELLATION, - FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_XR, - } - ])) - -if LOAD_ALL_DEVICE_DRIVERS: - from .optical_tfs.OpticalTfsDriver import OpticalTfsDriver # pylint: disable=wrong-import-position - DRIVERS.append( - (OpticalTfsDriver, [ - { - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPEN_LINE_SYSTEM, - FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_OPTICAL_TFS, - } - ])) - -if LOAD_ALL_DEVICE_DRIVERS: - from .oc_driver.OCDriver import OCDriver # pylint: disable=wrong-import-position - DRIVERS.append( - (OCDriver, [ - { - # Real Packet Router, specifying OpenConfig Driver => use OpenConfigDriver - FilterFieldEnum.DEVICE_TYPE: [ - DeviceTypeEnum.OPTICAL_ROADM, - DeviceTypeEnum.OPTICAL_TRANSPONDER - ], - FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_OC, - } - ])) - -if LOAD_ALL_DEVICE_DRIVERS: - from .qkd.QKDDriver2 import QKDDriver # pylint: disable=wrong-import-position - DRIVERS.append( - (QKDDriver, [ - { - # Close enough, it does optical switching - FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.QKD_NODE, - FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_QKD, - } - ])) diff --git a/tmp-code/context.proto b/tmp-code/context.proto deleted file mode 100644 index 2ab6f0aea..000000000 --- a/tmp-code/context.proto +++ /dev/null @@ -1,698 +0,0 @@ -// Copyright 2022-2024 ETSI OSG/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. - -syntax = "proto3"; -package context; - -import "acl.proto"; -import "kpi_sample_types.proto"; - -service ContextService { - rpc ListContextIds (Empty ) returns ( ContextIdList ) {} - rpc ListContexts (Empty ) returns ( ContextList ) {} - rpc GetContext (ContextId ) returns ( Context ) {} - rpc SetContext (Context ) returns ( ContextId ) {} - rpc RemoveContext (ContextId ) returns ( Empty ) {} - rpc GetContextEvents (Empty ) returns (stream ContextEvent ) {} - - rpc ListTopologyIds (ContextId ) returns ( TopologyIdList ) {} - rpc ListTopologies (ContextId ) returns ( TopologyList ) {} - rpc GetTopology (TopologyId ) returns ( Topology ) {} - rpc GetTopologyDetails (TopologyId ) returns ( TopologyDetails ) {} - rpc SetTopology (Topology ) returns ( TopologyId ) {} - rpc RemoveTopology (TopologyId ) returns ( Empty ) {} - rpc GetTopologyEvents (Empty ) returns (stream TopologyEvent ) {} - - rpc ListDeviceIds (Empty ) returns ( DeviceIdList ) {} - rpc ListDevices (Empty ) returns ( DeviceList ) {} - rpc GetDevice (DeviceId ) returns ( Device ) {} - rpc SetDevice (Device ) returns ( DeviceId ) {} - rpc RemoveDevice (DeviceId ) returns ( Empty ) {} - rpc GetDeviceEvents (Empty ) returns (stream DeviceEvent ) {} - rpc SelectDevice (DeviceFilter ) returns ( DeviceList ) {} - rpc ListEndPointNames (EndPointIdList) returns ( EndPointNameList) {} - - rpc ListLinkIds (Empty ) returns ( LinkIdList ) {} - rpc ListLinks (Empty ) returns ( LinkList ) {} - rpc GetLink (LinkId ) returns ( Link ) {} - rpc SetLink (Link ) returns ( LinkId ) {} - rpc RemoveLink (LinkId ) returns ( Empty ) {} - rpc GetLinkEvents (Empty ) returns (stream LinkEvent ) {} - - rpc ListServiceIds (ContextId ) returns ( ServiceIdList ) {} - rpc ListServices (ContextId ) returns ( ServiceList ) {} - rpc GetService (ServiceId ) returns ( Service ) {} - rpc SetService (Service ) returns ( ServiceId ) {} - rpc UnsetService (Service ) returns ( ServiceId ) {} - rpc RemoveService (ServiceId ) returns ( Empty ) {} - rpc GetServiceEvents (Empty ) returns (stream ServiceEvent ) {} - rpc SelectService (ServiceFilter ) returns ( ServiceList ) {} - - rpc ListSliceIds (ContextId ) returns ( SliceIdList ) {} - rpc ListSlices (ContextId ) returns ( SliceList ) {} - rpc GetSlice (SliceId ) returns ( Slice ) {} - rpc SetSlice (Slice ) returns ( SliceId ) {} - rpc UnsetSlice (Slice ) returns ( SliceId ) {} - rpc RemoveSlice (SliceId ) returns ( Empty ) {} - rpc GetSliceEvents (Empty ) returns (stream SliceEvent ) {} - rpc SelectSlice (SliceFilter ) returns ( SliceList ) {} - - rpc ListConnectionIds (ServiceId ) returns ( ConnectionIdList) {} - rpc ListConnections (ServiceId ) returns ( ConnectionList ) {} - rpc GetConnection (ConnectionId ) returns ( Connection ) {} - rpc SetConnection (Connection ) returns ( ConnectionId ) {} - rpc RemoveConnection (ConnectionId ) returns ( Empty ) {} - rpc GetConnectionEvents(Empty ) returns (stream ConnectionEvent ) {} - - - // ------------------------------ Experimental ----------------------------- - rpc GetOpticalConfig (Empty ) returns (OpticalConfigList ) {} - rpc SetOpticalConfig (OpticalConfig ) returns (OpticalConfigId ) {} - rpc SelectOpticalConfig(OpticalConfigId) returns (OpticalConfig ) {} - - rpc SetOpticalLink (OpticalLink ) returns (Empty ) {} - rpc GetOpticalLink (OpticalLinkId ) returns (OpticalLink ) {} - rpc GetFiber (FiberId ) returns (Fiber ) {} -} - -// ----- Generic ------------------------------------------------------------------------------------------------------- -message Empty {} - -message Uuid { - string uuid = 1; -} - -enum EventTypeEnum { - EVENTTYPE_UNDEFINED = 0; - EVENTTYPE_CREATE = 1; - EVENTTYPE_UPDATE = 2; - EVENTTYPE_REMOVE = 3; -} - -message Timestamp { - double timestamp = 1; -} - -message Event { - Timestamp timestamp = 1; - EventTypeEnum event_type = 2; -} - -// ----- Context ------------------------------------------------------------------------------------------------------- -message ContextId { - Uuid context_uuid = 1; -} - -message Context { - ContextId context_id = 1; - string name = 2; - repeated TopologyId topology_ids = 3; - repeated ServiceId service_ids = 4; - repeated SliceId slice_ids = 5; - TeraFlowController controller = 6; -} - -message ContextIdList { - repeated ContextId context_ids = 1; -} - -message ContextList { - repeated Context contexts = 1; -} - -message ContextEvent { - Event event = 1; - ContextId context_id = 2; -} - - -// ----- Topology ------------------------------------------------------------------------------------------------------ -message TopologyId { - ContextId context_id = 1; - Uuid topology_uuid = 2; -} - -message Topology { - TopologyId topology_id = 1; - string name = 2; - repeated DeviceId device_ids = 3; - repeated LinkId link_ids = 4; -} - -message TopologyDetails { - TopologyId topology_id = 1; - string name = 2; - repeated Device devices = 3; - repeated Link links = 4; -} - -message TopologyIdList { - repeated TopologyId topology_ids = 1; -} - -message TopologyList { - repeated Topology topologies = 1; -} - -message TopologyEvent { - Event event = 1; - TopologyId topology_id = 2; -} - - -// ----- Device -------------------------------------------------------------------------------------------------------- -message DeviceId { - Uuid device_uuid = 1; -} - -message Device { - DeviceId device_id = 1; - string name = 2; - string device_type = 3; - DeviceConfig device_config = 4; - DeviceOperationalStatusEnum device_operational_status = 5; - repeated DeviceDriverEnum device_drivers = 6; - repeated EndPoint device_endpoints = 7; - repeated Component components = 8; // Used for inventory - DeviceId controller_id = 9; // Identifier of node controlling the actual device -} - -message Component { //Defined previously to this section - Tested OK - Uuid component_uuid = 1; - string name = 2; - string type = 3; - - map attributes = 4; // dict[attr.name => json.dumps(attr.value)] - string parent = 5; -} - -message DeviceConfig { - repeated ConfigRule config_rules = 1; -} - -enum DeviceDriverEnum { - DEVICEDRIVER_UNDEFINED = 0; // also used for emulated - 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; -} - -enum DeviceOperationalStatusEnum { - DEVICEOPERATIONALSTATUS_UNDEFINED = 0; - DEVICEOPERATIONALSTATUS_DISABLED = 1; - DEVICEOPERATIONALSTATUS_ENABLED = 2; -} - -message DeviceIdList { - repeated DeviceId device_ids = 1; -} - -message DeviceList { - repeated Device devices = 1; -} - -message DeviceFilter { - DeviceIdList device_ids = 1; - bool include_endpoints = 2; - bool include_config_rules = 3; - bool include_components = 4; -} - -message DeviceEvent { - Event event = 1; - DeviceId device_id = 2; - DeviceConfig device_config = 3; -} - - -// ----- Link ---------------------------------------------------------------------------------------------------------- -message LinkId { - Uuid link_uuid = 1; -} - -message LinkAttributes { - float total_capacity_gbps = 1; - float used_capacity_gbps = 2; -} - -message Link { - LinkId link_id = 1; - string name = 2; - repeated EndPointId link_endpoint_ids = 3; - LinkAttributes attributes = 4; - LinkTypeEnum link_type = 5; -} - -message LinkIdList { - repeated LinkId link_ids = 1; -} - -message LinkList { - repeated Link links = 1; -} - -message LinkEvent { - Event event = 1; - LinkId link_id = 2; -} - -enum LinkTypeEnum { - LINKTYPE_UNKNOWN = 0; - LINKTYPE_COPPER = 1; - LINKTYPE_VIRTUAL_COPPER = 2; - LINKTYPE_OPTICAL = 3; - LINKTYPE_VIRTUAL_OPTICAL = 4; -} - -// ----- Service ------------------------------------------------------------------------------------------------------- -message ServiceId { - ContextId context_id = 1; - Uuid service_uuid = 2; -} - -message Service { - ServiceId service_id = 1; - string name = 2; - ServiceTypeEnum service_type = 3; - repeated EndPointId service_endpoint_ids = 4; - repeated Constraint service_constraints = 5; - ServiceStatus service_status = 6; - ServiceConfig service_config = 7; - Timestamp timestamp = 8; -} - -enum ServiceTypeEnum { - SERVICETYPE_UNKNOWN = 0; - SERVICETYPE_L3NM = 1; - SERVICETYPE_L2NM = 2; - SERVICETYPE_TAPI_CONNECTIVITY_SERVICE = 3; - SERVICETYPE_TE = 4; - SERVICETYPE_E2E = 5; - SERVICETYPE_OPTICAL_CONNECTIVITY = 6; - SERVICETYPE_QKD = 7; -} - -enum ServiceStatusEnum { - SERVICESTATUS_UNDEFINED = 0; - SERVICESTATUS_PLANNED = 1; - SERVICESTATUS_ACTIVE = 2; - SERVICESTATUS_UPDATING = 3; - SERVICESTATUS_PENDING_REMOVAL = 4; - SERVICESTATUS_SLA_VIOLATED = 5; -} - -message ServiceStatus { - ServiceStatusEnum service_status = 1; -} - -message ServiceConfig { - repeated ConfigRule config_rules = 1; -} - -message ServiceIdList { - repeated ServiceId service_ids = 1; -} - -message ServiceList { - repeated Service services = 1; -} - -message ServiceFilter { - ServiceIdList service_ids = 1; - bool include_endpoint_ids = 2; - bool include_constraints = 3; - bool include_config_rules = 4; -} - -message ServiceEvent { - Event event = 1; - ServiceId service_id = 2; -} - -// ----- Slice --------------------------------------------------------------------------------------------------------- -message SliceId { - ContextId context_id = 1; - Uuid slice_uuid = 2; -} - -message Slice { - SliceId slice_id = 1; - string name = 2; - repeated EndPointId slice_endpoint_ids = 3; - repeated Constraint slice_constraints = 4; - repeated ServiceId slice_service_ids = 5; - repeated SliceId slice_subslice_ids = 6; - SliceStatus slice_status = 7; - SliceConfig slice_config = 8; - SliceOwner slice_owner = 9; - Timestamp timestamp = 10; -} - -message SliceOwner { - Uuid owner_uuid = 1; - string owner_string = 2; -} - -enum SliceStatusEnum { - SLICESTATUS_UNDEFINED = 0; - SLICESTATUS_PLANNED = 1; - SLICESTATUS_INIT = 2; - SLICESTATUS_ACTIVE = 3; - SLICESTATUS_DEINIT = 4; - SLICESTATUS_SLA_VIOLATED = 5; -} - -message SliceStatus { - SliceStatusEnum slice_status = 1; -} - -message SliceConfig { - repeated ConfigRule config_rules = 1; -} - -message SliceIdList { - repeated SliceId slice_ids = 1; -} - -message SliceList { - repeated Slice slices = 1; -} - -message SliceFilter { - SliceIdList slice_ids = 1; - bool include_endpoint_ids = 2; - bool include_constraints = 3; - bool include_service_ids = 4; - bool include_subslice_ids = 5; - bool include_config_rules = 6; -} - -message SliceEvent { - Event event = 1; - SliceId slice_id = 2; -} - -// ----- Connection ---------------------------------------------------------------------------------------------------- -message ConnectionId { - Uuid connection_uuid = 1; -} - -message ConnectionSettings_L0 { - string lsp_symbolic_name = 1; -} - -message ConnectionSettings_L2 { - string src_mac_address = 1; - string dst_mac_address = 2; - uint32 ether_type = 3; - uint32 vlan_id = 4; - uint32 mpls_label = 5; - uint32 mpls_traffic_class = 6; -} - -message ConnectionSettings_L3 { - string src_ip_address = 1; - string dst_ip_address = 2; - uint32 dscp = 3; - uint32 protocol = 4; - uint32 ttl = 5; -} - -message ConnectionSettings_L4 { - uint32 src_port = 1; - uint32 dst_port = 2; - uint32 tcp_flags = 3; - uint32 ttl = 4; -} - -message ConnectionSettings { - ConnectionSettings_L0 l0 = 1; - ConnectionSettings_L2 l2 = 2; - ConnectionSettings_L3 l3 = 3; - ConnectionSettings_L4 l4 = 4; -} - -message Connection { - ConnectionId connection_id = 1; - ServiceId service_id = 2; - repeated EndPointId path_hops_endpoint_ids = 3; - repeated ServiceId sub_service_ids = 4; - ConnectionSettings settings = 5; -} - -message ConnectionIdList { - repeated ConnectionId connection_ids = 1; -} - -message ConnectionList { - repeated Connection connections = 1; -} - -message ConnectionEvent { - Event event = 1; - ConnectionId connection_id = 2; -} - - -// ----- Endpoint ------------------------------------------------------------------------------------------------------ -message EndPointId { - TopologyId topology_id = 1; - DeviceId device_id = 2; - Uuid endpoint_uuid = 3; -} - -message EndPoint { - EndPointId endpoint_id = 1; - string name = 2; - string endpoint_type = 3; - repeated kpi_sample_types.KpiSampleType kpi_sample_types = 4; - Location endpoint_location = 5; -} - -message EndPointName { - EndPointId endpoint_id = 1; - string device_name = 2; - string endpoint_name = 3; - string endpoint_type = 4; -} - -message EndPointIdList { - repeated EndPointId endpoint_ids = 1; -} - -message EndPointNameList { - repeated EndPointName endpoint_names = 1; -} - - -// ----- Configuration ------------------------------------------------------------------------------------------------- -enum ConfigActionEnum { - CONFIGACTION_UNDEFINED = 0; - CONFIGACTION_SET = 1; - CONFIGACTION_DELETE = 2; -} - -message ConfigRule_Custom { - string resource_key = 1; - string resource_value = 2; -} - -message ConfigRule_ACL { - EndPointId endpoint_id = 1; - acl.AclRuleSet rule_set = 2; -} - -message ConfigRule { - ConfigActionEnum action = 1; - oneof config_rule { - ConfigRule_Custom custom = 2; - ConfigRule_ACL acl = 3; - } -} - - -// ----- Constraint ---------------------------------------------------------------------------------------------------- -enum ConstraintActionEnum { - CONSTRAINTACTION_UNDEFINED = 0; - CONSTRAINTACTION_SET = 1; - CONSTRAINTACTION_DELETE = 2; -} - -message Constraint_Custom { - string constraint_type = 1; - string constraint_value = 2; -} - -message Constraint_Schedule { - double start_timestamp = 1; - float duration_days = 2; -} - -message GPS_Position { - float latitude = 1; - float longitude = 2; -} - -message Location { - oneof location { - string region = 1; - GPS_Position gps_position = 2; - } -} - -message Constraint_EndPointLocation { - EndPointId endpoint_id = 1; - Location location = 2; -} - -message Constraint_EndPointPriority { - EndPointId endpoint_id = 1; - uint32 priority = 2; -} - -message Constraint_SLA_Latency { - float e2e_latency_ms = 1; -} - -message Constraint_SLA_Capacity { - float capacity_gbps = 1; -} - -message Constraint_SLA_Availability { - uint32 num_disjoint_paths = 1; - bool all_active = 2; - float availability = 3; // 0.0 .. 100.0 percentage of availability -} - -enum IsolationLevelEnum { - NO_ISOLATION = 0; - PHYSICAL_ISOLATION = 1; - LOGICAL_ISOLATION = 2; - PROCESS_ISOLATION = 3; - PHYSICAL_MEMORY_ISOLATION = 4; - PHYSICAL_NETWORK_ISOLATION = 5; - VIRTUAL_RESOURCE_ISOLATION = 6; - NETWORK_FUNCTIONS_ISOLATION = 7; - SERVICE_ISOLATION = 8; -} - -message Constraint_SLA_Isolation_level { - repeated IsolationLevelEnum isolation_level = 1; -} - -message Constraint_Exclusions { - bool is_permanent = 1; - repeated DeviceId device_ids = 2; - repeated EndPointId endpoint_ids = 3; - repeated LinkId link_ids = 4; -} - - -message QoSProfileId { - context.Uuid qos_profile_id = 1; -} - -message Constraint_QoSProfile { - QoSProfileId qos_profile_id = 1; - string qos_profile_name = 2; -} - -message Constraint { - ConstraintActionEnum action = 1; - oneof constraint { - Constraint_Custom custom = 2; - Constraint_Schedule schedule = 3; - Constraint_EndPointLocation endpoint_location = 4; - Constraint_EndPointPriority endpoint_priority = 5; - Constraint_SLA_Capacity sla_capacity = 6; - Constraint_SLA_Latency sla_latency = 7; - Constraint_SLA_Availability sla_availability = 8; - Constraint_SLA_Isolation_level sla_isolation = 9; - Constraint_Exclusions exclusions = 10; - Constraint_QoSProfile qos_profile = 11; - } -} - - -// ----- Miscellaneous ------------------------------------------------------------------------------------------------- -message TeraFlowController { - ContextId context_id = 1; - string ip_address = 2; - uint32 port = 3; -} - -message AuthenticationResult { - ContextId context_id = 1; - bool authenticated = 2; -} - -// ---------------- Experimental ------------------------ -message OpticalConfigId { - string opticalconfig_uuid = 1; -} -message OpticalConfig { - OpticalConfigId opticalconfig_id = 1; - string config = 2; -} - -message OpticalConfigList { - repeated OpticalConfig opticalconfigs = 1; -} - -// ---- Optical Link ---- - -message OpticalLinkId { - Uuid optical_link_uuid = 1; -} - -message FiberId { - Uuid fiber_uuid = 1; -} - -message Fiber { - string ID = 10; - string src_port = 1; - string dst_port = 2; - string local_peer_port = 3; - string remote_peer_port = 4; - repeated int32 c_slots = 5; - repeated int32 l_slots = 6; - repeated int32 s_slots = 7; - float length = 8; - bool used = 9; - FiberId fiber_uuid = 11; - -} -message OpticalLinkDetails { - float length = 1; - string source = 2; - string target = 3; - repeated Fiber fibers = 4; -} - -message OpticalLink { - string name = 1; - OpticalLinkDetails details = 2; - OpticalLinkId optical_link_uuid = 3; -} diff --git a/tmp-code/run_openflow.sh b/tmp-code/run_openflow.sh deleted file mode 100755 index 2c525ca70..000000000 --- a/tmp-code/run_openflow.sh +++ /dev/null @@ -1,8 +0,0 @@ -PROJECTDIR=`pwd` - -cd $PROJECTDIR/src -RCFILE=$PROJECTDIR/coverage/.coveragerc - -# Run unitary tests and analyze coverage of code at same time -coverage run --rcfile=$RCFILE --append -m pytest --log-level=DEBUG --verbose \ - device/tests/test_OpenFlow.py \ No newline at end of file diff --git a/tmp-code/test_OpenFlow.py b/tmp-code/test_OpenFlow.py deleted file mode 100644 index 60ee4542c..000000000 --- a/tmp-code/test_OpenFlow.py +++ /dev/null @@ -1,77 +0,0 @@ -import json -from re import A -import resource -import logging, os, sys, time -#from typing import Dict, Self, Tuple -os.environ['DEVICE_EMULATED_ONLY'] = 'YES' -from device.service.drivers.OpenFlow.OpenFlowDriver import OpenFlowDriver -logging.basicConfig(level=logging.DEBUG) -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) - - -def test_main(): - driver_settings = { - 'protocol': 'http', - 'username': None, - 'password': None, - 'use_tls': False, - } - driver = OpenFlowDriver('127.0.0.1', 8080 , **driver_settings) - driver.Connect() - - - # Test: GetConfig - #resource_keys = [ 'flows:1','description:1','switches','port_description:1','switch_info','links_info'] - # config = driver.GetConfig(resource_keys ) - # LOGGER.info('Specific configuration: %s', config) - - #resource_delete=["flowentry_delete:1"] - #config = driver.DeleteConfig(resource_delete) - #LOGGER.info('Specific configuration: %s', config) - #a=driver.GetConfig(["flows:1"]) - #LOGGER.info('flow 1 = {:s}'.format(str(a))) -# delete_data = { -# "dpid": 2, -# "cookie": 1, -# "cookie_mask": 1, -# "table_id": 0, -# "idle_timeout": 30, -# "hard_timeout": 30, -# "priority": 11111, -# "flags": 1, -# "match":{ -# "in_port":2 -# }, -# "actions":[ -# { -# "type":"ddf", -# "port": 1 -# } -# ] -# } -# delete_result = driver.DeleteConfig([("flow_data", delete_data)]) -# LOGGER.info('resources_to_delete = {:s}'.format(str(delete_result))) -# a=driver.GetConfig(["flows:1"]) -# LOGGER.info('flow 2 = {:s}'.format(str(a))) - flow_data = { - "dpid": 2, - "priority": 22224, - "match": { - "in_port": 1 - }, - "actions": [ - { - "type": "GOTO_TABLE", - "table_id": 1 - } - ] - } - set_result = driver.SetConfig([('flow_data',flow_data)]) - LOGGER.info(set_result) - driver.Disconnect() - - raise Exception () - -if __name__ == '__main__': - sys.exit(test_main()) -- GitLab From b656e1658a812595b105b234fe0a160352fde066 Mon Sep 17 00:00:00 2001 From: rahhal Date: Thu, 12 Dec 2024 15:40:41 +0000 Subject: [PATCH 4/7] Updated-TaskExecutor --- .../service/task_scheduler/TaskExecutor.py | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py index 6fb1eca34..55f50f044 100644 --- a/src/service/service/task_scheduler/TaskExecutor.py +++ b/src/service/service/task_scheduler/TaskExecutor.py @@ -287,10 +287,15 @@ class TaskExecutor: devices.setdefault(device_type, dict())[device_uuid] = device else: if not exclude_managed_by_controller: + LOGGER.debug('device managed by controller = {:s}'.format(str(device_uuid))) device_type = DeviceTypeEnum._value2member_map_[device.device_type] + LOGGER.debug('device_type not exlude by controller = {:s}'.format(str(device_type))) devices.setdefault(device_type, dict())[device_uuid] = device - device_type = DeviceTypeEnum._value2member_map_[controller.device_type] - devices.setdefault(device_type, dict())[controller.device_id.device_uuid.uuid] = controller + else: + device_type = DeviceTypeEnum._value2member_map_[controller.device_type] + LOGGER.debug('device_type = {:s}'.format(str(device_type))) + devices.setdefault(device_type, dict())[controller.device_id.device_uuid.uuid] = controller + return devices # ----- Service-related methods ------------------------------------------------------------------------------------ @@ -320,16 +325,30 @@ class TaskExecutor: def get_service_handlers( self, connection : Connection, service : Service, **service_handler_settings ) -> Dict[DeviceTypeEnum, Tuple['_ServiceHandler', Dict[str, Device]]]: - connection_device_types : Dict[DeviceTypeEnum, Dict[str, Device]] = self.get_devices_from_connection( + # WARNING: exclude_managed_by_controller should be True, changed to False for test purposes. + # For Ryu SDN controller we need to know the underlying devices we are traversing. + # Elaborate proper logic to resolve this case. + connection_device_types_excluded : Dict[DeviceTypeEnum, Dict[str, Device]] = self.get_devices_from_connection( connection, exclude_managed_by_controller=True ) + LOGGER.debug('connection_device_types_excluded = {:s}'.format(str(connection_device_types_excluded))) + connection_device_types_included : Dict[DeviceTypeEnum, Dict[str, Device]] = self.get_devices_from_connection( + connection, exclude_managed_by_controller=False + ) + LOGGER.debug('connection_device_types_included = {:s}'.format(str(connection_device_types_included))) service_handlers : Dict[DeviceTypeEnum, Tuple['_ServiceHandler', Dict[str, Device]]] = dict() - for device_type, connection_devices in connection_device_types.items(): + for device_type, connection_devices in connection_device_types_excluded.items(): try: service_handler_class = get_service_handler_class( - self._service_handler_factory, service, connection_devices) + self._service_handler_factory, service, connection_devices + ) + LOGGER.debug('service_handler_class IN CONNECTION DEVICE TYPE EXCLUDED = {:s}'.format(str(service_handler_class.__name__))) service_handler = service_handler_class(service, self, **service_handler_settings) - service_handlers[device_type] = (service_handler, connection_devices) + LOGGER.debug('service_handler IN CONNECTION DEVICE TYPE EXCLUDED = {:s}'.format(str(service_handler))) + connection_devices_included = connection_device_types_included.get(device_type, connection_devices) + LOGGER.debug('connection_devices_included IN CONNECTION DEVICE TYPE EXCLUDED = {:s}'.format(str(connection_devices_included))) + service_handlers[device_type] = (service_handler, connection_devices_included) + LOGGER.debug('service_handlers IN CONNECTION DEVICE TYPE EXCLUDED = {:s}'.format(str(service_handlers))) except ( UnsatisfiedFilterException, UnsupportedFilterFieldException, UnsupportedFilterFieldValueException -- GitLab From f47ed4750eabe802756182f58b81e4de2270967a Mon Sep 17 00:00:00 2001 From: rahhal Date: Mon, 13 Jan 2025 15:47:28 +0000 Subject: [PATCH 5/7] Service component - Ryu Driver: - Added Configuration Rules In Service Handler --- .../drivers/OpenFlow/OpenFlowDriver.py | 36 ++----- .../l3nm_ryu/L3NMryuServiceHandler.py | 96 +++++++++++++------ .../service/task_scheduler/TaskExecutor.py | 2 +- 3 files changed, 78 insertions(+), 56 deletions(-) diff --git a/src/device/service/drivers/OpenFlow/OpenFlowDriver.py b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py index a425943e4..8ccf7e71d 100644 --- a/src/device/service/drivers/OpenFlow/OpenFlowDriver.py +++ b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py @@ -147,34 +147,14 @@ class OpenFlowDriver(_Driver): # results.append((key, e)) # return results # -# @metered_subclass_method(METRICS_POOL) -# def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: -# results = [] -# if not resources: -# return results -# with self.__lock: -# for item in resources: -# LOGGER.info('resources contains: %s', item) -# try: -# if isinstance(item, tuple) and len(item) == 2: -# key, flow_data = item -# else: -# LOGGER.warning("Resource format invalid. Each item should be a tuple with (key, data).") -# results.append(False) -# continue -# if key == "flow_data" and isinstance(flow_data, dict): -# LOGGER.info(f"Found valid flow_data entry: {flow_data}") -# success = add_flow(self.__base_url, flow_data, auth=self.__auth, timeout=self.__timeout) -# results.append(success) -# else: -# LOGGER.warning(f"Skipping item with key: {key} due to invalid format or missing data.") -# results.append(False) -# -# except Exception as e: -# LOGGER.error(f"Exception while setting configuration for item {item}: {str(e)}") -# results.append(e) -# -# return results + @metered_subclass_method(METRICS_POOL) + def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + results = [] + LOGGER.info(f'SetConfig_resources:{resources}') + if not resources: + return results + + return results # # # diff --git a/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py b/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py index 536f3997d..08141fda5 100644 --- a/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py +++ b/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py @@ -13,14 +13,18 @@ # limitations under the License. import json, logging, netaddr +from venv import logger from re import L from typing import Any, Dict, List, Optional, Tuple, Union + +from pytest import skip from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method -from common.proto.context_pb2 import ConfigRule, Device, DeviceId, EndPoint, Service +from common.proto.context_pb2 import ConfigRule, Device, DeviceId, EndPoint, Service,ConfigRule_Custom,ConfigActionEnum from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set from common.tools.object_factory.Device import json_device_id from common.type_checkers.Checkers import chk_type +#from nbi.service.rest_server.nbi_plugins.ietf_network.bindings.networks.network.link import destination from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching from service.service.service_handler_api._ServiceHandler import _ServiceHandler from service.service.service_handler_api.SettingsHandler import SettingsHandler @@ -41,25 +45,28 @@ class RYUServiceHandler(_ServiceHandler): self.__settings_handler = SettingsHandler(service.service_config, **settings) - #def _get_endpoint_details( - # self, endpoint : Tuple[str, str, Optional[str]] - #) -> Tuple[Device, EndPoint, Dict]: - # device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) - # LOGGER.debug('device_uuid = {:s}'.format(str(device_uuid))) - # LOGGER.debug('endpoint_uuid = {:s}'.format(str(endpoint_uuid))) - # device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) - # LOGGER.debug('device_obj = {:s}'.format(str(grpc_message_to_json_string(device_obj)))) - # endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) - # LOGGER.debug('endpoint_obj = {:s}'.format(str(grpc_message_to_json_string(endpoint_obj)))) - # endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) - # device_name = device_obj.name - # endpoint_name = endpoint_obj.name - # if endpoint_settings is None: - # MSG = 'Settings not found for Endpoint(device=[uuid={:s}, name={:s}], endpoint=[uuid={:s}, name={:s}])' - # raise Exception(MSG.format(device_uuid, device_name, endpoint_uuid, endpoint_name)) - # endpoint_settings_dict : Dict = endpoint_settings.value - # LOGGER.debug('endpoint_settings_dict = {:s}'.format(str(endpoint_settings_dict))) - # return device_obj, endpoint_obj, endpoint_settings_dict + def _get_endpoint_details( + self, endpoint : Tuple[str, str, Optional[str]] + ) -> Tuple[Device, EndPoint]: #Dict]: + device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) + #LOGGER.debug('device_uuid = {:s}'.format(str(device_uuid))) + #LOGGER.debug('endpoint_uuid = {:s}'.format(str(endpoint_uuid))) + device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + #LOGGER.debug('device_obj = {:s}'.format(str(grpc_message_to_json_string(device_obj)))) + endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + #LOGGER.debug('endpoint_obj = {:s}'.format(str(grpc_message_to_json_string(endpoint_obj)))) + #endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) + #LOGGER.debug('endpoint_settings = {:s}'.format(str(endpoint_settings))) + device_name = device_obj.name + #LOGGER.debug('device_name = {:s}'.format(str(device_name))) + endpoint_name = endpoint_obj.name + #LOGGER.debug('endpoint_name = {:s}'.format(str(endpoint_name))) + #if endpoint_settings is None: + # MSG = 'Settings not found for Endpoint(device=[uuid={:s}, name={:s}], endpoint=[uuid={:s}, name={:s}])' + # raise Exception(MSG.format(device_uuid, device_name, endpoint_uuid, endpoint_name)) + #endpoint_settings_dict : Dict = endpoint_settings.value + #LOGGER.debug('endpoint_settings_dict = {:s}'.format(str(endpoint_settings_dict))) + return device_obj, endpoint_obj #endpoint_settings_dict @metered_subclass_method(METRICS_POOL) @@ -72,15 +79,50 @@ class RYUServiceHandler(_ServiceHandler): LOGGER.warning('nothing done: not enough endpoints') return [] service_uuid = self.__service.service_id.service_uuid.uuid - LOGGER.debug('service_uuid = {:s}'.format(str(service_uuid))) - LOGGER.debug('self.__settings_handler = {:s}'.format(str(self.__settings_handler.dump_config_rules()))) + service_name= self.__service.name + LOGGER.debug('service_name = {:s}'.format(str(service_name))) + #LOGGER.debug('service_uuid = {:s}'.format(str(service_uuid))) + #LOGGER.debug('self.__settings_handler = {:s}'.format(str(self.__settings_handler.dump_config_rules()))) results = [] try: - # Get endpoint details - src_device, src_endpoint, src_settings = self._get_endpoint_details(endpoints[0]) - dst_device, dst_endpoint, dst_settings = self._get_endpoint_details(endpoints[-1]) - LOGGER.debug(f"Source settings: {src_settings}") - LOGGER.debug(f"Destination settings: {dst_settings}") + src_device, src_endpoint, = self._get_endpoint_details(endpoints[0]) + dst_device, dst_endpoint, = self._get_endpoint_details(endpoints[-1]) + src_controller = self.__task_executor.get_device_controller(src_device) + + for index in range(len(endpoints) - 1): + current_device, current_endpoint = self._get_endpoint_details(endpoints[index]) + #LOGGER.debug(f"Current device: {current_device.name}, Current endpoint: {current_endpoint.name}") + next_device, next_endpoint = self._get_endpoint_details(endpoints[index + 1]) + #LOGGER.debug(f"Next device: {next_device.name}, Next endpoint: {next_endpoint.name}") + if current_device.name == next_device.name: + in_port_forward = current_endpoint.name + out_port_forward = next_endpoint.name + flow_split = service_name.split('-') + flow_rule_forward = f"{flow_split[0]}-{flow_split[2]}" + flow_rule_reverse = f"{flow_split[2]}-{flow_split[0]}" + forward_resource_value = json.dumps({"dpid": current_device.name, "in-port": in_port_forward, "out-port": out_port_forward}) + forward_rule = ConfigRule( + custom=ConfigRule_Custom( + resource_key=f"/device[{current_endpoint.name.split('-')[0]}]/flow[{flow_rule_forward}]", + resource_value=forward_resource_value + ) + ) + LOGGER.debug(f"Forward configuration rule: {forward_rule}") + src_controller.device_config.config_rules.append(forward_rule) + in_port_reverse = next_endpoint.name + out_port_reverse = current_endpoint.name + reverse_resource_value = json.dumps({"dpid": current_device.name, "in-port": in_port_reverse, "out-port": out_port_reverse}) + reverse_rule = ConfigRule( + custom=ConfigRule_Custom( + resource_key=f"/device[{current_endpoint.name.split('-')[0]}]/flow[{flow_rule_reverse}]", + resource_value=reverse_resource_value + ) + ) + LOGGER.debug(f"Reverse configuration rule: {reverse_rule}") + src_controller.device_config.config_rules.append(reverse_rule) + + self.__task_executor.configure_device(src_controller) + results.append(True) return results diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py index 55f50f044..19f12ad4b 100644 --- a/src/service/service/task_scheduler/TaskExecutor.py +++ b/src/service/service/task_scheduler/TaskExecutor.py @@ -288,7 +288,7 @@ class TaskExecutor: else: if not exclude_managed_by_controller: LOGGER.debug('device managed by controller = {:s}'.format(str(device_uuid))) - device_type = DeviceTypeEnum._value2member_map_[device.device_type] + device_type = DeviceTypeEnum._value2member_map_[controller.device_type] LOGGER.debug('device_type not exlude by controller = {:s}'.format(str(device_type))) devices.setdefault(device_type, dict())[device_uuid] = device else: -- GitLab From e21ed3e1208678dcac8e5b7c24b6e312ca673168 Mon Sep 17 00:00:00 2001 From: rahhal Date: Fri, 17 Jan 2025 16:31:15 +0000 Subject: [PATCH 6/7] Device component - Ryu Driver: - Added Parsing + Posting Methid --- device | 220 ++++++++++++++++++ .../drivers/OpenFlow/OpenFlowDriver.py | 46 +++- .../l3nm_ryu/L3NMryuServiceHandler.py | 36 +-- 3 files changed, 286 insertions(+), 16 deletions(-) create mode 100644 device diff --git a/device b/device new file mode 100644 index 000000000..758ee9df4 --- /dev/null +++ b/device @@ -0,0 +1,220 @@ +[2025-01-15 15:49:41,972] INFO:__main__:Starting... +[2025-01-15 15:49:41,974] DEBUG:monitoring.client.MonitoringClient:Creating channel to monitoringservice:7070... +[2025-01-15 15:49:41,975] DEBUG:monitoring.client.MonitoringClient:Channel created +[2025-01-15 15:49:41,975] DEBUG:device.service.DeviceServiceServicerImpl:Creating Servicer... +[2025-01-15 15:49:41,975] DEBUG:device.service.DeviceServiceServicerImpl:Servicer Created +[2025-01-15 15:49:41,975] DEBUG:device.service.OpenConfigServicer:Creating Servicer... +[2025-01-15 15:49:41,975] DEBUG:device.service.OpenConfigServicer:Servicer Created +[2025-01-15 15:49:41,975] INFO:device.service.DeviceService:Starting Service (tentative endpoint: 0.0.0.0:2020, max_workers: 200)... +[2025-01-15 15:49:41,981] INFO:device.service.DeviceService:Listening on 0.0.0.0:2020... +[2025-01-15 15:49:41,982] DEBUG:device.service.DeviceService:Service started +[2025-01-15 15:49:41,982] INFO:__main__:Pre-loading drivers... +[2025-01-15 15:49:41,982] DEBUG:context.client.ContextClient:Creating channel to 10.152.183.206:1010... +[2025-01-15 15:49:41,983] DEBUG:context.client.ContextClient:Channel created +[2025-01-15 15:49:41,983] DEBUG:context.client.ContextClient:ListDevices request: {} +[2025-01-15 15:49:46,988] INFO:common.tools.client.RetryDecorator:[context.client.ContextClient:ListDevices] Retry 1/15 after 5.000000 seconds... +[2025-01-15 15:49:46,988] DEBUG:common.tools.client.RetryDecorator:[context.client.ContextClient:connect] Running prepare method... +[2025-01-15 15:49:46,989] DEBUG:context.client.ContextClient:ListDevices request: {} +[2025-01-15 15:49:51,997] INFO:common.tools.client.RetryDecorator:[context.client.ContextClient:ListDevices] Retry 2/15 after 5.000000 seconds... +[2025-01-15 15:49:51,997] DEBUG:common.tools.client.RetryDecorator:[context.client.ContextClient:connect] Running prepare method... +[2025-01-15 15:49:51,998] DEBUG:context.client.ContextClient:ListDevices request: {} +[2025-01-15 15:49:52,149] DEBUG:context.client.ContextClient:ListDevices result: {"devices": []} +[2025-01-15 15:50:17,451] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h1-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "h1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": ""} +[2025-01-15 15:50:17,451] DEBUG:context.client.ContextClient:Creating channel to 10.152.183.206:1010... +[2025-01-15 15:50:17,452] DEBUG:context.client.ContextClient:Channel created +[2025-01-15 15:50:17,453] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "RYU"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "openflow-ryu-controller", "name": ""} +[2025-01-15 15:50:17,453] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "h1"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,453] DEBUG:context.client.ContextClient:Creating channel to 10.152.183.206:1010... +[2025-01-15 15:50:17,455] DEBUG:context.client.ContextClient:Channel created +[2025-01-15 15:50:17,455] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "RYU"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,456] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h3-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "h3"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": ""} +[2025-01-15 15:50:17,457] DEBUG:context.client.ContextClient:Creating channel to 10.152.183.206:1010... +[2025-01-15 15:50:17,457] DEBUG:context.client.ContextClient:Channel created +[2025-01-15 15:50:17,457] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "h3"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,458] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h2-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "h2"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": ""} +[2025-01-15 15:50:17,458] DEBUG:context.client.ContextClient:Creating channel to 10.152.183.206:1010... +[2025-01-15 15:50:17,459] DEBUG:context.client.ContextClient:Channel created +[2025-01-15 15:50:17,459] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "h2"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,461] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h4-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "h4"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": ""} +[2025-01-15 15:50:17,462] DEBUG:context.client.ContextClient:Creating channel to 10.152.183.206:1010... +[2025-01-15 15:50:17,463] DEBUG:context.client.ContextClient:Channel created +[2025-01-15 15:50:17,463] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "h4"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,464] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": []} +[2025-01-15 15:50:17,464] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h1-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "h1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": ""} +[2025-01-15 15:50:17,472] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": []} +[2025-01-15 15:50:17,473] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h3-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "h3"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": ""} +[2025-01-15 15:50:17,517] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}} +[2025-01-15 15:50:17,517] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,533] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": []} +[2025-01-15 15:50:17,533] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h4-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "h4"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": ""} +[2025-01-15 15:50:17,534] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": []} +[2025-01-15 15:50:17,534] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "RYU"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "openflow-ryu-controller", "name": ""} +[2025-01-15 15:50:17,552] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}} +[2025-01-15 15:50:17,552] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,561] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": []} +[2025-01-15 15:50:17,562] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h2-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "h2"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": ""} +[2025-01-15 15:50:17,581] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h3-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": "h3"}]} +[2025-01-15 15:50:17,582] INFO:device.service.driver_api.DriverInstanceCache:Selecting driver for device(43be2984-467b-56da-a3e6-cfb6f1e8d978) with filter_fields({'device_type': 'emu-client', 'driver': [0]})... +[2025-01-15 15:50:17,582] INFO:device.service.driver_api.DriverInstanceCache:Driver(EmulatedDriver) selected for device(43be2984-467b-56da-a3e6-cfb6f1e8d978) with filter_fields({'device_type': 'emu-client', 'driver': [0]})... +[2025-01-15 15:50:17,583] DEBUG:tzlocal:/etc/timezone found, contents: + Etc/UTC + +[2025-01-15 15:50:17,584] DEBUG:tzlocal:/etc/localtime found +[2025-01-15 15:50:17,586] DEBUG:tzlocal:2 found: + {'/etc/timezone': 'Etc/UTC', '/etc/localtime is a symlink to': 'Etc/UTC'} +[2025-01-15 15:50:17,587] DEBUG:device.service.Tools:results_getconfig = [('/endpoints/endpoint[h3-eth0]', {'uuid': 'h3-eth0', 'type': 'copper/internal'}), ('/endpoints/endpoint[int]', {'uuid': 'int', 'type': 'copper/internal'})] +[2025-01-15 15:50:17,589] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h3-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[h3-eth0]", "resource_value": "{\"type\": \"copper/internal\", \"uuid\": \"h3-eth0\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[int]", "resource_value": "{\"type\": \"copper/internal\", \"uuid\": \"int\"}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}}, "endpoint_uuid": {"uuid": "h3-eth0"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": ""}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}}, "endpoint_uuid": {"uuid": "int"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": ""}], "device_id": {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "emu-client", "name": "h3"} +[2025-01-15 15:50:17,589] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}} +[2025-01-15 15:50:17,590] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,598] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}} +[2025-01-15 15:50:17,599] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,603] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h1-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": "h1"}]} +[2025-01-15 15:50:17,604] INFO:device.service.driver_api.DriverInstanceCache:Selecting driver for device(2a79cf95-9c1c-5588-83be-9533d4100b51) with filter_fields({'device_type': 'emu-client', 'driver': [0]})... +[2025-01-15 15:50:17,604] INFO:device.service.driver_api.DriverInstanceCache:Driver(EmulatedDriver) selected for device(2a79cf95-9c1c-5588-83be-9533d4100b51) with filter_fields({'device_type': 'emu-client', 'driver': [0]})... +[2025-01-15 15:50:17,605] DEBUG:device.service.Tools:results_getconfig = [('/endpoints/endpoint[h1-eth0]', {'uuid': 'h1-eth0', 'type': 'copper/internal'}), ('/endpoints/endpoint[int]', {'uuid': 'int', 'type': 'copper/internal'})] +[2025-01-15 15:50:17,607] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h1-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[h1-eth0]", "resource_value": "{\"type\": \"copper/internal\", \"uuid\": \"h1-eth0\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[int]", "resource_value": "{\"type\": \"copper/internal\", \"uuid\": \"int\"}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}}, "endpoint_uuid": {"uuid": "h1-eth0"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": ""}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}}, "endpoint_uuid": {"uuid": "int"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": ""}], "device_id": {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "emu-client", "name": "h1"} +[2025-01-15 15:50:17,618] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}} +[2025-01-15 15:50:17,618] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}}]}, "include_components": true, "include_config_rules": true, "include_endpoints": true} +[2025-01-15 15:50:17,640] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}} +[2025-01-15 15:50:17,641] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}}]}, "include_components": false, "include_config_rules": false, "include_endpoints": true} +[2025-01-15 15:50:17,641] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "openflow-ryu-controller", "name": "RYU"}]} +[2025-01-15 15:50:17,642] INFO:device.service.driver_api.DriverInstanceCache:Selecting driver for device(b2ed9526-554d-5a79-9dc9-33e00faecef1) with filter_fields({'device_type': 'openflow-ryu-controller', 'driver': [13]})... +[2025-01-15 15:50:17,642] INFO:device.service.driver_api.DriverInstanceCache:Driver(OpenFlowDriver) selected for device(b2ed9526-554d-5a79-9dc9-33e00faecef1) with filter_fields({'device_type': 'openflow-ryu-controller', 'driver': [13]})... +[2025-01-15 15:50:17,642] INFO:device.service.drivers.OpenFlow.TfsApiClient:self_devices_urlhttp://10.1.7.197:8080/v1.0/topology/switches +[2025-01-15 15:50:17,644] DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 10.1.7.197:8080 +[2025-01-15 15:50:17,647] DEBUG:urllib3.connectionpool:http://10.1.7.197:8080 "GET / HTTP/1.1" 200 306 +[2025-01-15 15:50:17,647] INFO:device.service.drivers.OpenFlow.OpenFlowDriver:resource_key:['__endpoints__'] +[2025-01-15 15:50:17,648] INFO:device.service.drivers.OpenFlow.OpenFlowDriver:resource_key:__endpoints__ +[2025-01-15 15:50:17,648] DEBUG:device.service.drivers.OpenFlow.TfsApiClient:[get_devices_endpoints] begin +[2025-01-15 15:50:17,649] DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 10.1.7.197:8080 +[2025-01-15 15:50:17,652] DEBUG:urllib3.connectionpool:http://10.1.7.197:8080 "GET /v1.0/topology/switches HTTP/1.1" 200 1661 +[2025-01-15 15:50:17,652] INFO:device.service.drivers.OpenFlow.TfsApiClient:[get_devices_endpoints] json_reply_switches=[{"dpid": "0000000000000001", "ports": [{"dpid": "0000000000000001", "port_no": "00000001", "hw_addr": "82:52:b9:9f:7d:b6", "name": "s1-eth1"}, {"dpid": "0000000000000001", "port_no": "00000002", "hw_addr": "be:1c:08:bc:fb:fa", "name": "s1-eth2"}]}, {"dpid": "0000000000000004", "ports": [{"dpid": "0000000000000004", "port_no": "00000001", "hw_addr": "52:32:f8:50:c5:77", "name": "s4-eth1"}, {"dpid": "0000000000000004", "port_no": "00000002", "hw_addr": "8a:bb:c9:b2:79:ba", "name": "s4-eth2"}]}, {"dpid": "0000000000000003", "ports": [{"dpid": "0000000000000003", "port_no": "00000001", "hw_addr": "46:0e:0d:04:58:28", "name": "s3-eth1"}, {"dpid": "0000000000000003", "port_no": "00000002", "hw_addr": "02:bb:8c:18:e0:24", "name": "s3-eth2"}]}, {"dpid": "0000000000000002", "ports": [{"dpid": "0000000000000002", "port_no": "00000001", "hw_addr": "6e:b4:7e:ea:22:2a", "name": "s2-eth1"}, {"dpid": "0000000000000002", "port_no": "00000004", "hw_addr": "ea:43:e4:a5:2c:7f", "name": "s2-eth4"}, {"dpid": "0000000000000002", "port_no": "00000002", "hw_addr": "da:d2:dd:5f:e0:9e", "name": "s2-eth2"}, {"dpid": "0000000000000002", "port_no": "00000003", "hw_addr": "d6:9e:c2:9f:2b:e2", "name": "s2-eth3"}]}, {"dpid": "0000000000000005", "ports": [{"dpid": "0000000000000005", "port_no": "00000004", "hw_addr": "b2:3b:fa:f9:89:91", "name": "s5-eth4"}, {"dpid": "0000000000000005", "port_no": "00000001", "hw_addr": "66:be:8c:28:47:67", "name": "s5-eth1"}, {"dpid": "0000000000000005", "port_no": "00000002", "hw_addr": "62:86:c3:2e:09:c0", "name": "s5-eth2"}, {"dpid": "0000000000000005", "port_no": "00000003", "hw_addr": "0e:b5:83:92:2d:2e", "name": "s5-eth3"}]}] +[2025-01-15 15:50:17,654] DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 10.1.7.197:8080 +[2025-01-15 15:50:17,656] DEBUG:urllib3.connectionpool:http://10.1.7.197:8080 "GET /v1.0/topology/links HTTP/1.1" 200 2240 +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000003', 's3-eth2'), ('0000000000000004', 's4-eth1')] +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000004', 's4-eth1'), ('0000000000000003', 's3-eth2')] +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000005', 's5-eth1'), ('0000000000000004', 's4-eth2')] +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000005', 's5-eth2'), ('0000000000000001', 's1-eth2')] +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000002', 's2-eth2'), ('0000000000000003', 's3-eth1')] +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000002', 's2-eth1'), ('0000000000000001', 's1-eth1')] +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000001', 's1-eth1'), ('0000000000000002', 's2-eth1')] +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000003', 's3-eth1'), ('0000000000000002', 's2-eth2')] +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000001', 's1-eth2'), ('0000000000000005', 's5-eth2')] +[2025-01-15 15:50:17,657] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000004', 's4-eth2'), ('0000000000000005', 's5-eth1')] +[2025-01-15 15:50:17,657] DEBUG:device.service.drivers.OpenFlow.TfsApiClient:[get_devices_endpoints] topology; returning +[2025-01-15 15:50:17,658] DEBUG:device.service.Tools:results_getconfig = [('/devices/device[0000000000000001]', {'uuid': '0000000000000001', 'name': '0000000000000001', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000001]', {'uuid': '0000000000000001', 'name': '0000000000000001', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000004]', {'uuid': '0000000000000004', 'name': '0000000000000004', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000004]', {'uuid': '0000000000000004', 'name': '0000000000000004', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000003]', {'uuid': '0000000000000003', 'name': '0000000000000003', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000003]', {'uuid': '0000000000000003', 'name': '0000000000000003', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000002]', {'uuid': '0000000000000002', 'name': '0000000000000002', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000002]', {'uuid': '0000000000000002', 'name': '0000000000000002', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000002]', {'uuid': '0000000000000002', 'name': '0000000000000002', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000002]', {'uuid': '0000000000000002', 'name': '0000000000000002', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000005]', {'uuid': '0000000000000005', 'name': '0000000000000005', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000005]', {'uuid': '0000000000000005', 'name': '0000000000000005', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000005]', {'uuid': '0000000000000005', 'name': '0000000000000005', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/devices/device[0000000000000005]', {'uuid': '0000000000000005', 'name': '0000000000000005', 'type': 'packet-switch', 'status': 2, 'drivers': 'DEVICEDRIVER_RYU'}), ('/endpoints/endpoint[s1-eth1]', {'device_uuid': '0000000000000001', 'uuid': 's1-eth1', 'name': 's1-eth1', 'type': 'copper'}), ('/endpoints/endpoint[s1-eth2]', {'device_uuid': '0000000000000001', 'uuid': 's1-eth2', 'name': 's1-eth2', 'type': 'copper'}), ('/endpoints/endpoint[s4-eth1]', {'device_uuid': '0000000000000004', 'uuid': 's4-eth1', 'name': 's4-eth1', 'type': 'copper'}), ('/endpoints/endpoint[s4-eth2]', {'device_uuid': '0000000000000004', 'uuid': 's4-eth2', 'name': 's4-eth2', 'type': 'copper'}), ('/endpoints/endpoint[s3-eth1]', {'device_uuid': '0000000000000003', 'uuid': 's3-eth1', 'name': 's3-eth1', 'type': 'copper'}), ('/endpoints/endpoint[s3-eth2]', {'device_uuid': '0000000000000003', 'uuid': 's3-eth2', 'name': 's3-eth2', 'type': 'copper'}), ('/endpoints/endpoint[s2-eth1]', {'device_uuid': '0000000000000002', 'uuid': 's2-eth1', 'name': 's2-eth1', 'type': 'copper'}), ('/endpoints/endpoint[s2-eth4]', {'device_uuid': '0000000000000002', 'uuid': 's2-eth4', 'name': 's2-eth4', 'type': 'copper'}), ('/endpoints/endpoint[s2-eth2]', {'device_uuid': '0000000000000002', 'uuid': 's2-eth2', 'name': 's2-eth2', 'type': 'copper'}), ('/endpoints/endpoint[s2-eth3]', {'device_uuid': '0000000000000002', 'uuid': 's2-eth3', 'name': 's2-eth3', 'type': 'copper'}), ('/endpoints/endpoint[s5-eth4]', {'device_uuid': '0000000000000005', 'uuid': 's5-eth4', 'name': 's5-eth4', 'type': 'copper'}), ('/endpoints/endpoint[s5-eth1]', {'device_uuid': '0000000000000005', 'uuid': 's5-eth1', 'name': 's5-eth1', 'type': 'copper'}), ('/endpoints/endpoint[s5-eth2]', {'device_uuid': '0000000000000005', 'uuid': 's5-eth2', 'name': 's5-eth2', 'type': 'copper'}), ('/endpoints/endpoint[s5-eth3]', {'device_uuid': '0000000000000005', 'uuid': 's5-eth3', 'name': 's5-eth3', 'type': 'copper'}), ('/links/link[s3-eth2==s4-eth1]', {'uuid': 's3-eth2==s4-eth1', 'name': '0000000000000003-s3-eth2===0000000000000004-s4-eth1', 'endpoints': [('0000000000000003', 's3-eth2'), ('0000000000000004', 's4-eth1')]}), ('/links/link[s4-eth1==s3-eth2]', {'uuid': 's4-eth1==s3-eth2', 'name': '0000000000000004-s4-eth1===0000000000000003-s3-eth2', 'endpoints': [('0000000000000004', 's4-eth1'), ('0000000000000003', 's3-eth2')]}), ('/links/link[s5-eth1==s4-eth2]', {'uuid': 's5-eth1==s4-eth2', 'name': '0000000000000005-s5-eth1===0000000000000004-s4-eth2', 'endpoints': [('0000000000000005', 's5-eth1'), ('0000000000000004', 's4-eth2')]}), ('/links/link[s5-eth2==s1-eth2]', {'uuid': 's5-eth2==s1-eth2', 'name': '0000000000000005-s5-eth2===0000000000000001-s1-eth2', 'endpoints': [('0000000000000005', 's5-eth2'), ('0000000000000001', 's1-eth2')]}), ('/links/link[s2-eth2==s3-eth1]', {'uuid': 's2-eth2==s3-eth1', 'name': '0000000000000002-s2-eth2===0000000000000003-s3-eth1', 'endpoints': [('0000000000000002', 's2-eth2'), ('0000000000000003', 's3-eth1')]}), ('/links/link[s2-eth1==s1-eth1]', {'uuid': 's2-eth1==s1-eth1', 'name': '0000000000000002-s2-eth1===0000000000000001-s1-eth1', 'endpoints': [('0000000000000002', 's2-eth1'), ('0000000000000001', 's1-eth1')]}), ('/links/link[s1-eth1==s2-eth1]', {'uuid': 's1-eth1==s2-eth1', 'name': '0000000000000001-s1-eth1===0000000000000002-s2-eth1', 'endpoints': [('0000000000000001', 's1-eth1'), ('0000000000000002', 's2-eth1')]}), ('/links/link[s3-eth1==s2-eth2]', {'uuid': 's3-eth1==s2-eth2', 'name': '0000000000000003-s3-eth1===0000000000000002-s2-eth2', 'endpoints': [('0000000000000003', 's3-eth1'), ('0000000000000002', 's2-eth2')]}), ('/links/link[s1-eth2==s5-eth2]', {'uuid': 's1-eth2==s5-eth2', 'name': '0000000000000001-s1-eth2===0000000000000005-s5-eth2', 'endpoints': [('0000000000000001', 's1-eth2'), ('0000000000000005', 's5-eth2')]}), ('/links/link[s4-eth2==s5-eth1]', {'uuid': 's4-eth2==s5-eth1', 'name': '0000000000000004-s4-eth2===0000000000000005-s5-eth1', 'endpoints': [('0000000000000004', 's4-eth2'), ('0000000000000005', 's5-eth1')]})] +[2025-01-15 15:50:17,660] INFO:device.service.drivers.OpenFlow.OpenFlowDriver:resource_key:['__endpoints__'] +[2025-01-15 15:50:17,660] INFO:device.service.drivers.OpenFlow.OpenFlowDriver:resource_key:__endpoints__ +[2025-01-15 15:50:17,660] DEBUG:device.service.drivers.OpenFlow.TfsApiClient:[get_devices_endpoints] begin +[2025-01-15 15:50:17,661] DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 10.1.7.197:8080 +[2025-01-15 15:50:17,663] DEBUG:urllib3.connectionpool:http://10.1.7.197:8080 "GET /v1.0/topology/switches HTTP/1.1" 200 1661 +[2025-01-15 15:50:17,664] INFO:device.service.drivers.OpenFlow.TfsApiClient:[get_devices_endpoints] json_reply_switches=[{"dpid": "0000000000000001", "ports": [{"dpid": "0000000000000001", "port_no": "00000001", "hw_addr": "82:52:b9:9f:7d:b6", "name": "s1-eth1"}, {"dpid": "0000000000000001", "port_no": "00000002", "hw_addr": "be:1c:08:bc:fb:fa", "name": "s1-eth2"}]}, {"dpid": "0000000000000004", "ports": [{"dpid": "0000000000000004", "port_no": "00000001", "hw_addr": "52:32:f8:50:c5:77", "name": "s4-eth1"}, {"dpid": "0000000000000004", "port_no": "00000002", "hw_addr": "8a:bb:c9:b2:79:ba", "name": "s4-eth2"}]}, {"dpid": "0000000000000003", "ports": [{"dpid": "0000000000000003", "port_no": "00000001", "hw_addr": "46:0e:0d:04:58:28", "name": "s3-eth1"}, {"dpid": "0000000000000003", "port_no": "00000002", "hw_addr": "02:bb:8c:18:e0:24", "name": "s3-eth2"}]}, {"dpid": "0000000000000002", "ports": [{"dpid": "0000000000000002", "port_no": "00000001", "hw_addr": "6e:b4:7e:ea:22:2a", "name": "s2-eth1"}, {"dpid": "0000000000000002", "port_no": "00000004", "hw_addr": "ea:43:e4:a5:2c:7f", "name": "s2-eth4"}, {"dpid": "0000000000000002", "port_no": "00000002", "hw_addr": "da:d2:dd:5f:e0:9e", "name": "s2-eth2"}, {"dpid": "0000000000000002", "port_no": "00000003", "hw_addr": "d6:9e:c2:9f:2b:e2", "name": "s2-eth3"}]}, {"dpid": "0000000000000005", "ports": [{"dpid": "0000000000000005", "port_no": "00000004", "hw_addr": "b2:3b:fa:f9:89:91", "name": "s5-eth4"}, {"dpid": "0000000000000005", "port_no": "00000001", "hw_addr": "66:be:8c:28:47:67", "name": "s5-eth1"}, {"dpid": "0000000000000005", "port_no": "00000002", "hw_addr": "62:86:c3:2e:09:c0", "name": "s5-eth2"}, {"dpid": "0000000000000005", "port_no": "00000003", "hw_addr": "0e:b5:83:92:2d:2e", "name": "s5-eth3"}]}] +[2025-01-15 15:50:17,666] DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 10.1.7.197:8080 +[2025-01-15 15:50:17,667] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}} +[2025-01-15 15:50:17,667] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}}]}, "include_components": false, "include_config_rules": false, "include_endpoints": true} +[2025-01-15 15:50:17,668] DEBUG:urllib3.connectionpool:http://10.1.7.197:8080 "GET /v1.0/topology/links HTTP/1.1" 200 2240 +[2025-01-15 15:50:17,669] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000003', 's3-eth2'), ('0000000000000004', 's4-eth1')] +[2025-01-15 15:50:17,669] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000004', 's4-eth1'), ('0000000000000003', 's3-eth2')] +[2025-01-15 15:50:17,669] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000005', 's5-eth1'), ('0000000000000004', 's4-eth2')] +[2025-01-15 15:50:17,669] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000005', 's5-eth2'), ('0000000000000001', 's1-eth2')] +[2025-01-15 15:50:17,669] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000002', 's2-eth2'), ('0000000000000003', 's3-eth1')] +[2025-01-15 15:50:17,669] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000002', 's2-eth1'), ('0000000000000001', 's1-eth1')] +[2025-01-15 15:50:17,669] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000001', 's1-eth1'), ('0000000000000002', 's2-eth1')] +[2025-01-15 15:50:17,669] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000003', 's3-eth1'), ('0000000000000002', 's2-eth2')] +[2025-01-15 15:50:17,669] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000001', 's1-eth2'), ('0000000000000005', 's5-eth2')] +[2025-01-15 15:50:17,670] INFO:device.service.drivers.OpenFlow.TfsApiClient:link_endpoint_ids are [('0000000000000004', 's4-eth2'), ('0000000000000005', 's5-eth1')] +[2025-01-15 15:50:17,670] DEBUG:device.service.drivers.OpenFlow.TfsApiClient:[get_devices_endpoints] topology; returning +[2025-01-15 15:50:17,675] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"} +[2025-01-15 15:50:17,676] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h4-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": "h4"}]} +[2025-01-15 15:50:17,676] INFO:device.service.driver_api.DriverInstanceCache:Selecting driver for device(c929235b-c0bd-5016-9e63-e7eaafaaa792) with filter_fields({'device_type': 'emu-client', 'driver': [0]})... +[2025-01-15 15:50:17,676] INFO:device.service.driver_api.DriverInstanceCache:Driver(EmulatedDriver) selected for device(c929235b-c0bd-5016-9e63-e7eaafaaa792) with filter_fields({'device_type': 'emu-client', 'driver': [0]})... +[2025-01-15 15:50:17,678] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h2-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_UNDEFINED", "device_type": "emu-client", "name": "h2"}]} +[2025-01-15 15:50:17,678] INFO:device.service.driver_api.DriverInstanceCache:Selecting driver for device(53ad149d-c690-52ea-aba9-66a7fd5dbd85) with filter_fields({'device_type': 'emu-client', 'driver': [0]})... +[2025-01-15 15:50:17,678] INFO:device.service.driver_api.DriverInstanceCache:Driver(EmulatedDriver) selected for device(53ad149d-c690-52ea-aba9-66a7fd5dbd85) with filter_fields({'device_type': 'emu-client', 'driver': [0]})... +[2025-01-15 15:50:17,679] DEBUG:device.service.Tools:results_getconfig = [('/endpoints/endpoint[h4-eth0]', {'uuid': 'h4-eth0', 'type': 'copper/internal'}), ('/endpoints/endpoint[int]', {'uuid': 'int', 'type': 'copper/internal'})] +[2025-01-15 15:50:17,680] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h4-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[h4-eth0]", "resource_value": "{\"type\": \"copper/internal\", \"uuid\": \"h4-eth0\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[int]", "resource_value": "{\"type\": \"copper/internal\", \"uuid\": \"int\"}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}}, "endpoint_uuid": {"uuid": "h4-eth0"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": ""}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}}, "endpoint_uuid": {"uuid": "int"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": ""}], "device_id": {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "emu-client", "name": "h4"} +[2025-01-15 15:50:17,681] DEBUG:device.service.Tools:results_getconfig = [('/endpoints/endpoint[h2-eth0]', {'uuid': 'h2-eth0', 'type': 'copper/internal'}), ('/endpoints/endpoint[int]', {'uuid': 'int', 'type': 'copper/internal'})] +[2025-01-15 15:50:17,681] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"endpoints\": [\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"h2-eth0\"\n},\n{\n\"type\": \"copper/internal\",\n\"uuid\": \"int\"\n}\n]\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[h2-eth0]", "resource_value": "{\"type\": \"copper/internal\", \"uuid\": \"h2-eth0\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[int]", "resource_value": "{\"type\": \"copper/internal\", \"uuid\": \"int\"}"}}]}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}}, "endpoint_uuid": {"uuid": "h2-eth0"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": ""}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}}, "endpoint_uuid": {"uuid": "int"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": ""}], "device_id": {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "emu-client", "name": "h2"} +[2025-01-15 15:50:17,690] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}}, "endpoint_uuid": {"uuid": "894f1db9-682b-534b-9e3e-1086e5435058"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": "h3-eth0"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}}, "endpoint_uuid": {"uuid": "b8fe51a0-91f7-5203-b571-87ef53e2ca2d"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": "int"}], "device_id": {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "emu-client", "name": "h3"}]} +[2025-01-15 15:50:17,694] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice reply: {"device_uuid": {"uuid": "43be2984-467b-56da-a3e6-cfb6f1e8d978"}} +[2025-01-15 15:50:17,725] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}}, "endpoint_uuid": {"uuid": "1b3b2793-64b2-57e3-88bb-8ce89c413e16"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": "int"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}}, "endpoint_uuid": {"uuid": "c9788b13-30ad-581c-a04d-7191d4e7cbd1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": "h1-eth0"}], "device_id": {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "emu-client", "name": "h1"}]} +[2025-01-15 15:50:17,726] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice reply: {"device_uuid": {"uuid": "2a79cf95-9c1c-5588-83be-9533d4100b51"}} +[2025-01-15 15:50:17,740] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}} +[2025-01-15 15:50:17,741] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_drivers": [], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000001"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000001"}}, "endpoint_uuid": {"uuid": "s1-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s1-eth1"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000001"}}, "endpoint_uuid": {"uuid": "s1-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s1-eth2"}], "device_id": {"device_uuid": {"uuid": "0000000000000001"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "packet-switch", "name": "0000000000000001"} +[2025-01-15 15:50:17,742] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}} +[2025-01-15 15:50:17,742] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}}]}, "include_components": false, "include_config_rules": false, "include_endpoints": true} +[2025-01-15 15:50:17,758] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}} +[2025-01-15 15:50:17,758] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}}]}, "include_components": false, "include_config_rules": false, "include_endpoints": true} +[2025-01-15 15:50:17,780] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}}, "endpoint_uuid": {"uuid": "0d195f1f-6876-5fbd-bb6e-58b0e645ca1f"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": "int"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}}, "endpoint_uuid": {"uuid": "a2efb85b-c007-5419-ad52-3a5729f0da71"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": "h4-eth0"}], "device_id": {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "emu-client", "name": "h4"}]} +[2025-01-15 15:50:17,780] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice reply: {"device_uuid": {"uuid": "c929235b-c0bd-5016-9e63-e7eaafaaa792"}} +[2025-01-15 15:50:17,782] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "995a62fc-2b2f-5d35-a0bb-c5a7dd22e892"}} +[2025-01-15 15:50:17,782] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_drivers": [], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000004"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000004"}}, "endpoint_uuid": {"uuid": "s4-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s4-eth1"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000004"}}, "endpoint_uuid": {"uuid": "s4-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s4-eth2"}], "device_id": {"device_uuid": {"uuid": "0000000000000004"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "packet-switch", "name": "0000000000000004"} +[2025-01-15 15:50:17,791] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}}, "endpoint_uuid": {"uuid": "20cb95be-f52f-5615-a349-18b893d59c9d"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": "int"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}}, "endpoint_uuid": {"uuid": "ad8b1d58-1a1e-56db-9b29-3cc111845804"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "copper/internal", "kpi_sample_types": [], "name": "h2-eth0"}], "device_id": {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "emu-client", "name": "h2"}]} +[2025-01-15 15:50:17,792] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice reply: {"device_uuid": {"uuid": "53ad149d-c690-52ea-aba9-66a7fd5dbd85"}} +[2025-01-15 15:50:17,808] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "c38fb93c-9578-5d7f-a081-a2db4b5f468c"}} +[2025-01-15 15:50:17,809] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_drivers": [], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000003"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000003"}}, "endpoint_uuid": {"uuid": "s3-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s3-eth1"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000003"}}, "endpoint_uuid": {"uuid": "s3-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s3-eth2"}], "device_id": {"device_uuid": {"uuid": "0000000000000003"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "packet-switch", "name": "0000000000000003"} +[2025-01-15 15:50:17,833] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "0bdaca38-0541-5d36-b58b-f828943dc213"}} +[2025-01-15 15:50:17,833] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_drivers": [], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "s2-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s2-eth1"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "s2-eth4"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s2-eth4"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "s2-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s2-eth2"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "s2-eth3"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s2-eth3"}], "device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "packet-switch", "name": "0000000000000002"} +[2025-01-15 15:50:17,862] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "a2f2519b-3c76-5f1e-99c7-cc2bbf815eec"}} +[2025-01-15 15:50:17,862] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_drivers": [], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "s5-eth4"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s5-eth4"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "s5-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s5-eth1"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "s5-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s5-eth2"}, {"endpoint_id": {"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "s5-eth3"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, "endpoint_type": "copper", "kpi_sample_types": [], "name": "s5-eth3"}], "device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "packet-switch", "name": "0000000000000005"} +[2025-01-15 15:50:17,888] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "b52aaf41-0c5a-55f2-a66e-eb42c1153a96"}} +[2025-01-15 15:50:17,888] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000001"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "RYU/mgmt==0000000000000001/mgmt"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "RYU/mgmt==0000000000000001/mgmt"} +[2025-01-15 15:50:17,929] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "a6ad0bf0-955e-5a3e-be3f-b161562ee922"}} +[2025-01-15 15:50:17,929] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000004"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "RYU/mgmt==0000000000000004/mgmt"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "RYU/mgmt==0000000000000004/mgmt"} +[2025-01-15 15:50:17,946] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "f732a34b-3b58-5208-972d-ead200e217a2"}} +[2025-01-15 15:50:17,947] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000003"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "RYU/mgmt==0000000000000003/mgmt"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "RYU/mgmt==0000000000000003/mgmt"} +[2025-01-15 15:50:17,964] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "9c27e1ef-2de9-5d4a-a39b-d986bc46e6ff"}} +[2025-01-15 15:50:17,964] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "RYU/mgmt==0000000000000002/mgmt"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "RYU/mgmt==0000000000000002/mgmt"} +[2025-01-15 15:50:17,982] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "23163f66-d373-53c7-87b9-a19332d499f9"}} +[2025-01-15 15:50:17,983] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "mgmt"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "RYU/mgmt==0000000000000005/mgmt"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "RYU/mgmt==0000000000000005/mgmt"} +[2025-01-15 15:50:17,999] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "035237df-d927-5831-9ca0-3e817f20b775"}} +[2025-01-15 15:50:17,999] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000003"}}, "endpoint_uuid": {"uuid": "s3-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000004"}}, "endpoint_uuid": {"uuid": "s4-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s3-eth2==s4-eth1"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000003-s3-eth2===0000000000000004-s4-eth1"} +[2025-01-15 15:50:18,014] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "beee85c4-62a0-5b24-87c0-dff4090b8b0f"}} +[2025-01-15 15:50:18,015] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000004"}}, "endpoint_uuid": {"uuid": "s4-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000003"}}, "endpoint_uuid": {"uuid": "s3-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s4-eth1==s3-eth2"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000004-s4-eth1===0000000000000003-s3-eth2"} +[2025-01-15 15:50:18,054] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "19aa0a16-b510-5efe-9c3d-8c4605319a74"}} +[2025-01-15 15:50:18,054] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "s5-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000004"}}, "endpoint_uuid": {"uuid": "s4-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s5-eth1==s4-eth2"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000005-s5-eth1===0000000000000004-s4-eth2"} +[2025-01-15 15:50:18,070] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "327c4898-85a4-5f42-912d-2c60c04fa650"}} +[2025-01-15 15:50:18,071] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "s5-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000001"}}, "endpoint_uuid": {"uuid": "s1-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s5-eth2==s1-eth2"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000005-s5-eth2===0000000000000001-s1-eth2"} +[2025-01-15 15:50:18,086] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "646fad23-eeee-5261-aa56-dcb6bd69ef9d"}} +[2025-01-15 15:50:18,087] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "s2-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000003"}}, "endpoint_uuid": {"uuid": "s3-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s2-eth2==s3-eth1"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000002-s2-eth2===0000000000000003-s3-eth1"} +[2025-01-15 15:50:18,102] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "b28d7bf0-19d3-5b94-b8c2-88f6dca8cd25"}} +[2025-01-15 15:50:18,103] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "s2-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000001"}}, "endpoint_uuid": {"uuid": "s1-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s2-eth1==s1-eth1"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000002-s2-eth1===0000000000000001-s1-eth1"} +[2025-01-15 15:50:18,118] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "3dcd7c7c-fd54-5599-b0cc-235806ee5b6f"}} +[2025-01-15 15:50:18,119] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000001"}}, "endpoint_uuid": {"uuid": "s1-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "s2-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s1-eth1==s2-eth1"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000001-s1-eth1===0000000000000002-s2-eth1"} +[2025-01-15 15:50:18,136] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "d0890789-62ad-5f5f-815b-786c1976c567"}} +[2025-01-15 15:50:18,136] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000003"}}, "endpoint_uuid": {"uuid": "s3-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000002"}}, "endpoint_uuid": {"uuid": "s2-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s3-eth1==s2-eth2"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000003-s3-eth1===0000000000000002-s2-eth2"} +[2025-01-15 15:50:18,153] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "509740ba-cd2c-59aa-8843-4cf8e278fc5d"}} +[2025-01-15 15:50:18,154] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000001"}}, "endpoint_uuid": {"uuid": "s1-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "s5-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s1-eth2==s5-eth2"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000001-s1-eth2===0000000000000005-s5-eth2"} +[2025-01-15 15:50:18,169] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "0f1c88d1-1b46-5e79-88a1-b0a5d2e28324"}} +[2025-01-15 15:50:18,170] DEBUG:context.client.ContextClient:SetLink request: {"link_endpoint_ids": [{"device_id": {"device_uuid": {"uuid": "0000000000000004"}}, "endpoint_uuid": {"uuid": "s4-eth2"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}, {"device_id": {"device_uuid": {"uuid": "0000000000000005"}}, "endpoint_uuid": {"uuid": "s5-eth1"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}], "link_id": {"link_uuid": {"uuid": "s4-eth2==s5-eth1"}}, "link_type": "LINKTYPE_UNKNOWN", "name": "0000000000000004-s4-eth2===0000000000000005-s5-eth1"} +[2025-01-15 15:50:18,186] DEBUG:context.client.ContextClient:SetLink result: {"link_uuid": {"uuid": "b7f8ba02-fe4c-5c3b-9346-740a69da5394"}} +[2025-01-15 15:50:18,187] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}]}, "include_components": false, "include_config_rules": false, "include_endpoints": true} +[2025-01-15 15:50:18,197] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "158268b6-968b-582a-968d-da4b922ebc1c"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"}]} +[2025-01-15 15:50:18,199] DEBUG:device.service.DeviceServiceServicerImpl:AddDevice reply: {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}} +[2025-01-15 15:50:25,412] DEBUG:device.service.DeviceServiceServicerImpl:ConfigureDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s2]/flow[h1-h3]", "resource_value": "{\"dpid\": \"0000000000000002\", \"in-port\": \"s2-eth3\", \"out-port\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s2]/flow[h3-h1]", "resource_value": "{\"dpid\": \"0000000000000002\", \"in-port\": \"s2-eth1\", \"out-port\": \"s2-eth3\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "158268b6-968b-582a-968d-da4b922ebc1c"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"} +[2025-01-15 15:50:25,412] DEBUG:context.client.ContextClient:Creating channel to 10.152.183.206:1010... +[2025-01-15 15:50:25,412] DEBUG:context.client.ContextClient:Channel created +[2025-01-15 15:50:25,413] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}]}, "include_components": false, "include_config_rules": true, "include_endpoints": false} +[2025-01-15 15:50:25,424] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"}]} +[2025-01-15 15:50:25,425] INFO:device.service.drivers.OpenFlow.OpenFlowDriver:SetConfig_resources:[('_connect/address', '10.1.7.197'), ('_connect/port', '8080'), ('_connect/settings', '{\n"timeout": 120\n}'), ('/devices/device[0000000000000001]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000001", "status": 2, "type": "packet-switch", "uuid": "0000000000000001"}'), ('/devices/device[0000000000000004]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000004", "status": 2, "type": "packet-switch", "uuid": "0000000000000004"}'), ('/devices/device[0000000000000003]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000003", "status": 2, "type": "packet-switch", "uuid": "0000000000000003"}'), ('/devices/device[0000000000000002]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000002", "status": 2, "type": "packet-switch", "uuid": "0000000000000002"}'), ('/devices/device[0000000000000005]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000005", "status": 2, "type": "packet-switch", "uuid": "0000000000000005"}'), ('/endpoints/endpoint[s1-eth1]', '{"device_uuid": "0000000000000001", "name": "s1-eth1", "type": "copper", "uuid": "s1-eth1"}'), ('/endpoints/endpoint[s1-eth2]', '{"device_uuid": "0000000000000001", "name": "s1-eth2", "type": "copper", "uuid": "s1-eth2"}'), ('/endpoints/endpoint[s4-eth1]', '{"device_uuid": "0000000000000004", "name": "s4-eth1", "type": "copper", "uuid": "s4-eth1"}'), ('/endpoints/endpoint[s4-eth2]', '{"device_uuid": "0000000000000004", "name": "s4-eth2", "type": "copper", "uuid": "s4-eth2"}'), ('/endpoints/endpoint[s3-eth1]', '{"device_uuid": "0000000000000003", "name": "s3-eth1", "type": "copper", "uuid": "s3-eth1"}'), ('/endpoints/endpoint[s3-eth2]', '{"device_uuid": "0000000000000003", "name": "s3-eth2", "type": "copper", "uuid": "s3-eth2"}'), ('/endpoints/endpoint[s2-eth1]', '{"device_uuid": "0000000000000002", "name": "s2-eth1", "type": "copper", "uuid": "s2-eth1"}'), ('/endpoints/endpoint[s2-eth4]', '{"device_uuid": "0000000000000002", "name": "s2-eth4", "type": "copper", "uuid": "s2-eth4"}'), ('/endpoints/endpoint[s2-eth2]', '{"device_uuid": "0000000000000002", "name": "s2-eth2", "type": "copper", "uuid": "s2-eth2"}'), ('/endpoints/endpoint[s2-eth3]', '{"device_uuid": "0000000000000002", "name": "s2-eth3", "type": "copper", "uuid": "s2-eth3"}'), ('/endpoints/endpoint[s5-eth4]', '{"device_uuid": "0000000000000005", "name": "s5-eth4", "type": "copper", "uuid": "s5-eth4"}'), ('/endpoints/endpoint[s5-eth1]', '{"device_uuid": "0000000000000005", "name": "s5-eth1", "type": "copper", "uuid": "s5-eth1"}'), ('/endpoints/endpoint[s5-eth2]', '{"device_uuid": "0000000000000005", "name": "s5-eth2", "type": "copper", "uuid": "s5-eth2"}'), ('/endpoints/endpoint[s5-eth3]', '{"device_uuid": "0000000000000005", "name": "s5-eth3", "type": "copper", "uuid": "s5-eth3"}'), ('/links/link[s3-eth2==s4-eth1]', '{"endpoints": [["0000000000000003", "s3-eth2"], ["0000000000000004", "s4-eth1"]], "name": "0000000000000003-s3-eth2===0000000000000004-s4-eth1", "uuid": "s3-eth2==s4-eth1"}'), ('/links/link[s4-eth1==s3-eth2]', '{"endpoints": [["0000000000000004", "s4-eth1"], ["0000000000000003", "s3-eth2"]], "name": "0000000000000004-s4-eth1===0000000000000003-s3-eth2", "uuid": "s4-eth1==s3-eth2"}'), ('/links/link[s5-eth1==s4-eth2]', '{"endpoints": [["0000000000000005", "s5-eth1"], ["0000000000000004", "s4-eth2"]], "name": "0000000000000005-s5-eth1===0000000000000004-s4-eth2", "uuid": "s5-eth1==s4-eth2"}'), ('/links/link[s5-eth2==s1-eth2]', '{"endpoints": [["0000000000000005", "s5-eth2"], ["0000000000000001", "s1-eth2"]], "name": "0000000000000005-s5-eth2===0000000000000001-s1-eth2", "uuid": "s5-eth2==s1-eth2"}'), ('/links/link[s2-eth2==s3-eth1]', '{"endpoints": [["0000000000000002", "s2-eth2"], ["0000000000000003", "s3-eth1"]], "name": "0000000000000002-s2-eth2===0000000000000003-s3-eth1", "uuid": "s2-eth2==s3-eth1"}'), ('/links/link[s2-eth1==s1-eth1]', '{"endpoints": [["0000000000000002", "s2-eth1"], ["0000000000000001", "s1-eth1"]], "name": "0000000000000002-s2-eth1===0000000000000001-s1-eth1", "uuid": "s2-eth1==s1-eth1"}'), ('/links/link[s1-eth1==s2-eth1]', '{"endpoints": [["0000000000000001", "s1-eth1"], ["0000000000000002", "s2-eth1"]], "name": "0000000000000001-s1-eth1===0000000000000002-s2-eth1", "uuid": "s1-eth1==s2-eth1"}'), ('/links/link[s3-eth1==s2-eth2]', '{"endpoints": [["0000000000000003", "s3-eth1"], ["0000000000000002", "s2-eth2"]], "name": "0000000000000003-s3-eth1===0000000000000002-s2-eth2", "uuid": "s3-eth1==s2-eth2"}'), ('/links/link[s1-eth2==s5-eth2]', '{"endpoints": [["0000000000000001", "s1-eth2"], ["0000000000000005", "s5-eth2"]], "name": "0000000000000001-s1-eth2===0000000000000005-s5-eth2", "uuid": "s1-eth2==s5-eth2"}'), ('/links/link[s4-eth2==s5-eth1]', '{"endpoints": [["0000000000000004", "s4-eth2"], ["0000000000000005", "s5-eth1"]], "name": "0000000000000004-s4-eth2===0000000000000005-s5-eth1", "uuid": "s4-eth2==s5-eth1"}')] +[2025-01-15 15:50:25,425] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"} +[2025-01-15 15:50:25,459] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}} +[2025-01-15 15:50:25,460] DEBUG:device.service.DeviceServiceServicerImpl:ConfigureDevice reply: {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}} +[2025-01-15 15:50:25,463] DEBUG:device.service.DeviceServiceServicerImpl:ConfigureDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s2]/flow[h1-h3]", "resource_value": "{\"dpid\": \"0000000000000002\", \"in-port\": \"s2-eth3\", \"out-port\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s2]/flow[h3-h1]", "resource_value": "{\"dpid\": \"0000000000000002\", \"in-port\": \"s2-eth1\", \"out-port\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s1]/flow[h1-h3]", "resource_value": "{\"dpid\": \"0000000000000001\", \"in-port\": \"s1-eth1\", \"out-port\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s1]/flow[h3-h1]", "resource_value": "{\"dpid\": \"0000000000000001\", \"in-port\": \"s1-eth2\", \"out-port\": \"s1-eth1\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "158268b6-968b-582a-968d-da4b922ebc1c"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"} +[2025-01-15 15:50:25,463] DEBUG:context.client.ContextClient:Creating channel to 10.152.183.206:1010... +[2025-01-15 15:50:25,464] DEBUG:context.client.ContextClient:Channel created +[2025-01-15 15:50:25,464] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}]}, "include_components": false, "include_config_rules": true, "include_endpoints": false} +[2025-01-15 15:50:25,473] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"}]} +[2025-01-15 15:50:25,474] INFO:device.service.drivers.OpenFlow.OpenFlowDriver:SetConfig_resources:[('_connect/address', '10.1.7.197'), ('_connect/port', '8080'), ('_connect/settings', '{\n"timeout": 120\n}'), ('/devices/device[0000000000000001]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000001", "status": 2, "type": "packet-switch", "uuid": "0000000000000001"}'), ('/devices/device[0000000000000004]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000004", "status": 2, "type": "packet-switch", "uuid": "0000000000000004"}'), ('/devices/device[0000000000000003]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000003", "status": 2, "type": "packet-switch", "uuid": "0000000000000003"}'), ('/devices/device[0000000000000002]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000002", "status": 2, "type": "packet-switch", "uuid": "0000000000000002"}'), ('/devices/device[0000000000000005]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000005", "status": 2, "type": "packet-switch", "uuid": "0000000000000005"}'), ('/endpoints/endpoint[s1-eth1]', '{"device_uuid": "0000000000000001", "name": "s1-eth1", "type": "copper", "uuid": "s1-eth1"}'), ('/endpoints/endpoint[s1-eth2]', '{"device_uuid": "0000000000000001", "name": "s1-eth2", "type": "copper", "uuid": "s1-eth2"}'), ('/endpoints/endpoint[s4-eth1]', '{"device_uuid": "0000000000000004", "name": "s4-eth1", "type": "copper", "uuid": "s4-eth1"}'), ('/endpoints/endpoint[s4-eth2]', '{"device_uuid": "0000000000000004", "name": "s4-eth2", "type": "copper", "uuid": "s4-eth2"}'), ('/endpoints/endpoint[s3-eth1]', '{"device_uuid": "0000000000000003", "name": "s3-eth1", "type": "copper", "uuid": "s3-eth1"}'), ('/endpoints/endpoint[s3-eth2]', '{"device_uuid": "0000000000000003", "name": "s3-eth2", "type": "copper", "uuid": "s3-eth2"}'), ('/endpoints/endpoint[s2-eth1]', '{"device_uuid": "0000000000000002", "name": "s2-eth1", "type": "copper", "uuid": "s2-eth1"}'), ('/endpoints/endpoint[s2-eth4]', '{"device_uuid": "0000000000000002", "name": "s2-eth4", "type": "copper", "uuid": "s2-eth4"}'), ('/endpoints/endpoint[s2-eth2]', '{"device_uuid": "0000000000000002", "name": "s2-eth2", "type": "copper", "uuid": "s2-eth2"}'), ('/endpoints/endpoint[s2-eth3]', '{"device_uuid": "0000000000000002", "name": "s2-eth3", "type": "copper", "uuid": "s2-eth3"}'), ('/endpoints/endpoint[s5-eth4]', '{"device_uuid": "0000000000000005", "name": "s5-eth4", "type": "copper", "uuid": "s5-eth4"}'), ('/endpoints/endpoint[s5-eth1]', '{"device_uuid": "0000000000000005", "name": "s5-eth1", "type": "copper", "uuid": "s5-eth1"}'), ('/endpoints/endpoint[s5-eth2]', '{"device_uuid": "0000000000000005", "name": "s5-eth2", "type": "copper", "uuid": "s5-eth2"}'), ('/endpoints/endpoint[s5-eth3]', '{"device_uuid": "0000000000000005", "name": "s5-eth3", "type": "copper", "uuid": "s5-eth3"}'), ('/links/link[s3-eth2==s4-eth1]', '{"endpoints": [["0000000000000003", "s3-eth2"], ["0000000000000004", "s4-eth1"]], "name": "0000000000000003-s3-eth2===0000000000000004-s4-eth1", "uuid": "s3-eth2==s4-eth1"}'), ('/links/link[s4-eth1==s3-eth2]', '{"endpoints": [["0000000000000004", "s4-eth1"], ["0000000000000003", "s3-eth2"]], "name": "0000000000000004-s4-eth1===0000000000000003-s3-eth2", "uuid": "s4-eth1==s3-eth2"}'), ('/links/link[s5-eth1==s4-eth2]', '{"endpoints": [["0000000000000005", "s5-eth1"], ["0000000000000004", "s4-eth2"]], "name": "0000000000000005-s5-eth1===0000000000000004-s4-eth2", "uuid": "s5-eth1==s4-eth2"}'), ('/links/link[s5-eth2==s1-eth2]', '{"endpoints": [["0000000000000005", "s5-eth2"], ["0000000000000001", "s1-eth2"]], "name": "0000000000000005-s5-eth2===0000000000000001-s1-eth2", "uuid": "s5-eth2==s1-eth2"}'), ('/links/link[s2-eth2==s3-eth1]', '{"endpoints": [["0000000000000002", "s2-eth2"], ["0000000000000003", "s3-eth1"]], "name": "0000000000000002-s2-eth2===0000000000000003-s3-eth1", "uuid": "s2-eth2==s3-eth1"}'), ('/links/link[s2-eth1==s1-eth1]', '{"endpoints": [["0000000000000002", "s2-eth1"], ["0000000000000001", "s1-eth1"]], "name": "0000000000000002-s2-eth1===0000000000000001-s1-eth1", "uuid": "s2-eth1==s1-eth1"}'), ('/links/link[s1-eth1==s2-eth1]', '{"endpoints": [["0000000000000001", "s1-eth1"], ["0000000000000002", "s2-eth1"]], "name": "0000000000000001-s1-eth1===0000000000000002-s2-eth1", "uuid": "s1-eth1==s2-eth1"}'), ('/links/link[s3-eth1==s2-eth2]', '{"endpoints": [["0000000000000003", "s3-eth1"], ["0000000000000002", "s2-eth2"]], "name": "0000000000000003-s3-eth1===0000000000000002-s2-eth2", "uuid": "s3-eth1==s2-eth2"}'), ('/links/link[s1-eth2==s5-eth2]', '{"endpoints": [["0000000000000001", "s1-eth2"], ["0000000000000005", "s5-eth2"]], "name": "0000000000000001-s1-eth2===0000000000000005-s5-eth2", "uuid": "s1-eth2==s5-eth2"}'), ('/links/link[s4-eth2==s5-eth1]', '{"endpoints": [["0000000000000004", "s4-eth2"], ["0000000000000005", "s5-eth1"]], "name": "0000000000000004-s4-eth2===0000000000000005-s5-eth1", "uuid": "s4-eth2==s5-eth1"}')] +[2025-01-15 15:50:25,475] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"} +[2025-01-15 15:50:25,504] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}} +[2025-01-15 15:50:25,505] DEBUG:device.service.DeviceServiceServicerImpl:ConfigureDevice reply: {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}} +[2025-01-15 15:50:25,508] DEBUG:device.service.DeviceServiceServicerImpl:ConfigureDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s2]/flow[h1-h3]", "resource_value": "{\"dpid\": \"0000000000000002\", \"in-port\": \"s2-eth3\", \"out-port\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s2]/flow[h3-h1]", "resource_value": "{\"dpid\": \"0000000000000002\", \"in-port\": \"s2-eth1\", \"out-port\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s1]/flow[h1-h3]", "resource_value": "{\"dpid\": \"0000000000000001\", \"in-port\": \"s1-eth1\", \"out-port\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s1]/flow[h3-h1]", "resource_value": "{\"dpid\": \"0000000000000001\", \"in-port\": \"s1-eth2\", \"out-port\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s5]/flow[h1-h3]", "resource_value": "{\"dpid\": \"0000000000000005\", \"in-port\": \"s5-eth2\", \"out-port\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_UNDEFINED", "custom": {"resource_key": "/device[s5]/flow[h3-h1]", "resource_value": "{\"dpid\": \"0000000000000005\", \"in-port\": \"s5-eth3\", \"out-port\": \"s5-eth2\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [{"endpoint_id": {"device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "endpoint_uuid": {"uuid": "158268b6-968b-582a-968d-da4b922ebc1c"}, "topology_id": {"context_id": {"context_uuid": {"uuid": "43813baf-195e-5da6-af20-b3d0922e71a7"}}, "topology_uuid": {"uuid": "c76135e3-24a8-5e92-9bed-c3c9139359c8"}}}, "endpoint_location": {}, "endpoint_type": "mgmt", "kpi_sample_types": [], "name": "mgmt"}], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"} +[2025-01-15 15:50:25,508] DEBUG:context.client.ContextClient:Creating channel to 10.152.183.206:1010... +[2025-01-15 15:50:25,509] DEBUG:context.client.ContextClient:Channel created +[2025-01-15 15:50:25,509] DEBUG:context.client.ContextClient:SelectDevice request: {"device_ids": {"device_ids": [{"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}]}, "include_components": false, "include_config_rules": true, "include_endpoints": false} +[2025-01-15 15:50:25,519] DEBUG:context.client.ContextClient:SelectDevice result: {"devices": [{"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"}]} +[2025-01-15 15:50:25,519] INFO:device.service.drivers.OpenFlow.OpenFlowDriver:SetConfig_resources:[('_connect/address', '10.1.7.197'), ('_connect/port', '8080'), ('_connect/settings', '{\n"timeout": 120\n}'), ('/devices/device[0000000000000001]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000001", "status": 2, "type": "packet-switch", "uuid": "0000000000000001"}'), ('/devices/device[0000000000000004]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000004", "status": 2, "type": "packet-switch", "uuid": "0000000000000004"}'), ('/devices/device[0000000000000003]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000003", "status": 2, "type": "packet-switch", "uuid": "0000000000000003"}'), ('/devices/device[0000000000000002]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000002", "status": 2, "type": "packet-switch", "uuid": "0000000000000002"}'), ('/devices/device[0000000000000005]', '{"drivers": "DEVICEDRIVER_RYU", "name": "0000000000000005", "status": 2, "type": "packet-switch", "uuid": "0000000000000005"}'), ('/endpoints/endpoint[s1-eth1]', '{"device_uuid": "0000000000000001", "name": "s1-eth1", "type": "copper", "uuid": "s1-eth1"}'), ('/endpoints/endpoint[s1-eth2]', '{"device_uuid": "0000000000000001", "name": "s1-eth2", "type": "copper", "uuid": "s1-eth2"}'), ('/endpoints/endpoint[s4-eth1]', '{"device_uuid": "0000000000000004", "name": "s4-eth1", "type": "copper", "uuid": "s4-eth1"}'), ('/endpoints/endpoint[s4-eth2]', '{"device_uuid": "0000000000000004", "name": "s4-eth2", "type": "copper", "uuid": "s4-eth2"}'), ('/endpoints/endpoint[s3-eth1]', '{"device_uuid": "0000000000000003", "name": "s3-eth1", "type": "copper", "uuid": "s3-eth1"}'), ('/endpoints/endpoint[s3-eth2]', '{"device_uuid": "0000000000000003", "name": "s3-eth2", "type": "copper", "uuid": "s3-eth2"}'), ('/endpoints/endpoint[s2-eth1]', '{"device_uuid": "0000000000000002", "name": "s2-eth1", "type": "copper", "uuid": "s2-eth1"}'), ('/endpoints/endpoint[s2-eth4]', '{"device_uuid": "0000000000000002", "name": "s2-eth4", "type": "copper", "uuid": "s2-eth4"}'), ('/endpoints/endpoint[s2-eth2]', '{"device_uuid": "0000000000000002", "name": "s2-eth2", "type": "copper", "uuid": "s2-eth2"}'), ('/endpoints/endpoint[s2-eth3]', '{"device_uuid": "0000000000000002", "name": "s2-eth3", "type": "copper", "uuid": "s2-eth3"}'), ('/endpoints/endpoint[s5-eth4]', '{"device_uuid": "0000000000000005", "name": "s5-eth4", "type": "copper", "uuid": "s5-eth4"}'), ('/endpoints/endpoint[s5-eth1]', '{"device_uuid": "0000000000000005", "name": "s5-eth1", "type": "copper", "uuid": "s5-eth1"}'), ('/endpoints/endpoint[s5-eth2]', '{"device_uuid": "0000000000000005", "name": "s5-eth2", "type": "copper", "uuid": "s5-eth2"}'), ('/endpoints/endpoint[s5-eth3]', '{"device_uuid": "0000000000000005", "name": "s5-eth3", "type": "copper", "uuid": "s5-eth3"}'), ('/links/link[s3-eth2==s4-eth1]', '{"endpoints": [["0000000000000003", "s3-eth2"], ["0000000000000004", "s4-eth1"]], "name": "0000000000000003-s3-eth2===0000000000000004-s4-eth1", "uuid": "s3-eth2==s4-eth1"}'), ('/links/link[s4-eth1==s3-eth2]', '{"endpoints": [["0000000000000004", "s4-eth1"], ["0000000000000003", "s3-eth2"]], "name": "0000000000000004-s4-eth1===0000000000000003-s3-eth2", "uuid": "s4-eth1==s3-eth2"}'), ('/links/link[s5-eth1==s4-eth2]', '{"endpoints": [["0000000000000005", "s5-eth1"], ["0000000000000004", "s4-eth2"]], "name": "0000000000000005-s5-eth1===0000000000000004-s4-eth2", "uuid": "s5-eth1==s4-eth2"}'), ('/links/link[s5-eth2==s1-eth2]', '{"endpoints": [["0000000000000005", "s5-eth2"], ["0000000000000001", "s1-eth2"]], "name": "0000000000000005-s5-eth2===0000000000000001-s1-eth2", "uuid": "s5-eth2==s1-eth2"}'), ('/links/link[s2-eth2==s3-eth1]', '{"endpoints": [["0000000000000002", "s2-eth2"], ["0000000000000003", "s3-eth1"]], "name": "0000000000000002-s2-eth2===0000000000000003-s3-eth1", "uuid": "s2-eth2==s3-eth1"}'), ('/links/link[s2-eth1==s1-eth1]', '{"endpoints": [["0000000000000002", "s2-eth1"], ["0000000000000001", "s1-eth1"]], "name": "0000000000000002-s2-eth1===0000000000000001-s1-eth1", "uuid": "s2-eth1==s1-eth1"}'), ('/links/link[s1-eth1==s2-eth1]', '{"endpoints": [["0000000000000001", "s1-eth1"], ["0000000000000002", "s2-eth1"]], "name": "0000000000000001-s1-eth1===0000000000000002-s2-eth1", "uuid": "s1-eth1==s2-eth1"}'), ('/links/link[s3-eth1==s2-eth2]', '{"endpoints": [["0000000000000003", "s3-eth1"], ["0000000000000002", "s2-eth2"]], "name": "0000000000000003-s3-eth1===0000000000000002-s2-eth2", "uuid": "s3-eth1==s2-eth2"}'), ('/links/link[s1-eth2==s5-eth2]', '{"endpoints": [["0000000000000001", "s1-eth2"], ["0000000000000005", "s5-eth2"]], "name": "0000000000000001-s1-eth2===0000000000000005-s5-eth2", "uuid": "s1-eth2==s5-eth2"}'), ('/links/link[s4-eth2==s5-eth1]', '{"endpoints": [["0000000000000004", "s4-eth2"], ["0000000000000005", "s5-eth1"]], "name": "0000000000000004-s4-eth2===0000000000000005-s5-eth1", "uuid": "s4-eth2==s5-eth1"}')] +[2025-01-15 15:50:25,520] DEBUG:context.client.ContextClient:SetDevice request: {"components": [], "controller_id": {}, "device_config": {"config_rules": [{"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "10.1.7.197"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "8080"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": "{\n\"timeout\": 120\n}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000001]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000001\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000001\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000004]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000004\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000004\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000003]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000003\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000003\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000002]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000002\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000002\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/devices/device[0000000000000005]", "resource_value": "{\"drivers\": \"DEVICEDRIVER_RYU\", \"name\": \"0000000000000005\", \"status\": 2, \"type\": \"packet-switch\", \"uuid\": \"0000000000000005\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth1\", \"type\": \"copper\", \"uuid\": \"s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s1-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000001\", \"name\": \"s1-eth2\", \"type\": \"copper\", \"uuid\": \"s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth1\", \"type\": \"copper\", \"uuid\": \"s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s4-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000004\", \"name\": \"s4-eth2\", \"type\": \"copper\", \"uuid\": \"s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth1\", \"type\": \"copper\", \"uuid\": \"s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s3-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000003\", \"name\": \"s3-eth2\", \"type\": \"copper\", \"uuid\": \"s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth1\", \"type\": \"copper\", \"uuid\": \"s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth4\", \"type\": \"copper\", \"uuid\": \"s2-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth2\", \"type\": \"copper\", \"uuid\": \"s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s2-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000002\", \"name\": \"s2-eth3\", \"type\": \"copper\", \"uuid\": \"s2-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth4]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth4\", \"type\": \"copper\", \"uuid\": \"s5-eth4\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth1]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth1\", \"type\": \"copper\", \"uuid\": \"s5-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth2]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth2\", \"type\": \"copper\", \"uuid\": \"s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/endpoints/endpoint[s5-eth3]", "resource_value": "{\"device_uuid\": \"0000000000000005\", \"name\": \"s5-eth3\", \"type\": \"copper\", \"uuid\": \"s5-eth3\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth2==s4-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth2\"], [\"0000000000000004\", \"s4-eth1\"]], \"name\": \"0000000000000003-s3-eth2===0000000000000004-s4-eth1\", \"uuid\": \"s3-eth2==s4-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth1==s3-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth1\"], [\"0000000000000003\", \"s3-eth2\"]], \"name\": \"0000000000000004-s4-eth1===0000000000000003-s3-eth2\", \"uuid\": \"s4-eth1==s3-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth1==s4-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth1\"], [\"0000000000000004\", \"s4-eth2\"]], \"name\": \"0000000000000005-s5-eth1===0000000000000004-s4-eth2\", \"uuid\": \"s5-eth1==s4-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s5-eth2==s1-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000005\", \"s5-eth2\"], [\"0000000000000001\", \"s1-eth2\"]], \"name\": \"0000000000000005-s5-eth2===0000000000000001-s1-eth2\", \"uuid\": \"s5-eth2==s1-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth2==s3-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth2\"], [\"0000000000000003\", \"s3-eth1\"]], \"name\": \"0000000000000002-s2-eth2===0000000000000003-s3-eth1\", \"uuid\": \"s2-eth2==s3-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s2-eth1==s1-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000002\", \"s2-eth1\"], [\"0000000000000001\", \"s1-eth1\"]], \"name\": \"0000000000000002-s2-eth1===0000000000000001-s1-eth1\", \"uuid\": \"s2-eth1==s1-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth1==s2-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth1\"], [\"0000000000000002\", \"s2-eth1\"]], \"name\": \"0000000000000001-s1-eth1===0000000000000002-s2-eth1\", \"uuid\": \"s1-eth1==s2-eth1\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s3-eth1==s2-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000003\", \"s3-eth1\"], [\"0000000000000002\", \"s2-eth2\"]], \"name\": \"0000000000000003-s3-eth1===0000000000000002-s2-eth2\", \"uuid\": \"s3-eth1==s2-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s1-eth2==s5-eth2]", "resource_value": "{\"endpoints\": [[\"0000000000000001\", \"s1-eth2\"], [\"0000000000000005\", \"s5-eth2\"]], \"name\": \"0000000000000001-s1-eth2===0000000000000005-s5-eth2\", \"uuid\": \"s1-eth2==s5-eth2\"}"}}, {"action": "CONFIGACTION_SET", "custom": {"resource_key": "/links/link[s4-eth2==s5-eth1]", "resource_value": "{\"endpoints\": [[\"0000000000000004\", \"s4-eth2\"], [\"0000000000000005\", \"s5-eth1\"]], \"name\": \"0000000000000004-s4-eth2===0000000000000005-s5-eth1\", \"uuid\": \"s4-eth2==s5-eth1\"}"}}]}, "device_drivers": ["DEVICEDRIVER_RYU"], "device_endpoints": [], "device_id": {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}}, "device_operational_status": "DEVICEOPERATIONALSTATUS_ENABLED", "device_type": "openflow-ryu-controller", "name": "RYU"} +[2025-01-15 15:50:25,549] DEBUG:context.client.ContextClient:SetDevice result: {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}} +[2025-01-15 15:50:25,549] DEBUG:device.service.DeviceServiceServicerImpl:ConfigureDevice reply: {"device_uuid": {"uuid": "b2ed9526-554d-5a79-9dc9-33e00faecef1"}} diff --git a/src/device/service/drivers/OpenFlow/OpenFlowDriver.py b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py index 8ccf7e71d..91a1d8da0 100644 --- a/src/device/service/drivers/OpenFlow/OpenFlowDriver.py +++ b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py @@ -13,6 +13,7 @@ # limitations under the License. import json import logging, requests, threading +import resource from requests.auth import HTTPBasicAuth from typing import Any, Iterator, List, Optional, Tuple, Union from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method @@ -149,12 +150,53 @@ class OpenFlowDriver(_Driver): # @metered_subclass_method(METRICS_POOL) def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + url = f"{self.__base_url}/stats/flowentry/add" results = [] - LOGGER.info(f'SetConfig_resources:{resources}') + LOGGER.info(f"SetConfig_resources: {resources}") if not resources: - return results + return results + with self.__lock: + for resource in resources: + try: + resource_key, resource_value = resource + resource_value_dict = json.loads(resource_value) + dpid = int(resource_value_dict["dpid"], 16) + in_port = int(resource_value_dict["in-port"].split("-")[1][3:]) + out_port = int(resource_value_dict["out-port"].split("-")[1][3:]) + flow_entry = { + "dpid": dpid, + "cookie": 0, + "priority": 32768, + "match": { + "in_port": in_port + }, + "actions": [ + { + "type": "OUTPUT", + "port": out_port + } + ] + } + try: + response = requests.post(url,json=flow_entry,timeout=self.__timeout,verify=False,auth=self.__auth) + response.raise_for_status() + results.append(True) + LOGGER.info(f"Successfully posted flow entry: {flow_entry}") + except requests.exceptions.Timeout: + LOGGER.error(f"Timeout connecting to {url}") + results.append(Exception(f"Timeout connecting to {url}")) + except requests.exceptions.RequestException as e: + LOGGER.error(f"Error posting to {url}: {e}") + results.append(e) + else: + LOGGER.warning(f"Skipped invalid resource_key: {resource_key}") + results.append(Exception(f"Invalid resource_key: {resource_key}")) + except Exception as e: + LOGGER.error(f"Error processing resource {resource_key}: {e}", exc_info=True) + results.append(e) return results + # # # diff --git a/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py b/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py index 08141fda5..29e73c42e 100644 --- a/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py +++ b/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py @@ -88,11 +88,12 @@ class RYUServiceHandler(_ServiceHandler): src_device, src_endpoint, = self._get_endpoint_details(endpoints[0]) dst_device, dst_endpoint, = self._get_endpoint_details(endpoints[-1]) src_controller = self.__task_executor.get_device_controller(src_device) + del src_controller.device_config.config_rules[:] for index in range(len(endpoints) - 1): current_device, current_endpoint = self._get_endpoint_details(endpoints[index]) #LOGGER.debug(f"Current device: {current_device.name}, Current endpoint: {current_endpoint.name}") - next_device, next_endpoint = self._get_endpoint_details(endpoints[index + 1]) + next_device, next_endpoint = self._get_endpoint_details(endpoints[index + 1]) #LOGGER.debug(f"Next device: {next_device.name}, Next endpoint: {next_endpoint.name}") if current_device.name == next_device.name: in_port_forward = current_endpoint.name @@ -100,30 +101,37 @@ class RYUServiceHandler(_ServiceHandler): flow_split = service_name.split('-') flow_rule_forward = f"{flow_split[0]}-{flow_split[2]}" flow_rule_reverse = f"{flow_split[2]}-{flow_split[0]}" - forward_resource_value = json.dumps({"dpid": current_device.name, "in-port": in_port_forward, "out-port": out_port_forward}) - forward_rule = ConfigRule( - custom=ConfigRule_Custom( + forward_resource_value = ({"dpid": current_device.name, "in-port": in_port_forward, "out-port": out_port_forward}) + forward_rule = json_config_rule_set ( resource_key=f"/device[{current_endpoint.name.split('-')[0]}]/flow[{flow_rule_forward}]", resource_value=forward_resource_value ) - ) LOGGER.debug(f"Forward configuration rule: {forward_rule}") - src_controller.device_config.config_rules.append(forward_rule) + src_controller.device_config.config_rules.append(ConfigRule(**forward_rule)) in_port_reverse = next_endpoint.name out_port_reverse = current_endpoint.name - reverse_resource_value = json.dumps({"dpid": current_device.name, "in-port": in_port_reverse, "out-port": out_port_reverse}) - reverse_rule = ConfigRule( - custom=ConfigRule_Custom( + reverse_resource_value = ({"dpid": current_device.name, "in-port": in_port_reverse, "out-port": out_port_reverse}) + reverse_rule = json_config_rule_set( resource_key=f"/device[{current_endpoint.name.split('-')[0]}]/flow[{flow_rule_reverse}]", resource_value=reverse_resource_value ) - ) LOGGER.debug(f"Reverse configuration rule: {reverse_rule}") - src_controller.device_config.config_rules.append(reverse_rule) - - self.__task_executor.configure_device(src_controller) - results.append(True) + src_controller.device_config.config_rules.append(ConfigRule(**reverse_rule)) + self.__task_executor.configure_device(src_controller) + results.append(True) + def get_config_rules(controller): + try: + config_rules = controller.device_config.config_rules + for rule in config_rules: + if rule.HasField("custom"): + resource_key = rule.custom.resource_key + resource_value = rule.custom.resource_value + LOGGER.debug(f"Resource key in config: {resource_key}, Resource value in config: {resource_value}") + except Exception as e: + print(f"Error accessing config rules: {e}") + get_config_rules(src_controller) + LOGGER.debug(f"Configuration rules: {src_controller.device_config.config_rules}") return results except Exception as e: -- GitLab From ba897132d96e6a855e4035a1e032d320abd46c61 Mon Sep 17 00:00:00 2001 From: rahhal Date: Tue, 11 Feb 2025 08:03:38 +0000 Subject: [PATCH 7/7] Device-Service component - Ryu - Driver - Service Handler: - Added Connectivity Service --- .../drivers/OpenFlow/OpenFlowDriver.py | 282 ++++++++++++------ .../l3nm_ryu/L3NMryuServiceHandler.py | 88 +++++- 2 files changed, 270 insertions(+), 100 deletions(-) diff --git a/src/device/service/drivers/OpenFlow/OpenFlowDriver.py b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py index 91a1d8da0..070dc597d 100644 --- a/src/device/service/drivers/OpenFlow/OpenFlowDriver.py +++ b/src/device/service/drivers/OpenFlow/OpenFlowDriver.py @@ -43,6 +43,8 @@ class OpenFlowDriver(_Driver): self.__base_url = '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port)) self.__timeout = int(self.settings.get('timeout', 120)) self.tac = TfsApiClient(self.address, int(self.port), scheme=scheme, username=username, password=password) + self.__cookie_counter = 0 + self._priority_counter = 1 def Connect(self) -> bool: url = f"{self.__base_url}" @@ -89,120 +91,208 @@ class OpenFlowDriver(_Driver): results.append((resource_key, e)) return results - -# @metered_subclass_method(METRICS_POOL) -# def GetConfig(self, resource_keys: List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: -# chk_type('resources', resource_keys, list) -# results = [] -# with self.__lock: -# for key in resource_keys: -# try: -# if key.startswith('flows:'): -# dpid = key.split(':', 1)[1] -# flows = get_flows(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) -# results.append((key, flows)) -# elif key.startswith('description:'): -# dpid = key.split(':', 1)[1] -# desc = get_desc(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) -# results.append((key, desc)) -# elif key.startswith('switches'): -# switches = get_switches(self.__base_url, auth=self.__auth, timeout=self.__timeout) -# results.append((key, switches)) -# elif key.startswith('port_description:'): -# dpid = key.split(':', 1)[1] -# desc = get_port_desc(self.__base_url,dpid, auth=self.__auth, timeout=self.__timeout) -# results.append((key, desc)) -# elif key.startswith('switch_info'): -# sin = get_switches_information(self.__base_url, auth=self.__auth, timeout=self.__timeout) -# results.append((key, sin)) -# elif key.startswith('links_info'): -# lin = get_links_information(self.__base_url, auth=self.__auth, timeout=self.__timeout) -# results.append((key, lin)) -# else: -# results.append((key, None)) # If key not handled, append None -# except Exception as e: -# results.append((key, e)) -# return results -# -# @metered_subclass_method(METRICS_POOL) -# def DeleteConfig(self, resource_keys: List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: -# chk_type('resources', resource_keys, list) -# results = [] -# with self.__lock: -# for item in resource_keys: -# try: -# if isinstance(item, tuple): -# key, data = item -# else: -# key, data = item, None -# if key.startswith('flowentry_delete:'): -# dpid = key.split(':', 1)[1] -# flows = del_flow_entry(self.__base_url, dpid, auth=self.__auth, timeout=self.__timeout) -# results.append((key, flows)) -# elif key=='flow_data' and data: -# flow_del = delete_flow (self.__base_url,data,auth=self.__auth, timeout=self.__timeout) -# results.append((key, flow_del)) -# else: -# results.append((key, None)) -# except Exception as e: -# results.append((key, e)) -# return results -# @metered_subclass_method(METRICS_POOL) def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: url = f"{self.__base_url}/stats/flowentry/add" results = [] LOGGER.info(f"SetConfig_resources: {resources}") + if not resources: return results + with self.__lock: for resource in resources: try: - resource_key, resource_value = resource - resource_value_dict = json.loads(resource_value) - dpid = int(resource_value_dict["dpid"], 16) - in_port = int(resource_value_dict["in-port"].split("-")[1][3:]) - out_port = int(resource_value_dict["out-port"].split("-")[1][3:]) - flow_entry = { - "dpid": dpid, - "cookie": 0, - "priority": 32768, - "match": { - "in_port": in_port - }, - "actions": [ - { - "type": "OUTPUT", - "port": out_port - } - ] - } - try: - response = requests.post(url,json=flow_entry,timeout=self.__timeout,verify=False,auth=self.__auth) - response.raise_for_status() - results.append(True) - LOGGER.info(f"Successfully posted flow entry: {flow_entry}") - except requests.exceptions.Timeout: - LOGGER.error(f"Timeout connecting to {url}") - results.append(Exception(f"Timeout connecting to {url}")) - except requests.exceptions.RequestException as e: - LOGGER.error(f"Error posting to {url}: {e}") - results.append(e) - else: - LOGGER.warning(f"Skipped invalid resource_key: {resource_key}") - results.append(Exception(f"Invalid resource_key: {resource_key}")) + resource_key, resource_value = resource + + if not resource_key.startswith("/device[") or not "/flow[" in resource_key: + LOGGER.error(f"Invalid resource_key format: {resource_key}") + results.append(Exception(f"Invalid resource_key format: {resource_key}")) + continue + + try: + resource_value_dict = json.loads(resource_value) + LOGGER.info(f"resource_value_dict: {resource_value_dict}") + dpid = int(resource_value_dict["dpid"], 16) + in_port = int(resource_value_dict["in-port"].split("-")[1][3:]) + out_port = int(resource_value_dict["out-port"].split("-")[1][3:]) + self.__cookie_counter += 1 + cookie = self.__cookie_counter + ip_address_source = resource_value_dict.get("ip_address_source", "") + ip_address_destination = resource_value_dict.get("ip_address_destination", "") + mac_address_source = resource_value_dict.get("mac_address_source", "") + mac_address_destination = resource_value_dict.get("mac_address_destination", "") + + # Default priority + #priority = 1000 + + if "h1-h3" in resource_key: + priority = 65535 + match_fields = { + "in_port": in_port, + "eth_type": 0x0800, + #"ipv4_src": ip_address_source , + #"ipv4_dst": ip_address_destination, + "eth_src": mac_address_source, + "dl_dst": mac_address_destination + } + elif "h3-h1" in resource_key: + priority = 65535 + match_fields = { + "in_port": in_port, + "eth_type": 0x0800, + #"ipv4_src": ip_address_source, + #"ipv4_dst": ip_address_destination, + "eth_src": mac_address_source, + "dl_dst": mac_address_destination + } + elif "h2-h4" in resource_key: + priority = 1500 + match_fields = { + "in_port": in_port, + "eth_type": 0x0800, + "ipv4_src": ip_address_source , + "ipv4_dst": ip_address_destination, + "eth_src": mac_address_source, + "eth_dst": mac_address_destination + } + elif "h4-h2" in resource_key: + priority = 1500 + match_fields = { + "in_port": in_port, + "eth_type": 0x0800, + "ipv4_src": ip_address_source, + "ipv4_dst": ip_address_destination, + "eth_src": mac_address_source, + "eth_dst": mac_address_destination + } + + except (KeyError, ValueError, IndexError) as e: + LOGGER.error(f"Invalid resource_value: {resource_value}, error: {e}") + results.append(Exception(f"Invalid resource_value: {resource_value}")) + continue + + LOGGER.debug(f"Flow match fields: {match_fields}") + + flow_entry = { + "dpid": dpid, + #cookie": 0, + "priority": priority, + "match": match_fields, + "instructions": [ + { + "type": "APPLY_ACTIONS", + "actions": [ + { + "max_len": 65535, + "type": "OUTPUT", + "port": out_port + }]}]} + + flow_entry_arp_foraward = { + "dpid": dpid, + "priority": 65535, + "match": { + "eth_dst": "ff:ff:ff:ff:ff:ff", + "eth_type": 0x0806 + }, + "instructions": [ + { + "type": "APPLY_ACTIONS", + "actions": [ + { + "type": "OUTPUT", + "port": "0xfffffffb" + } + ]}]} + flow_entry_arp_reply = { + "dpid": dpid, + "priority": 65535, + "match": { + "eth_type": 0x0806, + "arp_op": 2 + }, + "instructions": [ + { + "type": "APPLY_ACTIONS", + "actions": [ + { + "type": "OUTPUT", + "port": "0xfffffffb" + } + ]}]} + + try: + response = requests.post(url, json=flow_entry_arp_foraward, timeout=self.__timeout, verify=False, auth=self.__auth) + response = requests.post(url, json=flow_entry_arp_reply, timeout=self.__timeout, verify=False, auth=self.__auth) + response = requests.post(url, json=flow_entry, timeout=self.__timeout, verify=False, auth=self.__auth) + response.raise_for_status() + results.append(True) + LOGGER.info(f"Successfully posted flow entry: {flow_entry}") + except requests.exceptions.Timeout: + LOGGER.error(f"Timeout connecting to {url}") + results.append(Exception(f"Timeout connecting to {url}")) + except requests.exceptions.RequestException as e: + LOGGER.error(f"Error posting flow entry {flow_entry} to {url}: {e}") + results.append(e) except Exception as e: LOGGER.error(f"Error processing resource {resource_key}: {e}", exc_info=True) results.append(e) return results + + + #@metered_subclass_method(METRICS_POOL) + #def DeleteConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + # LOGGER.info(f"DeleteConfig123_resources: {resources}") + # url = f"{self.__base_url}/stats/flowentry/delete_strict" + # results = [] + # if not resources: + # return results + # with self.__lock: + # for resource in resources: + # try: + # resource_key, resource_value = resource + # if not resource_key.startswith("/device[") or not "/flow[" in resource_key: + # LOGGER.error(f"Invalid resource_key format: {resource_key}") + # results.append(Exception(f"Invalid resource_key format: {resource_key}")) + # continue + # try: + # resource_value_dict = json.loads(resource_value) + # dpid = int(resource_value_dict["dpid"], 16) + # in_port = int(resource_value_dict["in-port"].split("-")[1][3:]) + # out_port = int(resource_value_dict["out-port"].split("-")[1][3:]) + # except (KeyError, ValueError, IndexError) as e: + # LOGGER.error(f"Invalid resource_value: {resource_value}, error: {e}") + # results.append(Exception(f"Invalid resource_value: {resource_value}")) + # continue + # flow_entry = { + # "dpid": dpid, + # "table_id": 0, + # "priority": 11111, + # "match": {"in_port": in_port}, + # } + # try: + # response = requests.post(url, json=flow_entry, timeout=self.__timeout, verify=False, auth=self.__auth) + # response.raise_for_status() + # results.append(True) + # LOGGER.info(f"Successfully posted flow entry: {flow_entry}") + # except requests.exceptions.Timeout: + # LOGGER.error(f"Timeout connecting to {url}") + # results.append(Exception(f"Timeout connecting to {url}")) + # except requests.exceptions.RequestException as e: + # LOGGER.error(f"Error posting flow entry {flow_entry} to {url}: {e}") + # results.append(e) + # except Exception as e: + # LOGGER.error(f"Error processing resource {resource_key}: {e}", exc_info=True) + # results.append(e) + # return results # # -# -# @metered_subclass_method(METRICS_POOL) -# def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: -# # TODO: TAPI does not support monitoring by now +## @metered_subclass_method(METRICS_POOL) +## def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: +## # TODO: TAPI does not support monitoring by now # return [False for _ in subscriptions] # # @metered_subclass_method(METRICS_POOL) diff --git a/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py b/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py index 29e73c42e..493ddd60e 100644 --- a/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py +++ b/src/service/service/service_handlers/l3nm_ryu/L3NMryuServiceHandler.py @@ -17,6 +17,7 @@ from venv import logger from re import L from typing import Any, Dict, List, Optional, Tuple, Union +from py import log from pytest import skip from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method from common.proto.context_pb2 import ConfigRule, Device, DeviceId, EndPoint, Service,ConfigRule_Custom,ConfigActionEnum @@ -30,6 +31,7 @@ from service.service.service_handler_api._ServiceHandler import _ServiceHandler from service.service.service_handler_api.SettingsHandler import SettingsHandler from service.service.task_scheduler.TaskExecutor import TaskExecutor import requests +import re logging.basicConfig(level=logging.DEBUG) LOGGER = logging.getLogger(__name__) @@ -80,6 +82,23 @@ class RYUServiceHandler(_ServiceHandler): return [] service_uuid = self.__service.service_id.service_uuid.uuid service_name= self.__service.name + service_configuration_rules=self.__service.service_config.config_rules + LOGGER.debug('service_configuration_rules = {:s}'.format(str(service_configuration_rules))) + ip_addresses = [] + mac_addresses = [] + for rule in service_configuration_rules: + try: + custom_field = rule.custom + resource_value_str = custom_field.resource_value + resource_value = json.loads(resource_value_str) + ip_address = resource_value.get("address_ip") + mac_address = resource_value.get("mac_address") + ip_addresses.append(ip_address) + mac_addresses.append(mac_address) + except Exception as e: + print(f"Error parsing rule: {e}, Rule: {rule}") + LOGGER.debug('ip_address = {:s}'.format(str(ip_addresses))) + LOGGER.debug('mac_address = {:s}'.format(str(mac_addresses))) LOGGER.debug('service_name = {:s}'.format(str(service_name))) #LOGGER.debug('service_uuid = {:s}'.format(str(service_uuid))) #LOGGER.debug('self.__settings_handler = {:s}'.format(str(self.__settings_handler.dump_config_rules()))) @@ -88,6 +107,7 @@ class RYUServiceHandler(_ServiceHandler): src_device, src_endpoint, = self._get_endpoint_details(endpoints[0]) dst_device, dst_endpoint, = self._get_endpoint_details(endpoints[-1]) src_controller = self.__task_executor.get_device_controller(src_device) + #LOGGER.debug(f"Source controller: {src_controller.device_config.config_rules}") del src_controller.device_config.config_rules[:] for index in range(len(endpoints) - 1): @@ -99,9 +119,24 @@ class RYUServiceHandler(_ServiceHandler): in_port_forward = current_endpoint.name out_port_forward = next_endpoint.name flow_split = service_name.split('-') + dpid_src = int(current_device.name) + LOGGER.debug(f"DPID source: {dpid_src}") + dpid_dst = int(next_device.name) + LOGGER.debug(f"DPID destination: {dpid_dst}") flow_rule_forward = f"{flow_split[0]}-{flow_split[2]}" flow_rule_reverse = f"{flow_split[2]}-{flow_split[0]}" - forward_resource_value = ({"dpid": current_device.name, "in-port": in_port_forward, "out-port": out_port_forward}) + ip_address_source = ip_addresses[0] + ip_address_destination = ip_addresses[1] + mac_address_source = mac_addresses[0] + mac_address_destination = mac_addresses[1] + forward_resource_value = ({"dpid": current_device.name, + "in-port": in_port_forward, + "out-port": out_port_forward, + "ip_address_source": ip_address_source, + "ip_address_destination": ip_address_destination, + "mac_address_source": mac_address_source, + "mac_address_destination": mac_address_destination + }) forward_rule = json_config_rule_set ( resource_key=f"/device[{current_endpoint.name.split('-')[0]}]/flow[{flow_rule_forward}]", resource_value=forward_resource_value @@ -109,8 +144,16 @@ class RYUServiceHandler(_ServiceHandler): LOGGER.debug(f"Forward configuration rule: {forward_rule}") src_controller.device_config.config_rules.append(ConfigRule(**forward_rule)) in_port_reverse = next_endpoint.name - out_port_reverse = current_endpoint.name - reverse_resource_value = ({"dpid": current_device.name, "in-port": in_port_reverse, "out-port": out_port_reverse}) + out_port_reverse = current_endpoint.name + reverse_resource_value = { + "dpid": current_device.name, + "in-port": in_port_reverse, + "out-port": out_port_reverse, + "ip_address_source": ip_address_destination, + "ip_address_destination": ip_address_source, + "mac_address_source": mac_address_destination, + "mac_address_destination": mac_address_source + } reverse_rule = json_config_rule_set( resource_key=f"/device[{current_endpoint.name.split('-')[0]}]/flow[{flow_rule_reverse}]", resource_value=reverse_resource_value @@ -137,5 +180,42 @@ class RYUServiceHandler(_ServiceHandler): except Exception as e: LOGGER.error(f"Error in SetEndpoint: {e}") return [e] + + @metered_subclass_method(METRICS_POOL) + def DeleteEndpoint( + self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None + ) -> List[Union[bool, Exception]]: + LOGGER.debug('endpoints = {:s}'.format(str(endpoints))) + chk_type('endpoints', endpoints, list) + if len(endpoints) < 2: return [] + service_uuid = self.__service.service_id.service_uuid.uuid + service_name= self.__service.name + results = [] + try: + src_device_uuid, _ = get_device_endpoint_uuids(endpoints[0]) + src_device = self.__task_executor.get_device(DeviceId(**json_device_id(src_device_uuid))) + src_controller = self.__task_executor.get_device_controller(src_device) + + dst_device_uuid, _ = get_device_endpoint_uuids(endpoints[1]) + dst_device = self.__task_executor.get_device(DeviceId(**json_device_id(dst_device_uuid))) + dst_controller = self.__task_executor.get_device_controller(dst_device) + + if src_controller.device_id.device_uuid.uuid != dst_controller.device_id.device_uuid.uuid: + raise Exception('Different Src-Dst devices not supported by now') + controller = src_controller + + json_config_rule = json_config_rule_delete('/services/service[{:s}]'.format(service_uuid), { + 'uuid': service_uuid + }) + del controller.device_config.config_rules[:] + controller.device_config.config_rules.append(ConfigRule(**json_config_rule)) + self.__task_executor.configure_device(controller) + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unable to DeleteEndpoint for Service({:s})'.format(str(service_uuid))) + results.append(e) + + return results + + - -- GitLab