Loading src/device/client/DeviceClient.py +9 −2 Original line number Diff line number Diff line Loading @@ -15,12 +15,12 @@ import grpc, logging from common.Constants import ServiceNameEnum from common.Settings import get_service_host, get_service_port_grpc from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty,MyConfig,MyConfigId from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceStub from common.tools.client.RetryDecorator import retry, delay_exponential from common.tools.grpc.Tools import grpc_message_to_json_string from common.proto.openconfig_device_pb2_grpc import OpenConfigServiceStub LOGGER = logging.getLogger(__name__) MAX_RETRIES = 15 DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0) Loading @@ -34,12 +34,14 @@ class DeviceClient: LOGGER.debug('Creating channel to {:s}...'.format(str(self.endpoint))) self.channel = None self.stub = None self.openconfig_stub=None self.connect() LOGGER.debug('Channel created') def connect(self): self.channel = grpc.insecure_channel(self.endpoint) self.stub = DeviceServiceStub(self.channel) self.openconfig_stub=OpenConfigServiceStub(self.channel) def close(self): if self.channel is not None: self.channel.close() Loading Loading @@ -80,3 +82,8 @@ class DeviceClient: response = self.stub.MonitorDeviceKpi(request) LOGGER.debug('MonitorDeviceKpi result: {:s}'.format(grpc_message_to_json_string(response))) return response def ConfigureOpticalDevice(self, request : MyConfig) -> MyConfigId: response = self.openconfig_stub.ConfigureOpticalDevice(request) return response src/device/service/DeviceService.py +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ from common.tools.service.GenericGrpcService import GenericGrpcService from .driver_api.DriverInstanceCache import DriverInstanceCache from .DeviceServiceServicerImpl import DeviceServiceServicerImpl from .monitoring.MonitoringLoops import MonitoringLoops from .OpenConfigServicer import OpenConfigServicer from common.proto.openconfig_device_pb2_grpc import add_OpenConfigServiceServicer_to_server # Custom gRPC settings # Multiple clients might keep connections alive waiting for RPC methods to be executed. Loading @@ -31,10 +33,13 @@ class DeviceService(GenericGrpcService): super().__init__(port, max_workers=GRPC_MAX_WORKERS, cls_name=cls_name) self.monitoring_loops = MonitoringLoops() self.device_servicer = DeviceServiceServicerImpl(driver_instance_cache, self.monitoring_loops) self.openconfig_device_servicer=OpenConfigServicer(driver_instance_cache,self.monitoring_loops) def install_servicers(self): self.monitoring_loops.start() add_DeviceServiceServicer_to_server(self.device_servicer, self.server) add_OpenConfigServiceServicer_to_server(self.openconfig_device_servicer,self.server) def stop(self): super().stop() Loading src/device/service/DeviceServiceServicerImpl.py +13 −4 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.proto.context_pb2 import ( Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link) Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link,MyConfig,MyConfigId) from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer from common.tools.context_queries.Device import get_device Loading @@ -29,6 +29,7 @@ from context.client.ContextClient import ContextClient from .driver_api._Driver import _Driver from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver from .monitoring.MonitoringLoops import MonitoringLoops from .drivers.oc_driver.OCDriver import OCDriver from .ErrorMessages import ERROR_MISSING_DRIVER, ERROR_MISSING_KPI from .Tools import ( check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules, Loading Loading @@ -58,6 +59,7 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): device_uuid = request.device_id.device_uuid.uuid connection_config_rules = check_connect_rules(request.device_config) if (request.device_drivers[0]!= 9) : check_no_endpoints(request.device_endpoints) t1 = time.time() Loading Loading @@ -139,6 +141,13 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): # ZTP is not deployed; assume the device is ready while onboarding and set them as enabled. device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED # temporary line if (request.device_drivers[0]== 9 and len(request.device_endpoints)>0): for endpoint in request.device_endpoints: #endpoint.endpoint_id.device_id.CopyFrom(device.device_id) pass device.device_endpoints.extend(request.device_endpoints) device_id = context_client.SetDevice(device) t10 = time.time() Loading src/device/service/OpenConfigServicer.py 0 → 100644 +212 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 grpc, logging, os, time from typing import Dict from prometheus_client import Histogram from common.Constants import ServiceNameEnum from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.proto.context_pb2 import ( Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link,MyConfig,MyConfigId ,MyConfig,MyConfigList) from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer from common.tools.context_queries.Device import get_device from common.tools.mutex_queues.MutexQueues import MutexQueues from context.client.ContextClient import ContextClient from .driver_api._Driver import _Driver from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver from .monitoring.MonitoringLoops import MonitoringLoops from .drivers.oc_driver.OCDriver import OCDriver from .ErrorMessages import ERROR_MISSING_DRIVER, ERROR_MISSING_KPI from .Tools import extract_resources from .Tools import ( check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules, get_device_controller_uuid, populate_config_rules, populate_endpoint_monitoring_resources, populate_endpoints, populate_initial_config_rules, subscribe_kpi, unsubscribe_kpi, update_endpoints) LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Device', 'RPC') METRICS_POOL_DETAILS = MetricsPool('Device', 'execution', labels={ 'driver': '', 'operation': '', 'step': '', }) class OpenConfigServicer(DeviceServiceServicer): def __init__(self, driver_instance_cache : DriverInstanceCache, monitoring_loops : MonitoringLoops) -> None: LOGGER.debug('Creating Servicer...') self.driver_instance_cache = driver_instance_cache self.monitoring_loops = monitoring_loops self.mutex_queues = MutexQueues() LOGGER.debug('Servicer Created') @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def AddOpenConfigDevice(self, request : MyConfig, context : grpc.ServicerContext) -> DeviceId: device_uuid = request.device_id.device_uuid.uuid device_type=request.device_type ocdriver=OCDriver() connection_config_rules = check_connect_rules(request.device_config) check_no_endpoints(request.device_endpoints) context_client = ContextClient() device = get_device(context_client, device_uuid, rw_copy=True) if device is None: # not in context, create blank one to get UUID, and populate it below device = Device() device.device_id.CopyFrom(request.device_id) # pylint: disable=no-member device.name = request.name device.device_type = request.device_type device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED device.device_drivers.extend(request.device_drivers) # pylint: disable=no-member device.device_config.CopyFrom(request.device_config) # pylint: disable=no-member device_id = context_client.SetDevice(device) device = get_device(context_client, device_id.device_uuid.uuid, rw_copy=True) # update device_uuid to honor UUID provided by Context device_uuid = device.device_id.device_uuid.uuid LOGGER.debug('device type %s',device) t2 = time.time() self.mutex_queues.wait_my_turn(device_uuid) t3 = time.time() #temp fix to solve the error #todo check what to pass here resources_to_get = [] try: #driver : _Driver = get_driver(self.driver_instance_cache, device) results_getconfig=ocdriver.GetConfig(resource_keys=resources_to_get,device_uuid=device_uuid) #results_getconfig = driver.GetConfig(resources_to_get,device_uuid) except Exception as error : LOGGER.debug("error %s",error) # @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) # def ConfigureOpenConfigDevice(self, request : MyConfig, context : grpc.ServicerContext) -> DeviceId: # device_id = request.myconfig_id # device_uuid = device_id.myconfig_uuid # self.mutex_queues.wait_my_turn(device_uuid) # t1 = time.time() # try: # context_client = ContextClient() # t2 = time.time() # device = get_device( # context_client, device_uuid, rw_copy=True, include_endpoints=False, include_components=False, # include_config_rules=True) # if device is None: # raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice') # t3 = time.time() # device_controller_uuid = get_device_controller_uuid(device) # if device_controller_uuid is not None: # device = get_device( # context_client, device_controller_uuid, rw_copy=True, include_endpoints=False, # include_components=False, include_config_rules=True) # if device is None: # raise NotFoundException( # 'Device', device_controller_uuid, extra_details='loading in ConfigureDevice') # device_uuid = device.device_id.device_uuid.uuid # driver : _Driver = get_driver(self.driver_instance_cache, device) # resources_to_set, resources_to_delete = compute_rules_to_add_delete(device, request) # results_setconfig = driver.SetConfig(resources=resources_to_set) # except Exception as e: # LOGGER.debug("error in updating %s",e) ''' @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def ConfigureOpticalDevice (self, request : MyConfig, context:grpc.ServicerContext) -> Empty: LOGGER.info('Updating from ConfigureOpticalDevice %s',request) device_id = request.myconfig_id device_uuid = device_id.myconfig_uuid resources=[] add_proccess=False update_interface=False result=None config =eval(request.config) filter_fields= ["frequency","target-output-power","interface","operational-mode"] try: context_client = ContextClient() device = get_device( context_client, device_uuid, rw_copy=True, include_endpoints=False, include_components=False, include_config_rules=True) if device is None: LOGGER.debug("device is none") raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice') resources,conditions=extract_resources(config=config,device=device) driver : _Driver = get_driver(self.driver_instance_cache, device) LOGGER.info("resource %s conditions %s",resources,conditions) result = driver.SetConfig(resources=resources,conditions=conditions) driver.GetConfig(resource_keys=filter_fields) except Exception as e: LOGGER.info("error in configuring %s",e) LOGGER.info("result %s",result) return Empty() ''' #modified Andrea @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def ConfigureOpticalDevice (self, request : MyConfig, context:grpc.ServicerContext) -> Empty: LOGGER.info('Setting from ConfigureOpticalDevice with Flows %s',request) #device_id = request.myconfig_id #device_uuid = device_id.myconfig_uuid device_uuid = request.myconfig_id.myconfig_uuid LOGGER.info("AAAAAAAAAAAAAAAAAAAAAAA device uuid {}".format(device_uuid)) resources=[] result=None config =eval(request.config) filter_fields= ["frequency","target-output-power","interface","operational-mode"] try: context_client = ContextClient() device = get_device( context_client, device_uuid, rw_copy=True, include_endpoints=True, include_components=False, include_config_rules=False) if device is None: LOGGER.info("AAAAAAAAAAAAAAAAAAAAAAAdevice is none") raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice') resources,conditions=extract_resources(config=config,device=device) driver : _Driver = get_driver(self.driver_instance_cache, device) LOGGER.info("resource %s conditions %s",resources,conditions) result = driver.SetConfig(resources=resources,conditions=conditions) #todo #add a control with the NETCONF get #driver.GetConfig(resource_keys=filter_fields) except Exception as e: LOGGER.info("error in configuring %s",e) LOGGER.info("result %s",result) return Empty() No newline at end of file src/device/service/Tools.py +95 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ # 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 uuid import UUID, uuid4, uuid5 import json, logging from typing import Any, Dict, List, Optional, Tuple, Union from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME Loading @@ -27,9 +27,29 @@ from .ErrorMessages import ( ERROR_BAD_RESOURCE, ERROR_DELETE, ERROR_GET, ERROR_GET_INIT, ERROR_MISSING_KPI, ERROR_SAMPLETYPE, ERROR_SET, ERROR_SUBSCRIBE, ERROR_UNSUBSCRIBE, ERROR_UNSUP_RESOURCE ) from .drivers.oc_driver.OCDriver import OCDriver from common.method_wrappers.ServiceExceptions import NotFoundException from common.type_checkers.Checkers import chk_length, chk_type from common.proto.context_pb2 import EndPoint LOGGER = logging.getLogger(__name__) def get_endpoint_matching(device : Device, endpoint_uuid_or_name : str) -> EndPoint: for endpoint in device.device_endpoints: choices = {endpoint.endpoint_id.endpoint_uuid.uuid, endpoint.name} if endpoint_uuid_or_name in choices: return endpoint device_uuid = device.device_id.device_uuid.uuid extra_details = 'Device({:s})'.format(str(device_uuid)) raise NotFoundException('Endpoint', endpoint_uuid_or_name, extra_details=extra_details) def get_device_endpoint_uuids(endpoint : Tuple[str, str, Optional[str]]) -> Tuple[str, str]: chk_type('endpoint', endpoint, (tuple, list)) chk_length('endpoint', endpoint, min_length=2, max_length=3) device_uuid, endpoint_uuid = endpoint[0:2] # ignore topology_uuid by now return device_uuid, endpoint_uuid def check_connect_rules(device_config : DeviceConfig) -> Dict[str, Any]: connection_config_rules = dict() unexpected_config_rules = list() Loading Loading @@ -434,3 +454,77 @@ def update_endpoints(src_device : Device, dst_device : Device) -> None: dst_topology_id = dst_endpoint_id.topology_id if len(src_topology_uuid) > 0: dst_topology_id.topology_uuid.uuid = src_topology_uuid if len(src_context_uuid) > 0: dst_topology_id.context_id.context_uuid.uuid = src_context_uuid def oc_default_endpoints( device : Device, driver : _Driver, monitoring_loops : MonitoringLoops, new_sub_devices : Dict[str, Device], new_sub_links : Dict[str, Link] ) -> List[str]: pass #def get_enpoint_name (device:Device,endpoint_id:str): # str(UUID(str_uuid_or_name)) def get_edit_target (device:Device,is_opticalband:bool)-> str: if (is_opticalband): return "optical-band" else : if device.device_type =='optical-roadm': return 'media-channel' else : return 'optical-channel' def extract_resources (config:dict,device:Device)-> list : conditions={} resources=[] resources.append({"resource_key":"channel_namespace","value":config["channel_namespace"] if "channel_namespace" in config else None}) resources.append({"resource_key":'add_transceiver',"value":config['add_transceiver'] if 'add_transceiver' in config else None}) resources.append({"resource_key":"interface","value":config["update_interface"] if 'update_interface' in config else None}) is_opticalband=config['is_opticalband'] if 'is_opticalband' in config else False conditions["is_opticalband"]=is_opticalband conditions["edit_type"]=get_edit_target(device=device,is_opticalband=is_opticalband) if ('flow' in config): #for tuple_value in config['flow'][device.name]: source_vals = [] dest_vals = [] for tuple_value in config['flow']: source_port=None destination_port=None #resources.append({"resource_key":"source_port","value":source_port}) #resources.append({"resource_key":"destination_port","value":destination_port}) source_port_uuid,destination_port_uuid=tuple_value if (source_port_uuid !='0'): src_endpoint_obj = get_endpoint_matching(device, source_port_uuid) source_port = src_endpoint_obj.name source_vals.append(source_port) if (destination_port_uuid !='0'): dst_endpoint_obj = get_endpoint_matching(device, destination_port_uuid) destination_port = dst_endpoint_obj.name dest_vals.append(destination_port) resources.append({"resource_key":"source_port","value":source_vals}) resources.append({"resource_key":"destination_port","value":dest_vals}) if ('new_config' in config): lower_frequency=None upper_frequency=None resources.append({"resource_key":"target-output-power","value":config["new_config"]["target-output-power"] if "target-output-power" in config["new_config"] else None }) #resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config else config["new_config"]["freqency"]}) resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config["new_config"] else None}) resources.append({"resource_key":"operational-mode","value":config["new_config"]["operational-mode"] if "operational-mode" in config["new_config"] else None}) resources.append({"resource_key":"line-port","value":config["new_config"]["line-port"] if "line-port" in config["new_config"] else None}) resources.append({"resource_key":"name","value":config['new_config']['band_type'] if 'band_type' in config['new_config'] else None}) resources.append({"resource_key":"optical-band-parent","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None }) resources.append({"resource_key":"channel_name","value":config["new_config"]["name"] if "name" in config["new_config"] else None}) if not is_opticalband : if 'frequency' in config['new_config'] and 'band' in config['new_config'] and conditions["edit_type"] == 'media-channel': lower_frequency= int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2)) upper_frequency= int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2)) #lower_frequency= (config['new_config']['frequency']- config['new_config']['band'])/2 #upper_frequency=(config['new_config']['frequency']+ config['new_config']['band'])/2 resources.append({"resource_key":"index","value":config["new_config"]["flow_id"] if "flow_id" in config["new_config"] else None}) else : lower_frequency=config['new_config']['low-freq'] if "low-freq" in config['new_config'] else None upper_frequency=config['new_config']['up-freq'] if 'up-freq' in config['new_config'] else None resources.append({"resource_key":"index","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None}) resources.append({"resource_key":"lower-frequency","value":lower_frequency}) resources.append({"resource_key":"upper-frequency","value":upper_frequency}) return [resources,conditions] Loading
src/device/client/DeviceClient.py +9 −2 Original line number Diff line number Diff line Loading @@ -15,12 +15,12 @@ import grpc, logging from common.Constants import ServiceNameEnum from common.Settings import get_service_host, get_service_port_grpc from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty,MyConfig,MyConfigId from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceStub from common.tools.client.RetryDecorator import retry, delay_exponential from common.tools.grpc.Tools import grpc_message_to_json_string from common.proto.openconfig_device_pb2_grpc import OpenConfigServiceStub LOGGER = logging.getLogger(__name__) MAX_RETRIES = 15 DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0) Loading @@ -34,12 +34,14 @@ class DeviceClient: LOGGER.debug('Creating channel to {:s}...'.format(str(self.endpoint))) self.channel = None self.stub = None self.openconfig_stub=None self.connect() LOGGER.debug('Channel created') def connect(self): self.channel = grpc.insecure_channel(self.endpoint) self.stub = DeviceServiceStub(self.channel) self.openconfig_stub=OpenConfigServiceStub(self.channel) def close(self): if self.channel is not None: self.channel.close() Loading Loading @@ -80,3 +82,8 @@ class DeviceClient: response = self.stub.MonitorDeviceKpi(request) LOGGER.debug('MonitorDeviceKpi result: {:s}'.format(grpc_message_to_json_string(response))) return response def ConfigureOpticalDevice(self, request : MyConfig) -> MyConfigId: response = self.openconfig_stub.ConfigureOpticalDevice(request) return response
src/device/service/DeviceService.py +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ from common.tools.service.GenericGrpcService import GenericGrpcService from .driver_api.DriverInstanceCache import DriverInstanceCache from .DeviceServiceServicerImpl import DeviceServiceServicerImpl from .monitoring.MonitoringLoops import MonitoringLoops from .OpenConfigServicer import OpenConfigServicer from common.proto.openconfig_device_pb2_grpc import add_OpenConfigServiceServicer_to_server # Custom gRPC settings # Multiple clients might keep connections alive waiting for RPC methods to be executed. Loading @@ -31,10 +33,13 @@ class DeviceService(GenericGrpcService): super().__init__(port, max_workers=GRPC_MAX_WORKERS, cls_name=cls_name) self.monitoring_loops = MonitoringLoops() self.device_servicer = DeviceServiceServicerImpl(driver_instance_cache, self.monitoring_loops) self.openconfig_device_servicer=OpenConfigServicer(driver_instance_cache,self.monitoring_loops) def install_servicers(self): self.monitoring_loops.start() add_DeviceServiceServicer_to_server(self.device_servicer, self.server) add_OpenConfigServiceServicer_to_server(self.openconfig_device_servicer,self.server) def stop(self): super().stop() Loading
src/device/service/DeviceServiceServicerImpl.py +13 −4 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.proto.context_pb2 import ( Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link) Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link,MyConfig,MyConfigId) from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer from common.tools.context_queries.Device import get_device Loading @@ -29,6 +29,7 @@ from context.client.ContextClient import ContextClient from .driver_api._Driver import _Driver from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver from .monitoring.MonitoringLoops import MonitoringLoops from .drivers.oc_driver.OCDriver import OCDriver from .ErrorMessages import ERROR_MISSING_DRIVER, ERROR_MISSING_KPI from .Tools import ( check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules, Loading Loading @@ -58,6 +59,7 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): device_uuid = request.device_id.device_uuid.uuid connection_config_rules = check_connect_rules(request.device_config) if (request.device_drivers[0]!= 9) : check_no_endpoints(request.device_endpoints) t1 = time.time() Loading Loading @@ -139,6 +141,13 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): # ZTP is not deployed; assume the device is ready while onboarding and set them as enabled. device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED # temporary line if (request.device_drivers[0]== 9 and len(request.device_endpoints)>0): for endpoint in request.device_endpoints: #endpoint.endpoint_id.device_id.CopyFrom(device.device_id) pass device.device_endpoints.extend(request.device_endpoints) device_id = context_client.SetDevice(device) t10 = time.time() Loading
src/device/service/OpenConfigServicer.py 0 → 100644 +212 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 grpc, logging, os, time from typing import Dict from prometheus_client import Histogram from common.Constants import ServiceNameEnum from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.proto.context_pb2 import ( Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link,MyConfig,MyConfigId ,MyConfig,MyConfigList) from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer from common.tools.context_queries.Device import get_device from common.tools.mutex_queues.MutexQueues import MutexQueues from context.client.ContextClient import ContextClient from .driver_api._Driver import _Driver from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver from .monitoring.MonitoringLoops import MonitoringLoops from .drivers.oc_driver.OCDriver import OCDriver from .ErrorMessages import ERROR_MISSING_DRIVER, ERROR_MISSING_KPI from .Tools import extract_resources from .Tools import ( check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules, get_device_controller_uuid, populate_config_rules, populate_endpoint_monitoring_resources, populate_endpoints, populate_initial_config_rules, subscribe_kpi, unsubscribe_kpi, update_endpoints) LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Device', 'RPC') METRICS_POOL_DETAILS = MetricsPool('Device', 'execution', labels={ 'driver': '', 'operation': '', 'step': '', }) class OpenConfigServicer(DeviceServiceServicer): def __init__(self, driver_instance_cache : DriverInstanceCache, monitoring_loops : MonitoringLoops) -> None: LOGGER.debug('Creating Servicer...') self.driver_instance_cache = driver_instance_cache self.monitoring_loops = monitoring_loops self.mutex_queues = MutexQueues() LOGGER.debug('Servicer Created') @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def AddOpenConfigDevice(self, request : MyConfig, context : grpc.ServicerContext) -> DeviceId: device_uuid = request.device_id.device_uuid.uuid device_type=request.device_type ocdriver=OCDriver() connection_config_rules = check_connect_rules(request.device_config) check_no_endpoints(request.device_endpoints) context_client = ContextClient() device = get_device(context_client, device_uuid, rw_copy=True) if device is None: # not in context, create blank one to get UUID, and populate it below device = Device() device.device_id.CopyFrom(request.device_id) # pylint: disable=no-member device.name = request.name device.device_type = request.device_type device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED device.device_drivers.extend(request.device_drivers) # pylint: disable=no-member device.device_config.CopyFrom(request.device_config) # pylint: disable=no-member device_id = context_client.SetDevice(device) device = get_device(context_client, device_id.device_uuid.uuid, rw_copy=True) # update device_uuid to honor UUID provided by Context device_uuid = device.device_id.device_uuid.uuid LOGGER.debug('device type %s',device) t2 = time.time() self.mutex_queues.wait_my_turn(device_uuid) t3 = time.time() #temp fix to solve the error #todo check what to pass here resources_to_get = [] try: #driver : _Driver = get_driver(self.driver_instance_cache, device) results_getconfig=ocdriver.GetConfig(resource_keys=resources_to_get,device_uuid=device_uuid) #results_getconfig = driver.GetConfig(resources_to_get,device_uuid) except Exception as error : LOGGER.debug("error %s",error) # @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) # def ConfigureOpenConfigDevice(self, request : MyConfig, context : grpc.ServicerContext) -> DeviceId: # device_id = request.myconfig_id # device_uuid = device_id.myconfig_uuid # self.mutex_queues.wait_my_turn(device_uuid) # t1 = time.time() # try: # context_client = ContextClient() # t2 = time.time() # device = get_device( # context_client, device_uuid, rw_copy=True, include_endpoints=False, include_components=False, # include_config_rules=True) # if device is None: # raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice') # t3 = time.time() # device_controller_uuid = get_device_controller_uuid(device) # if device_controller_uuid is not None: # device = get_device( # context_client, device_controller_uuid, rw_copy=True, include_endpoints=False, # include_components=False, include_config_rules=True) # if device is None: # raise NotFoundException( # 'Device', device_controller_uuid, extra_details='loading in ConfigureDevice') # device_uuid = device.device_id.device_uuid.uuid # driver : _Driver = get_driver(self.driver_instance_cache, device) # resources_to_set, resources_to_delete = compute_rules_to_add_delete(device, request) # results_setconfig = driver.SetConfig(resources=resources_to_set) # except Exception as e: # LOGGER.debug("error in updating %s",e) ''' @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def ConfigureOpticalDevice (self, request : MyConfig, context:grpc.ServicerContext) -> Empty: LOGGER.info('Updating from ConfigureOpticalDevice %s',request) device_id = request.myconfig_id device_uuid = device_id.myconfig_uuid resources=[] add_proccess=False update_interface=False result=None config =eval(request.config) filter_fields= ["frequency","target-output-power","interface","operational-mode"] try: context_client = ContextClient() device = get_device( context_client, device_uuid, rw_copy=True, include_endpoints=False, include_components=False, include_config_rules=True) if device is None: LOGGER.debug("device is none") raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice') resources,conditions=extract_resources(config=config,device=device) driver : _Driver = get_driver(self.driver_instance_cache, device) LOGGER.info("resource %s conditions %s",resources,conditions) result = driver.SetConfig(resources=resources,conditions=conditions) driver.GetConfig(resource_keys=filter_fields) except Exception as e: LOGGER.info("error in configuring %s",e) LOGGER.info("result %s",result) return Empty() ''' #modified Andrea @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def ConfigureOpticalDevice (self, request : MyConfig, context:grpc.ServicerContext) -> Empty: LOGGER.info('Setting from ConfigureOpticalDevice with Flows %s',request) #device_id = request.myconfig_id #device_uuid = device_id.myconfig_uuid device_uuid = request.myconfig_id.myconfig_uuid LOGGER.info("AAAAAAAAAAAAAAAAAAAAAAA device uuid {}".format(device_uuid)) resources=[] result=None config =eval(request.config) filter_fields= ["frequency","target-output-power","interface","operational-mode"] try: context_client = ContextClient() device = get_device( context_client, device_uuid, rw_copy=True, include_endpoints=True, include_components=False, include_config_rules=False) if device is None: LOGGER.info("AAAAAAAAAAAAAAAAAAAAAAAdevice is none") raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice') resources,conditions=extract_resources(config=config,device=device) driver : _Driver = get_driver(self.driver_instance_cache, device) LOGGER.info("resource %s conditions %s",resources,conditions) result = driver.SetConfig(resources=resources,conditions=conditions) #todo #add a control with the NETCONF get #driver.GetConfig(resource_keys=filter_fields) except Exception as e: LOGGER.info("error in configuring %s",e) LOGGER.info("result %s",result) return Empty() No newline at end of file
src/device/service/Tools.py +95 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ # 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 uuid import UUID, uuid4, uuid5 import json, logging from typing import Any, Dict, List, Optional, Tuple, Union from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME Loading @@ -27,9 +27,29 @@ from .ErrorMessages import ( ERROR_BAD_RESOURCE, ERROR_DELETE, ERROR_GET, ERROR_GET_INIT, ERROR_MISSING_KPI, ERROR_SAMPLETYPE, ERROR_SET, ERROR_SUBSCRIBE, ERROR_UNSUBSCRIBE, ERROR_UNSUP_RESOURCE ) from .drivers.oc_driver.OCDriver import OCDriver from common.method_wrappers.ServiceExceptions import NotFoundException from common.type_checkers.Checkers import chk_length, chk_type from common.proto.context_pb2 import EndPoint LOGGER = logging.getLogger(__name__) def get_endpoint_matching(device : Device, endpoint_uuid_or_name : str) -> EndPoint: for endpoint in device.device_endpoints: choices = {endpoint.endpoint_id.endpoint_uuid.uuid, endpoint.name} if endpoint_uuid_or_name in choices: return endpoint device_uuid = device.device_id.device_uuid.uuid extra_details = 'Device({:s})'.format(str(device_uuid)) raise NotFoundException('Endpoint', endpoint_uuid_or_name, extra_details=extra_details) def get_device_endpoint_uuids(endpoint : Tuple[str, str, Optional[str]]) -> Tuple[str, str]: chk_type('endpoint', endpoint, (tuple, list)) chk_length('endpoint', endpoint, min_length=2, max_length=3) device_uuid, endpoint_uuid = endpoint[0:2] # ignore topology_uuid by now return device_uuid, endpoint_uuid def check_connect_rules(device_config : DeviceConfig) -> Dict[str, Any]: connection_config_rules = dict() unexpected_config_rules = list() Loading Loading @@ -434,3 +454,77 @@ def update_endpoints(src_device : Device, dst_device : Device) -> None: dst_topology_id = dst_endpoint_id.topology_id if len(src_topology_uuid) > 0: dst_topology_id.topology_uuid.uuid = src_topology_uuid if len(src_context_uuid) > 0: dst_topology_id.context_id.context_uuid.uuid = src_context_uuid def oc_default_endpoints( device : Device, driver : _Driver, monitoring_loops : MonitoringLoops, new_sub_devices : Dict[str, Device], new_sub_links : Dict[str, Link] ) -> List[str]: pass #def get_enpoint_name (device:Device,endpoint_id:str): # str(UUID(str_uuid_or_name)) def get_edit_target (device:Device,is_opticalband:bool)-> str: if (is_opticalband): return "optical-band" else : if device.device_type =='optical-roadm': return 'media-channel' else : return 'optical-channel' def extract_resources (config:dict,device:Device)-> list : conditions={} resources=[] resources.append({"resource_key":"channel_namespace","value":config["channel_namespace"] if "channel_namespace" in config else None}) resources.append({"resource_key":'add_transceiver',"value":config['add_transceiver'] if 'add_transceiver' in config else None}) resources.append({"resource_key":"interface","value":config["update_interface"] if 'update_interface' in config else None}) is_opticalband=config['is_opticalband'] if 'is_opticalband' in config else False conditions["is_opticalband"]=is_opticalband conditions["edit_type"]=get_edit_target(device=device,is_opticalband=is_opticalband) if ('flow' in config): #for tuple_value in config['flow'][device.name]: source_vals = [] dest_vals = [] for tuple_value in config['flow']: source_port=None destination_port=None #resources.append({"resource_key":"source_port","value":source_port}) #resources.append({"resource_key":"destination_port","value":destination_port}) source_port_uuid,destination_port_uuid=tuple_value if (source_port_uuid !='0'): src_endpoint_obj = get_endpoint_matching(device, source_port_uuid) source_port = src_endpoint_obj.name source_vals.append(source_port) if (destination_port_uuid !='0'): dst_endpoint_obj = get_endpoint_matching(device, destination_port_uuid) destination_port = dst_endpoint_obj.name dest_vals.append(destination_port) resources.append({"resource_key":"source_port","value":source_vals}) resources.append({"resource_key":"destination_port","value":dest_vals}) if ('new_config' in config): lower_frequency=None upper_frequency=None resources.append({"resource_key":"target-output-power","value":config["new_config"]["target-output-power"] if "target-output-power" in config["new_config"] else None }) #resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config else config["new_config"]["freqency"]}) resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config["new_config"] else None}) resources.append({"resource_key":"operational-mode","value":config["new_config"]["operational-mode"] if "operational-mode" in config["new_config"] else None}) resources.append({"resource_key":"line-port","value":config["new_config"]["line-port"] if "line-port" in config["new_config"] else None}) resources.append({"resource_key":"name","value":config['new_config']['band_type'] if 'band_type' in config['new_config'] else None}) resources.append({"resource_key":"optical-band-parent","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None }) resources.append({"resource_key":"channel_name","value":config["new_config"]["name"] if "name" in config["new_config"] else None}) if not is_opticalband : if 'frequency' in config['new_config'] and 'band' in config['new_config'] and conditions["edit_type"] == 'media-channel': lower_frequency= int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2)) upper_frequency= int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2)) #lower_frequency= (config['new_config']['frequency']- config['new_config']['band'])/2 #upper_frequency=(config['new_config']['frequency']+ config['new_config']['band'])/2 resources.append({"resource_key":"index","value":config["new_config"]["flow_id"] if "flow_id" in config["new_config"] else None}) else : lower_frequency=config['new_config']['low-freq'] if "low-freq" in config['new_config'] else None upper_frequency=config['new_config']['up-freq'] if 'up-freq' in config['new_config'] else None resources.append({"resource_key":"index","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None}) resources.append({"resource_key":"lower-frequency","value":lower_frequency}) resources.append({"resource_key":"upper-frequency","value":upper_frequency}) return [resources,conditions]