From 6963de194ed183269a62cc9a52b04861fc8f29f1 Mon Sep 17 00:00:00 2001 From: sgambelluri Date: Thu, 15 Feb 2024 10:04:13 +0300 Subject: [PATCH 1/2] opticalcontoller service --- src/service/requirements.in | 1 + .../service/ServiceServiceServicerImpl.py | 91 ++++- .../service/service_handlers/__init__.py | 7 + .../service_handlers/oc/ConfigRules.py | 255 ++++++++++++++ .../service_handlers/oc/OCServiceHandler.py | 274 +++++++++++++++ .../service/service_handlers/oc/OCTools.py | 143 ++++++++ .../service/service_handlers/oc/__init__.py | 14 + .../service/task_scheduler/TaskExecutor.py | 68 +++- src/service/service/tools/OpticalTools.py | 290 ++++++++++++++++ src/service/service/tools/replies.py | 321 ++++++++++++++++++ 10 files changed, 1461 insertions(+), 3 deletions(-) create mode 100644 src/service/service/service_handlers/oc/ConfigRules.py create mode 100644 src/service/service/service_handlers/oc/OCServiceHandler.py create mode 100644 src/service/service/service_handlers/oc/OCTools.py create mode 100644 src/service/service/service_handlers/oc/__init__.py create mode 100644 src/service/service/tools/OpticalTools.py create mode 100644 src/service/service/tools/replies.py diff --git a/src/service/requirements.in b/src/service/requirements.in index a10f7da7a..ea4d41cc4 100644 --- a/src/service/requirements.in +++ b/src/service/requirements.in @@ -19,3 +19,4 @@ netaddr==0.9.0 networkx==2.6.3 pydot==1.4.2 redis==4.1.2 +requests==2.31.0 diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py index d7a983dc9..f11a60ade 100644 --- a/src/service/service/ServiceServiceServicerImpl.py +++ b/src/service/service/ServiceServiceServicerImpl.py @@ -34,6 +34,13 @@ from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory from .task_scheduler.TaskScheduler import TasksScheduler from .tools.GeodesicDistance import gps_distance +from common.tools.object_factory.Context import json_context_id +from common.tools.object_factory.Topology import json_topology_id +from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME +from common.proto.context_pb2 import Empty, TopologyId +from service.service.tools.OpticalTools import add_lightpath, delete_lightpath, adapt_reply, get_device_name_from_uuid, get_optical_band + + LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Service', 'RPC') @@ -241,7 +248,65 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): if len(service_with_uuids.service_endpoint_ids) >= num_expected_endpoints: pathcomp_request = PathCompRequest() pathcomp_request.services.append(service_with_uuids) # pylint: disable=no-member - + if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY: + context_id_x = json_context_id(DEFAULT_CONTEXT_NAME) + topology_id_x = json_topology_id( + DEFAULT_TOPOLOGY_NAME, context_id_x) + topology_details = context_client.GetTopologyDetails( + TopologyId(**topology_id_x)) + # devices = get_devices_in_topology(context_client, TopologyId(**topology_id_x), ContextId(**context_id_x)) + devices = topology_details.devices + context_uuid_x = topology_details.topology_id.context_id.context_uuid.uuid + topology_uuid_x = topology_details.topology_id.topology_uuid.uuid + devs = [] + ports = [] + for endpoint_id in service.service_endpoint_ids: + devs.append(endpoint_id.device_id.device_uuid.uuid) + ports.append(endpoint_id.endpoint_uuid.uuid) + src = devs[0] + dst = devs[1] + bidir = None + ob_band = None + bitrate = 100 + for constraint in service.service_constraints: + if "bandwidth" in constraint.custom.constraint_type: + bitrate = int(float(constraint.custom.constraint_value)) + elif "bidirectionality" in constraint.custom.constraint_type: + bidir = int(constraint.custom.constraint_value) + elif "optical-band-width" in constraint.custom.constraint_type: + ob_band = int(constraint.custom.constraint_value) + + + # to get the reply form the optical module + reply_txt = add_lightpath(src, dst, bitrate, bidir, ob_band) + + # reply with 2 transponders and 2 roadms + reply_json = json.loads(reply_txt) + optical_band_txt = "" + if "new_optical_band" in reply_json.keys(): + if reply_json["new_optical_band"] == 1: + if reply_json["parent_opt_band"]: + if "parent_opt_band" in reply_json.keys(): + parent_ob = reply_json["parent_opt_band"] + LOGGER.debug('Parent optical-band={}'.format(parent_ob)) + optical_band_txt = get_optical_band(parent_ob) + LOGGER.debug('optical-band details={}'.format(optical_band_txt)) + else: + LOGGER.debug('expected optical band not found') + else: + LOGGER.debug('expected optical band not found') + else: + LOGGER.debug('Using existing optical band') + else: + LOGGER.debug('Using existing optical band') + if reply_txt is not None: + optical_reply = adapt_reply(devices, _service, reply_json, context_uuid_x, topology_uuid_x, optical_band_txt) + LOGGER.debug('optical_reply={:s}'.format( + grpc_message_to_json_string(optical_reply))) + + tasks_scheduler.compose_from_pathcompreply( + optical_reply, is_delete=False) + if num_disjoint_paths is None or num_disjoint_paths in {0, 1}: pathcomp_request.shortest_path.Clear() # pylint: disable=no-member else: @@ -280,6 +345,30 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): context_client.RemoveService(request) return Empty() + if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY: + devs = [] + + context_id_x = json_context_id(DEFAULT_CONTEXT_NAME) + topology_id_x = json_topology_id( + DEFAULT_TOPOLOGY_NAME, context_id_x) + topology_details = context_client.GetTopologyDetails( + TopologyId(**topology_id_x)) + devices = topology_details.devices + for endpoint_id in service.service_endpoint_ids: + devs.append(endpoint_id.device_id.device_uuid.uuid) + src = get_device_name_from_uuid(devices, devs[0]) + dst = get_device_name_from_uuid(devices, devs[1]) + + bitrate = int( + float(service.service_constraints[0].custom.constraint_value)) + if len(service.service_config.config_rules) > 0: + c_rules_dict = json.loads( + service.service_config.config_rules[0].custom.resource_value) + flow_id = c_rules_dict["flow_id"] + + reply = delete_lightpath(flow_id, src, dst, bitrate) + + # Normal service # Feed TaskScheduler with this service and the sub-services and sub-connections related to this service. # TaskScheduler identifies inter-dependencies among them and produces a schedule of tasks (an ordered list of diff --git a/src/service/service/service_handlers/__init__.py b/src/service/service/service_handlers/__init__.py index eaf8f715a..f0628110f 100644 --- a/src/service/service/service_handlers/__init__.py +++ b/src/service/service/service_handlers/__init__.py @@ -26,6 +26,7 @@ from .p4.p4_service_handler import P4ServiceHandler from .tapi_tapi.TapiServiceHandler import TapiServiceHandler from .tapi_xr.TapiXrServiceHandler import TapiXrServiceHandler from .e2e_orch.E2EOrchestratorServiceHandler import E2EOrchestratorServiceHandler +from .oc.OCServiceHandler import OCServiceHandler SERVICE_HANDLERS = [ (L2NMEmulatedServiceHandler, [ @@ -100,4 +101,10 @@ SERVICE_HANDLERS = [ FilterFieldEnum.DEVICE_DRIVER : [DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE], } ]), + (OCServiceHandler, [ + { + FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY, + FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_OC, + } + ]) ] diff --git a/src/service/service/service_handlers/oc/ConfigRules.py b/src/service/service/service_handlers/oc/ConfigRules.py new file mode 100644 index 000000000..f4a46112e --- /dev/null +++ b/src/service/service/service_handlers/oc/ConfigRules.py @@ -0,0 +1,255 @@ +# 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. + +from typing import Dict, List +from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set +from service.service.service_handler_api.AnyTreeTools import TreeNode + +def setup_config_rules( + service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str, + service_settings : TreeNode, endpoint_settings : TreeNode +) -> List[Dict]: + + if service_settings is None: return [] + if endpoint_settings is None: return [] + + json_settings : Dict = service_settings.value + json_endpoint_settings : Dict = endpoint_settings.value + + service_short_uuid = service_uuid.split('-')[-1] + network_instance_name = '{:s}-NetInst'.format(service_short_uuid) + network_interface_desc = '{:s}-NetIf'.format(service_uuid) + network_subinterface_desc = '{:s}-NetSubIf'.format(service_uuid) + + mtu = json_settings.get('mtu', 1450 ) # 1512 + #address_families = json_settings.get('address_families', [] ) # ['IPV4'] + bgp_as = json_settings.get('bgp_as', 0 ) # 65000 + bgp_route_target = json_settings.get('bgp_route_target', '0:0') # 65000:333 + + #router_id = json_endpoint_settings.get('router_id', '0.0.0.0') # '10.95.0.10' + route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0' ) # '60001:801' + sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0 ) # 1 + vlan_id = json_endpoint_settings.get('vlan_id', 1 ) # 400 + address_ip = json_endpoint_settings.get('address_ip', '0.0.0.0') # '2.2.2.1' + address_prefix = json_endpoint_settings.get('address_prefix', 24 ) # 30 + if_subif_name = '{:s}.{:d}'.format(endpoint_name, vlan_id) + + json_config_rules = [ + json_config_rule_set( + '/network_instance[{:s}]'.format(network_instance_name), { + 'name': network_instance_name, 'description': network_interface_desc, 'type': 'L3VRF', + 'route_distinguisher': route_distinguisher, + #'router_id': router_id, 'address_families': address_families, + }), + json_config_rule_set( + '/interface[{:s}]'.format(endpoint_name), { + 'name': endpoint_name, 'description': network_interface_desc, 'mtu': mtu, + }), + json_config_rule_set( + '/interface[{:s}]/subinterface[{:d}]'.format(endpoint_name, sub_interface_index), { + 'name': endpoint_name, 'index': sub_interface_index, + 'description': network_subinterface_desc, 'vlan_id': vlan_id, + 'address_ip': address_ip, 'address_prefix': address_prefix, + }), + json_config_rule_set( + '/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), { + 'name': network_instance_name, 'id': if_subif_name, 'interface': endpoint_name, + 'subinterface': sub_interface_index, + }), + json_config_rule_set( + '/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), { + 'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP', 'as': bgp_as, + }), + json_config_rule_set( + '/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), { + 'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP', + 'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE', + }), + json_config_rule_set( + '/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format( + network_instance_name), { + 'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP', + 'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE', + }), + json_config_rule_set( + '/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), { + 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name), + }), + json_config_rule_set( + '/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format( + network_instance_name, bgp_route_target), { + 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name), + 'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target), + }), + json_config_rule_set( + '/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), { + 'policy_name': '{:s}_import'.format(network_instance_name), + }), + json_config_rule_set( + '/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format( + network_instance_name, '3'), { + 'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3', + 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name), + 'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE', + }), + json_config_rule_set( + # pylint: disable=duplicate-string-formatting-argument + '/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format( + network_instance_name, network_instance_name), { + 'name': network_instance_name, 'import_policy': '{:s}_import'.format(network_instance_name), + }), + json_config_rule_set( + '/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), { + 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name), + }), + json_config_rule_set( + '/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format( + network_instance_name, bgp_route_target), { + 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name), + 'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target), + }), + json_config_rule_set( + '/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), { + 'policy_name': '{:s}_export'.format(network_instance_name), + }), + json_config_rule_set( + '/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format( + network_instance_name, '3'), { + 'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3', + 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name), + 'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE', + }), + json_config_rule_set( + # pylint: disable=duplicate-string-formatting-argument + '/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format( + network_instance_name, network_instance_name), { + 'name': network_instance_name, 'export_policy': '{:s}_export'.format(network_instance_name), + }), + ] + + return json_config_rules + +def teardown_config_rules( + service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str, + service_settings : TreeNode, endpoint_settings : TreeNode +) -> List[Dict]: + + if service_settings is None: return [] + if endpoint_settings is None: return [] + + json_settings : Dict = service_settings.value + json_endpoint_settings : Dict = endpoint_settings.value + + #mtu = json_settings.get('mtu', 1450 ) # 1512 + #address_families = json_settings.get('address_families', [] ) # ['IPV4'] + #bgp_as = json_settings.get('bgp_as', 0 ) # 65000 + bgp_route_target = json_settings.get('bgp_route_target', '0:0') # 65000:333 + + #router_id = json_endpoint_settings.get('router_id', '0.0.0.0') # '10.95.0.10' + #route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0' ) # '60001:801' + sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0 ) # 1 + vlan_id = json_endpoint_settings.get('vlan_id', 1 ) # 400 + #address_ip = json_endpoint_settings.get('address_ip', '0.0.0.0') # '2.2.2.1' + #address_prefix = json_endpoint_settings.get('address_prefix', 24 ) # 30 + + if_subif_name = '{:s}.{:d}'.format(endpoint_name, vlan_id) + service_short_uuid = service_uuid.split('-')[-1] + network_instance_name = '{:s}-NetInst'.format(service_short_uuid) + #network_interface_desc = '{:s}-NetIf'.format(service_uuid) + #network_subinterface_desc = '{:s}-NetSubIf'.format(service_uuid) + + json_config_rules = [ + json_config_rule_delete( + '/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), { + 'name': network_instance_name, 'id': if_subif_name, + }), + json_config_rule_delete( + '/interface[{:s}]/subinterface[{:d}]'.format(endpoint_name, sub_interface_index), { + 'name': endpoint_name, 'index': sub_interface_index, + }), + json_config_rule_delete( + '/interface[{:s}]'.format(endpoint_name), { + 'name': endpoint_name, + }), + json_config_rule_delete( + '/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format( + network_instance_name), { + 'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP', + 'address_family': 'IPV4', + }), + json_config_rule_delete( + '/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), { + 'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP', + 'address_family': 'IPV4', + }), + json_config_rule_delete( + '/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), { + 'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP', + }), + json_config_rule_delete( + # pylint: disable=duplicate-string-formatting-argument + '/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format( + network_instance_name, network_instance_name), { + 'name': network_instance_name, + }), + json_config_rule_delete( + '/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format( + network_instance_name, '3'), { + 'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3', + }), + json_config_rule_delete( + '/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), { + 'policy_name': '{:s}_import'.format(network_instance_name), + }), + json_config_rule_delete( + '/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format( + network_instance_name, bgp_route_target), { + 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name), + 'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target), + }), + json_config_rule_delete( + '/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), { + 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name), + }), + json_config_rule_delete( + # pylint: disable=duplicate-string-formatting-argument + '/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format( + network_instance_name, network_instance_name), { + 'name': network_instance_name, + }), + json_config_rule_delete( + '/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format( + network_instance_name, '3'), { + 'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3', + }), + json_config_rule_delete( + '/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), { + 'policy_name': '{:s}_export'.format(network_instance_name), + }), + json_config_rule_delete( + '/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format( + network_instance_name, bgp_route_target), { + 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name), + 'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target), + }), + json_config_rule_delete( + '/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), { + 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name), + }), + json_config_rule_delete( + '/network_instance[{:s}]'.format(network_instance_name), { + 'name': network_instance_name + }), + ] + return json_config_rules diff --git a/src/service/service/service_handlers/oc/OCServiceHandler.py b/src/service/service/service_handlers/oc/OCServiceHandler.py new file mode 100644 index 000000000..89e9d23ed --- /dev/null +++ b/src/service/service/service_handlers/oc/OCServiceHandler.py @@ -0,0 +1,274 @@ +# 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 json, logging +from typing import Any, List, Optional, Tuple, Union +from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method +from common.proto.context_pb2 import ConfigRule, DeviceId, Service +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 +from .ConfigRules import setup_config_rules, teardown_config_rules + +from common.proto.context_pb2 import EndPointId +from .OCTools import convert_endpoints_to_flows, handle_flows_names +LOGGER = logging.getLogger(__name__) + +METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'l3nm_emulated'}) + +class OCServiceHandler(_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) + + + + + ''' + @metered_subclass_method(METRICS_POOL) + def SetEndpoint( + self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None + ) -> List[Union[bool, Exception]]: + + chk_type('endpoints', endpoints, list) + if len(endpoints) == 0: return [] + + service_uuid = self.__service.service_id.service_uuid.uuid + if self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)): + settings = self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)) + else: + settings = self.__settings_handler.get('/settings') + LOGGER.info("AAAAAAAAAAAAAAAAAAAA settings={}".format(settings)) + + settings = self.__settings_handler.get('/settings') + #new structure + #in, dev, out, topo(opt) + entries = List[Tuple[str, str, str Optional[str]]] + entry_tuple = device_uuid, endpoint_uuid, topology_uuid + entries.append(endpoint_id_tuple) + for i in range (1, len(endpoints)): + endpoint_x = endpoints[i] + dev_x = endpoint_x[0] + if_x = endpoint_x[1] + + + + + + results = [] + for endpoint in endpoints: + try: + device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) + + device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) + endpoint_name = endpoint_obj.name + + json_config_rules = setup_config_rules( + service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name, + settings, endpoint_settings) + LOGGER.info("Start configuring device %s",settings) + if (settings): + self.__task_executor.configure_optical_device(device_obj,settings) + if len(json_config_rules) > 0: + LOGGER.info("Start configuring device") + del device_obj.device_config.config_rules[:] + for json_config_rule in json_config_rules: + device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) + self.__task_executor.configure_optical_device(device_obj) + #self.__task_executor.configure_device(device_obj) + + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unable to SetEndpoint({:s})'.format(str(endpoint))) + results.append(e) + + return results + ''' + + + @metered_subclass_method(METRICS_POOL) + def SetEndpoint( + self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None + ) -> List[Union[bool, Exception]]: + + chk_type('endpoints', endpoints, list) + if len(endpoints) == 0: return [] + is_opticalband =False + #service_uuid = self.__service.service_id.service_uuid.uuid + settings=None + if self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)): + is_opticalband=True + settings = self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)) + else: + settings = self.__settings_handler.get('/settings') + + LOGGER.debug("Andrea111 settings={}".format(settings)) + # settings = self.__settings_handler.get('/settings') + + #flow is the new variable that stores input-output relationship + + flows = convert_endpoints_to_flows(endpoints) + #handled_flows=handle_flows_names(flows=flows,task_executor=self.__task_executor) + LOGGER.debug("AndreaXXX dict of flows= {}".format(flows)) + #LOGGER.info("Handled Flows %s",handled_flows) + + results = [] + #new cycle for setting optical devices + for device_uuid in flows.keys(): + try: + dev_flows = flows[device_uuid] + device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + LOGGER.debug("Andrea567 device_obj={}".format(device_obj)) + ''' + #to be imported in the device handler + endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) + endpoint_name = endpoint_obj.name + ''' + if (settings): + LOGGER.debug("Andrea234 settings={}".format(settings)) + self.__task_executor.configure_optical_device(device_obj, settings, dev_flows, is_opticalband) + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unable to configure Device({:s})'.format(str(device_uuid))) + results.append(e) + + ''' + for endpoint in endpoints: + try: + device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) + + device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) + endpoint_name = endpoint_obj.name + + # json_config_rules = setup_config_rules( + # service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name, + # settings, endpoint_settings) + + if (settings): + LOGGER.debug("Andrea234 settings={}".format(settings)) + self.__task_executor.configure_optical_device(device_obj,settings,handled_flows,is_opticalband) + #we don't use config_rules + # if len(json_config_rules) > 0: + # LOGGER.debug("VBNMHGStart configuring device") + # del device_obj.device_config.config_rules[:] + # for json_config_rule in json_config_rules: + # device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) + # self.__task_executor.configure_optical_device(device_obj) + #self.__task_executor.configure_device(device_obj) + + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unable to SetEndpoint({:s})'.format(str(endpoint))) + results.append(e) + ''' + + return results + + @metered_subclass_method(METRICS_POOL) + def DeleteEndpoint( + self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None + ) -> List[Union[bool, Exception]]: + chk_type('endpoints', endpoints, list) + if len(endpoints) == 0: return [] + + service_uuid = self.__service.service_id.service_uuid.uuid + settings = self.__settings_handler.get('/settings') + + results = [] + for endpoint in endpoints: + try: + device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) + + device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) + endpoint_name = endpoint_obj.name + + json_config_rules = teardown_config_rules( + service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name, + settings, endpoint_settings) + + if len(json_config_rules) > 0: + del device_obj.device_config.config_rules[:] + for json_config_rule in json_config_rules: + device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) + self.__task_executor.configure_device(device_obj) + + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unable to DeleteEndpoint({:s})'.format(str(endpoint))) + results.append(e) + + return results + + @metered_subclass_method(METRICS_POOL) + def SetConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + chk_type('constraints', constraints, list) + if len(constraints) == 0: return [] + + msg = '[SetConstraint] Method not implemented. Constraints({:s}) are being ignored.' + LOGGER.warning(msg.format(str(constraints))) + return [True for _ in range(len(constraints))] + + @metered_subclass_method(METRICS_POOL) + def DeleteConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + chk_type('constraints', constraints, list) + if len(constraints) == 0: return [] + + msg = '[DeleteConstraint] Method not implemented. Constraints({:s}) are being ignored.' + LOGGER.warning(msg.format(str(constraints))) + return [True for _ in range(len(constraints))] + + @metered_subclass_method(METRICS_POOL) + def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + chk_type('resources', resources, list) + if len(resources) == 0: return [] + + results = [] + for resource in resources: + try: + resource_value = json.loads(resource[1]) + self.__settings_handler.set(resource[0], resource_value) + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unable to SetConfig({:s})'.format(str(resource))) + results.append(e) + + return results + + @metered_subclass_method(METRICS_POOL) + def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + chk_type('resources', resources, list) + if len(resources) == 0: return [] + + results = [] + for resource in resources: + try: + self.__settings_handler.delete(resource[0]) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unable to DeleteConfig({:s})'.format(str(resource))) + results.append(e) + + return results diff --git a/src/service/service/service_handlers/oc/OCTools.py b/src/service/service/service_handlers/oc/OCTools.py new file mode 100644 index 000000000..c8bddefb9 --- /dev/null +++ b/src/service/service/service_handlers/oc/OCTools.py @@ -0,0 +1,143 @@ +# 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. +from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching +from typing import Dict, Any, List, Optional, Tuple +import logging +from common.proto.context_pb2 import ConfigRule, DeviceId, Service +from common.tools.object_factory.Device import json_device_id +log = logging.getLogger(__name__) + +#def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]])->Dict[str: List[Tuple[str, str]]]: + +def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]])->Dict: + #entries = List[Tuple[str, str, str, Optional[str]]] + #entries = Dict[str: List[Tuple[str, str]]] + entries = {} + #tuple is in, out + end = len(endpoints) + i = 0 + bidir = 0 + log.debug("end={}".format(end)) + while(i < end): + endpoint = endpoints[i] + device_uuid, endpoint_uuid = endpoint[0:2] + log.debug("current OCTools step {}, {}, {}".format(i, device_uuid, endpoint_uuid)) + if device_uuid not in entries.keys(): + entries[device_uuid] = [] + if i == 0: + entry_tuple = "0", endpoint_uuid + entries[device_uuid].append(entry_tuple) + next_endpoint = endpoints[i+1] + next_device_uuid, next_endpoint_uuid = next_endpoint[0:2] + if next_device_uuid == device_uuid: + bidir = 1 + log.debug("connection is bidirectional") + entry_tuple = next_endpoint_uuid, "0" + entries[device_uuid].append(entry_tuple) + i = i + 1 + else: + log.debug("connection is unidirectional") + else: + if not bidir: + if i == end-1: + #is the last node + entry_tuple = endpoint_uuid, "0" + entries[device_uuid].append(entry_tuple) + else: + #it is a transit node + next_endpoint = endpoints[i+1] + next_device_uuid, next_endpoint_uuid = next_endpoint[0:2] + if next_device_uuid == device_uuid: + entry_tuple = endpoint_uuid, next_endpoint_uuid + entries[device_uuid].append(entry_tuple) + i = i + 1 + log.debug("current OCTools step {}, {}, {}".format(i, next_device_uuid, device_uuid)) + else: + log.debug("ERROR in unidirectional connection 4") + return {} + if bidir: + log.debug("Ocheck i {}, {}, {}".format(i, i+1, end-1)) + if i + 1 == end-1: + log.debug("current OCTools step {}, {}, {}".format(i, device_uuid, endpoint_uuid)) + #is the last node + entry_tuple = endpoint_uuid, "0" + entries[device_uuid].append(entry_tuple) + next_endpoint = endpoints[i+1] + log.debug("OCTools i+1 step {}, {}, {}".format(i+1, next_device_uuid, device_uuid)) + + next_device_uuid, next_endpoint_uuid = next_endpoint[0:2] + if next_device_uuid == device_uuid: + entry_tuple = "0", next_endpoint_uuid + entries[device_uuid].append(entry_tuple) + i = i + 1 + else: + log.debug("ERROR in bidirectional connection 2") + return entries + else: + log.debug("OCTools i+1+2+3 step {}, {}, {}".format(i+1, next_device_uuid, device_uuid)) + #i+1 + next_endpoint = endpoints[i+1] + next_device_uuid, next_endpoint_uuid = next_endpoint[0:2] + if next_device_uuid == device_uuid: + entry_tuple = endpoint_uuid, next_endpoint_uuid + entries[device_uuid].append(entry_tuple) + else: + log.debug("ERROR in bidirectional connection 3") + log.debug("{}, {}, {}".format(i, next_device_uuid, device_uuid)) + return entries + #i+2 + next_2_endpoint = endpoints[i+2] + next_2_device_uuid, next_2_endpoint_uuid = next_2_endpoint[0:2] + #i+3 + next_3_endpoint = endpoints[i+3] + next_3_device_uuid, next_3_endpoint_uuid = next_3_endpoint[0:2] + if next_2_device_uuid == next_3_device_uuid and next_3_device_uuid == device_uuid: + entry_tuple = next_2_endpoint_uuid, next_3_endpoint_uuid + entries[device_uuid].append(entry_tuple) + i = i + 3 + else: + log.debug("ERROR in bidirection connection 4") + return {} + i = i + 1 + return entries + + +def get_device_endpint_name (endpoint_uuid:str,device_uuid:str,task_executor)->Tuple: + + + + device_obj = task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + endpoint_name = endpoint_obj.name + + return (device_obj.name,endpoint_name) + +def handle_flows_names (task_executor,flows:dict)->Dict : + new_flows={} + for index,( device_uuid_key , device_endpoints_list) in enumerate(flows.items()): + for endpoint_tupple in device_endpoints_list: + source_port=None + destination_port=None + device_name="" + source_endpoint,destination_endpoint =endpoint_tupple + if (source_endpoint !='0'): + if get_device_endpint_name(source_endpoint,device_uuid_key,task_executor) is not None: + device_name,source_port=get_device_endpint_name(source_endpoint,device_uuid_key,task_executor) + if (destination_endpoint !='0'): + if get_device_endpint_name(destination_endpoint,device_uuid_key,task_executor) is not None: + device_name,destination_port=get_device_endpint_name(destination_endpoint,device_uuid_key,task_executor) + if (device_name not in new_flows): + new_flows[device_name]=[] + new_flows[device_name].append((source_port,destination_port)) + return new_flows \ No newline at end of file diff --git a/src/service/service/service_handlers/oc/__init__.py b/src/service/service/service_handlers/oc/__init__.py new file mode 100644 index 000000000..1549d9811 --- /dev/null +++ b/src/service/service/service_handlers/oc/__init__.py @@ -0,0 +1,14 @@ +# 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. + diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py index ae0f1be7d..3718c01f4 100644 --- a/src/service/service/task_scheduler/TaskExecutor.py +++ b/src/service/service/task_scheduler/TaskExecutor.py @@ -16,7 +16,7 @@ import logging #, json from enum import Enum from typing import TYPE_CHECKING, Any, Dict, Optional, Union from common.method_wrappers.ServiceExceptions import NotFoundException -from common.proto.context_pb2 import Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId +from common.proto.context_pb2 import Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId,MyConfig,MyConfigId from common.tools.context_queries.Connection import get_connection_by_id from common.tools.context_queries.Device import get_device from common.tools.context_queries.Service import get_service_by_id @@ -108,10 +108,74 @@ class TaskExecutor: return device def configure_device(self, device : Device) -> None: + self._context_client.SelectMyConfig() device_key = get_device_key(device.device_id) self._device_client.ConfigureDevice(device) self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device) - + + # New function Andrea for Optical Devices + def configure_optical_device(self,device:Device,settings:str,flows:list,is_opticalband:bool): + + + device_key = get_device_key(device.device_id) + myid=MyConfigId() + myid.myconfig_uuid=device.device_id.device_uuid.uuid + myConfig=MyConfig() + + setting =settings.value if settings else "" + + new_config={} + try: + result=self._context_client.SelectMyConfig(myid) + new_config=eval(result.config) + LOGGER.info("result %s",result) + if result is not None : + + new_config["new_config"]=setting + new_config["is_opticalband"]=is_opticalband + new_config["flow"]=flows + result.config = str(new_config) + myConfig.CopyFrom(result) + + self._device_client.ConfigureOpticalDevice(myConfig) + + self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device) + except Exception as e: + LOGGER.debug("error in config my config %s",e) + + ''' + # For Optical Devices + def configure_optical_device (self,device:Device,settings:str,flows:dict,is_opticalband:bool) : + + + device_key = get_device_key(device.device_id) + myid=MyConfigId() + myid.myconfig_uuid=device.device_id.device_uuid.uuid + myConfig=MyConfig() + + setting =settings.value if settings else "" + + new_config={} + try: + result=self._context_client.SelectMyConfig(myid) + new_config=eval(result.config) + + if result is not None : + + new_config["new_config"]=setting + new_config["is_opticalband"]=is_opticalband + new_config["flow"]=flows + result.config = str(new_config) + myConfig.CopyFrom(result) + + self._device_client.ConfigureOpticalDevice(myConfig) + + self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device) + except Exception as e: + LOGGER.debug("error in config my config %s",e) + ''' + + def get_device_controller(self, device : Device) -> Optional[Device]: #json_controller = None #for config_rule in device.device_config.config_rules: diff --git a/src/service/service/tools/OpticalTools.py b/src/service/service/tools/OpticalTools.py new file mode 100644 index 000000000..227be2765 --- /dev/null +++ b/src/service/service/tools/OpticalTools.py @@ -0,0 +1,290 @@ +# 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 json +import requests +import uuid +from common.Constants import * +from typing import Dict, List +from common.proto.context_pb2 import( + Device, DeviceId, Service, Connection, EndPointId, TopologyId, ContextId, Uuid, ConfigRule, ConfigActionEnum, ConfigRule_Custom) +from common.proto.pathcomp_pb2 import PathCompReply +from typing import Dict, List, Optional, Tuple + +from context.service.database.uuids.EndPoint import endpoint_get_uuid + + +from service.service.tools.replies import reply_uni_txt, optical_band_uni_txt, reply_bid_txt, optical_band_bid_txt + +log = logging.getLogger(__name__) + +testing = True + + +def get_uuids_from_names(devices: List[Device], device_name: str, port_name: str): + + device_uuid = "" + port_uuid = "" + for device in devices: + if device.name == device_name: + + device_uuid = device.device_id.device_uuid.uuid + + for ep in device.device_endpoints: + if ep.name == port_name: + port_uuid = ep.endpoint_id.endpoint_uuid.uuid + + return device_uuid, port_uuid + return "", "" + + +def get_names_from_uuids(devices: List[Device], device_uuid: str, port_uuid: str): + device_name = "" + port_name = "" + for device in devices: + if device.device_id.device_uuid.uuid == device_uuid: + device_name = device.name + for ep in device.device_endpoints: + if ep.endpoint_id.endpoint_uuid.uuid == port_uuid: + port_name = ep.name + return device_name, port_name + return "", "" + +def get_device_name_from_uuid(devices: List[Device], device_uuid: str): + device_name = "" + + for device in devices: + if device.device_id.device_uuid.uuid == device_uuid: + device_name = device.name + return device_name + return "" + + +def add_lightpath(src, dst, bitrate, bidir, ob_band) -> str: + if not testing: + urlx = "" + headers = {"Content-Type": "application/json"} + if ob_band is None: + if bidir is None: + bidir = 1 + urlx = "http://{}:{}/OpticalTFS/AddFlexLightpath/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, src, dst, bitrate, bidir) + else: + if bidir is None: + bidir = 1 + urlx = "http://{}:{}/OpticalTFS/AddFlexLightpath/{}/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, src, dst, bitrate, bidir, ob_band) + r = requests.put(urlx, headers=headers) + reply = r.text + return reply + else: + if bidir is not None: + if bidir == 0: + return reply_uni_txt + return reply_bid_txt + + +def get_optical_band(idx) -> str: + if not testing: + urlx = "http://{}:{}/OpticalTFS/GetOpticalBand/{}".format(OPTICAL_IP, OPTICAL_PORT, idx) + headers = {"Content-Type": "application/json"} + r = requests.get(urlx, headers=headers) + reply = r.text + return reply + else: + if str(idx) == "1": + return optical_band_bid_txt + else: + return optical_band_uni_txt + + +def delete_lightpath(flow_id, src, dst, bitrate) -> str: + reply = "200" + if not testing: + urlx = "http://{}:{}/OpticalTFS/DelLightpath/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, flow_id, src, dst, bitrate) + + headers = {"Content-Type": "application/json"} + r = requests.delete(urlx, headers=headers) + reply = r.text + return reply + + +def get_lightpaths() -> str: + urlx = "http://{}:{}/OpticalTFS/GetLightpaths".format(OPTICAL_IP, OPTICAL_PORT) + + headers = {"Content-Type": "application/json"} + r = requests.get(urlx, headers=headers) + reply = r.text + return reply + + +def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_band_txt) -> PathCompReply: + opt_reply = PathCompReply() + topo = TopologyId(context_id=ContextId(context_uuid=Uuid(uuid=context_id)),topology_uuid=Uuid(uuid=topology_id)) + #add optical band connection first + rules_ob= [] + ob_id = 0 + if optical_band_txt != "": + ob_json = json.loads(optical_band_txt) + ob = ob_json + connection_ob = add_connection_to_reply(opt_reply) + uuuid_x = str(uuid.uuid4()) + connection_ob.connection_id.connection_uuid.uuid = uuuid_x + connection_ob.service_id.CopyFrom(service.service_id) + + ob_id = ob["optical_band_id"] + obt = ob["band_type"] + if obt == "l_slots": + band_type = "L_BAND" + elif obt == "s_slots": + band_type = "S_BAND" + else: + band_type = "C_BAND" + + freq = ob["freq"] + bx = ob["band"] + lf = int(int(freq)-int(bx/2)) + uf = int(int(freq)+int(bx/2)) + val_ob = {"band_type": band_type, "low-freq": lf, "up-freq": uf, "frequency": freq, "band": bx, "ob_id": ob_id} + rules_ob.append(ConfigRule_Custom(resource_key="/settings-ob_{}".format(uuuid_x), resource_value=json.dumps(val_ob))) + bidir_ob = ob["bidir"] + for devxb in ob["flows"].keys(): + log.debug("optical-band device {}".format(devxb)) + in_end_point_b = "0" + out_end_point_b = "0" + in_end_point_f = ob["flows"][devxb]["f"]["in"] + out_end_point_f = ob["flows"][devxb]["f"]["out"] + log.debug("optical-band ports {}, {}".format(in_end_point_f, out_end_point_f)) + if bidir_ob: + in_end_point_b = ob["flows"][devxb]["b"]["in"] + out_end_point_b = ob["flows"][devxb]["b"]["out"] + log.debug("optical-band ports {}, {}".format(in_end_point_b, out_end_point_b)) + #if (in_end_point_f == "0" or out_end_point_f == "0") and (in_end_point_b == "0" or out_end_point_b == "0"): + if in_end_point_f != "0": + d_ob, p_ob = get_uuids_from_names(devices, devxb, in_end_point_f) + if d_ob != "" and p_ob != "": + end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob)) + connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) + else: + log.INFO("no map device port for device {} port {}".format(devxb, in_end_point_f)) + + if out_end_point_f != "0": + d_ob, p_ob = get_uuids_from_names(devices, devxb, out_end_point_f) + if d_ob != "" and p_ob != "": + end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob)) + connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) + else: + log.INFO("no map device port for device {} port {}".format(devxb, out_end_point_f)) + if in_end_point_b != "0": + d_ob, p_ob = get_uuids_from_names(devices, devxb, in_end_point_b) + if d_ob != "" and p_ob != "": + end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob)) + connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) + else: + log.INFO("no map device port for device {} port {}".format(devxb, in_end_point_b)) + if out_end_point_b != "0": + d_ob, p_ob = get_uuids_from_names(devices, devxb, out_end_point_b) + if d_ob != "" and p_ob != "": + end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob)) + connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) + else: + log.INFO("no map device port for device {} port {}".format(devxb, out_end_point_b)) + log.debug("optical-band connection {}".format(connection_ob)) + r = reply_json + bidir_f = r["bidir"] + connection_f = add_connection_to_reply(opt_reply) + connection_f.connection_id.connection_uuid.uuid = str(uuid.uuid4()) + connection_f.service_id.CopyFrom(service.service_id) + for devx in r["flows"].keys(): + log.debug("lightpath device {}".format(devx)) + in_end_point_b = "0" + out_end_point_b = "0" + + in_end_point_f = r["flows"][devx]["f"]["in"] + out_end_point_f = r["flows"][devx]["f"]["out"] + log.debug("lightpath ports {}, {}".format(in_end_point_f, out_end_point_f)) + if bidir_f: + in_end_point_b = r["flows"][devx]["b"]["in"] + out_end_point_b = r["flows"][devx]["b"]["out"] + log.debug("lightpath ports {}, {}".format(in_end_point_b, out_end_point_b)) + if in_end_point_f != "0": + d, p = get_uuids_from_names(devices, devx, in_end_point_f) + if d != "" and p != "": + end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p)) + connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) + else: + log.INFO("no map device port for device {} port {}".format(devx, in_end_point_f)) + if out_end_point_f != "0": + d, p = get_uuids_from_names(devices, devx, out_end_point_f) + if d != "" and p != "": + end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p)) + connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) + else: + log.INFO("no map device port for device {} port {}".format(devx, out_end_point_f)) + if in_end_point_b != "0": + d, p = get_uuids_from_names(devices, devx, in_end_point_b) + if d != "" and p != "": + end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p)) + connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) + else: + log.INFO("no map device port for device {} port {}".format(devx, in_end_point_b)) + if out_end_point_b != "0": + d, p = get_uuids_from_names(devices, devx, out_end_point_b) + if d != "" and p != "": + end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p)) + connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) + else: + log.INFO("no map device port for device {} port {}".format(devx, out_end_point_b)) + #check that list of endpoints is not empty + if len(connection_ob.path_hops_endpoint_ids) == 0: + log.debug("deleting empty optical-band connection") + opt_reply.connections.remove(connection_ob) + + #inizialize custom optical parameters + band = r["band"] + op_mode = r["op-mode"] + frequency = r["freq"] + flow_id = r["flow_id"] + r_type = r["band_type"] + if r_type == "l_slots": + band_type = "L_BAND" + elif r_type == "s_slots": + band_type = "S_BAND" + else: + band_type = "C_BAND" + + if ob_id is not 0: + val = {"frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "ob_id": ob_id, "band_type": band_type,} + else: + val = {"frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "band_type": band_type,} + custom_rule = ConfigRule_Custom(resource_key="/settings", resource_value=json.dumps(val)) + rule = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=custom_rule) + service.service_config.config_rules.add().CopyFrom(rule) + log.debug("optical-band rules {}".format(rules_ob)) + if len(rules_ob) > 0: + for rulex in rules_ob: + rule_ob = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=rulex) + service.service_config.config_rules.add().CopyFrom(rule_ob) + + opt_reply.services.add().CopyFrom(service) + + return opt_reply + +def add_service_to_reply(reply : PathCompReply, service : Service)-> Service: + service_x = reply.services.add() + service_x.CopyFrom(service) + return service_x + +def add_connection_to_reply(reply : PathCompReply)-> Connection: + conn = reply.connections.add() + return conn diff --git a/src/service/service/tools/replies.py b/src/service/service/tools/replies.py new file mode 100644 index 000000000..5fcb393e9 --- /dev/null +++ b/src/service/service/tools/replies.py @@ -0,0 +1,321 @@ +# 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. +# + +reply_bid_txt = """ +{ + "flow_id": 1, + "src": "T1", + "dst": "T2", + "bitrate": 100, + "bidir": 1, + "flows": { + "T1": { + "f": { + "in": "0", + "out": "1" + }, + "b": { + "in": "1", + "out": "0" + } + }, + "R1": { + "f": { + "in": "12", + "out": "3" + }, + "b": { + "in": "13", + "out": "2" + } + }, + "R2": { + "f": { + "in": "14", + "out": "5" + }, + "b": { + "in": "15", + "out": "4" + } + }, + "T2": { + "f": { + "in": "6", + "out": "0" + }, + "b": { + "in": "0", + "out": "6" + } + } + }, + "band_type": "c_slots", + "slots": [ + 1, + 2, + 3, + 4 + ], + "fiber_forward": { + "T1-R1": "M1", + "R2-T2": "S1" + }, + "fiber_backward": { + "R1-T1": "S1", + "T2-R2": "M1" + }, + "op-mode": 1, + "n_slots": 4, + "links": [ + "T1-R1", + "R2-T2" + ], + "path": [ + "R1", + "R2" + ], + "band": 50000, + "freq": 192031250, + "is_active": true, + "parent_opt_band": 1, + "new_optical_band": 1 +} + """ + +optical_band_bid_txt = """ +{ + "optical_band_id": 1, + "bidir": 1, + "src": "R1", + "dst": "R2", + "flows": { + "R1": { + "f": { + "in": "0", + "out": "3" + }, + "b": { + "in": "13", + "out": "0" + } + }, + "R2": { + "f": { + "in": "14", + "out": "0" + }, + "b": { + "in": "0", + "out": "4" + } + } + }, + "band_type": "c_slots", + "fiber_forward": { + "R1-R2": "d1-1" + }, + "fiber_backward": { + "R2-R1": "d1-1" + }, + "op-mode": 0, + "n_slots": 16, + "links": [ + "R1-R2" + ], + "path": [ + "R1", + "R2" + ], + "band": 200000, + "freq": 192106250, + "is_active": true, + "src_port": "101", + "dst_port": "201", + "rev_dst_port": "201", + "rev_src_port": "101", + "c_slots": [ + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "served_lightpaths": [ + 1 + ] +} + """ + +reply_uni_txt = """ +{ + "flow_id": 2, + "src": "T1", + "dst": "T2", + "bitrate": 100, + "bidir": 0, + "flows": { + "T1": { + "f": { + "in": "0", + "out": "1" + }, + "b": { + "in": "1", + "out": "0" + } + }, + "R1": { + "f": { + "in": "12", + "out": "3" + }, + "b": { + "in": "13", + "out": "2" + } + }, + "R2": { + "f": { + "in": "14", + "out": "5" + }, + "b": { + "in": "15", + "out": "4" + } + }, + "T2": { + "f": { + "in": "6", + "out": "0" + }, + "b": { + "in": "0", + "out": "6" + } + } + }, + "band_type": "c_slots", + "slots": [ + 1, + 2, + 3, + 4 + ], + "fiber_forward": { + "T1-R1": "M1", + "R2-T2": "S1" + }, + "fiber_backward": { + "R1-T1": "S1", + "T2-R2": "M1" + }, + "op-mode": 1, + "n_slots": 4, + "links": [ + "T1-R1", + "R2-T2" + ], + "path": [ + "R1", + "R2" + ], + "band": 50000, + "freq": 192031250, + "is_active": true, + "parent_opt_band": 2, + "new_optical_band": 1 +} + """ + +optical_band_uni_txt = """ +{ + "optical_band_id": 2, + "bidir": 0, + "src": "R1", + "dst": "R2", + "flows": { + "R1": { + "f": { + "in": "0", + "out": "3" + }, + "b": { + "in": "13", + "out": "0" + } + }, + "R2": { + "f": { + "in": "14", + "out": "0" + }, + "b": { + "in": "0", + "out": "4" + } + } + }, + "band_type": "c_slots", + "fiber_forward": { + "R1-R2": "d1-1" + }, + "fiber_backward": { + "R2-R1": "d1-1" + }, + "op-mode": 0, + "n_slots": 16, + "links": [ + "R1-R2" + ], + "path": [ + "R1", + "R2" + ], + "band": 200000, + "freq": 192106250, + "is_active": true, + "src_port": "101", + "dst_port": "201", + "rev_dst_port": "201", + "rev_src_port": "101", + "c_slots": [ + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "served_lightpaths": [ + 2 + ] +} + """ + -- GitLab From 9f4f27cdccb3ec947c04f6aaa9166df8f52cb406 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Tue, 20 Feb 2024 15:57:07 +0000 Subject: [PATCH 2/2] Service component: - Pre-merge cleanup --- src/service/requirements.in | 2 +- .../service/ServiceServiceServicerImpl.py | 107 ++++++------- .../service_handlers/oc/OCServiceHandler.py | 144 ++---------------- .../service/service_handlers/oc/OCTools.py | 9 +- .../service/task_scheduler/TaskExecutor.py | 81 +++------- 5 files changed, 92 insertions(+), 251 deletions(-) diff --git a/src/service/requirements.in b/src/service/requirements.in index ea4d41cc4..86720da19 100644 --- a/src/service/requirements.in +++ b/src/service/requirements.in @@ -19,4 +19,4 @@ netaddr==0.9.0 networkx==2.6.3 pydot==1.4.2 redis==4.1.2 -requests==2.31.0 +requests==2.27.1 diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py index f11a60ade..b06295dee 100644 --- a/src/service/service/ServiceServiceServicerImpl.py +++ b/src/service/service/ServiceServiceServicerImpl.py @@ -248,65 +248,66 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): if len(service_with_uuids.service_endpoint_ids) >= num_expected_endpoints: pathcomp_request = PathCompRequest() pathcomp_request.services.append(service_with_uuids) # pylint: disable=no-member + if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY: - context_id_x = json_context_id(DEFAULT_CONTEXT_NAME) - topology_id_x = json_topology_id( - DEFAULT_TOPOLOGY_NAME, context_id_x) - topology_details = context_client.GetTopologyDetails( - TopologyId(**topology_id_x)) - # devices = get_devices_in_topology(context_client, TopologyId(**topology_id_x), ContextId(**context_id_x)) - devices = topology_details.devices - context_uuid_x = topology_details.topology_id.context_id.context_uuid.uuid - topology_uuid_x = topology_details.topology_id.topology_uuid.uuid - devs = [] - ports = [] - for endpoint_id in service.service_endpoint_ids: - devs.append(endpoint_id.device_id.device_uuid.uuid) - ports.append(endpoint_id.endpoint_uuid.uuid) - src = devs[0] - dst = devs[1] - bidir = None - ob_band = None - bitrate = 100 - for constraint in service.service_constraints: - if "bandwidth" in constraint.custom.constraint_type: - bitrate = int(float(constraint.custom.constraint_value)) - elif "bidirectionality" in constraint.custom.constraint_type: - bidir = int(constraint.custom.constraint_value) - elif "optical-band-width" in constraint.custom.constraint_type: - ob_band = int(constraint.custom.constraint_value) - - - # to get the reply form the optical module - reply_txt = add_lightpath(src, dst, bitrate, bidir, ob_band) - - # reply with 2 transponders and 2 roadms - reply_json = json.loads(reply_txt) - optical_band_txt = "" - if "new_optical_band" in reply_json.keys(): - if reply_json["new_optical_band"] == 1: - if reply_json["parent_opt_band"]: - if "parent_opt_band" in reply_json.keys(): - parent_ob = reply_json["parent_opt_band"] - LOGGER.debug('Parent optical-band={}'.format(parent_ob)) - optical_band_txt = get_optical_band(parent_ob) - LOGGER.debug('optical-band details={}'.format(optical_band_txt)) - else: - LOGGER.debug('expected optical band not found') + context_id_x = json_context_id(DEFAULT_CONTEXT_NAME) + topology_id_x = json_topology_id( + DEFAULT_TOPOLOGY_NAME, context_id_x) + topology_details = context_client.GetTopologyDetails( + TopologyId(**topology_id_x)) + devices = topology_details.devices + context_uuid_x = topology_details.topology_id.context_id.context_uuid.uuid + topology_uuid_x = topology_details.topology_id.topology_uuid.uuid + devs = [] + ports = [] + for endpoint_id in service.service_endpoint_ids: + devs.append(endpoint_id.device_id.device_uuid.uuid) + ports.append(endpoint_id.endpoint_uuid.uuid) + src = devs[0] + dst = devs[1] + bidir = None + ob_band = None + bitrate = 100 + for constraint in service.service_constraints: + if "bandwidth" in constraint.custom.constraint_type: + bitrate = int(float(constraint.custom.constraint_value)) + elif "bidirectionality" in constraint.custom.constraint_type: + bidir = int(constraint.custom.constraint_value) + elif "optical-band-width" in constraint.custom.constraint_type: + ob_band = int(constraint.custom.constraint_value) + + # to get the reply form the optical module + reply_txt = add_lightpath(src, dst, bitrate, bidir, ob_band) + + # reply with 2 transponders and 2 roadms + reply_json = json.loads(reply_txt) + optical_band_txt = "" + if "new_optical_band" in reply_json.keys(): + if reply_json["new_optical_band"] == 1: + if reply_json["parent_opt_band"]: + if "parent_opt_band" in reply_json.keys(): + parent_ob = reply_json["parent_opt_band"] + LOGGER.debug('Parent optical-band={}'.format(parent_ob)) + optical_band_txt = get_optical_band(parent_ob) + LOGGER.debug('optical-band details={}'.format(optical_band_txt)) else: LOGGER.debug('expected optical band not found') else: - LOGGER.debug('Using existing optical band') + LOGGER.debug('expected optical band not found') else: LOGGER.debug('Using existing optical band') - if reply_txt is not None: - optical_reply = adapt_reply(devices, _service, reply_json, context_uuid_x, topology_uuid_x, optical_band_txt) - LOGGER.debug('optical_reply={:s}'.format( - grpc_message_to_json_string(optical_reply))) - - tasks_scheduler.compose_from_pathcompreply( - optical_reply, is_delete=False) - + else: + LOGGER.debug('Using existing optical band') + if reply_txt is not None: + optical_reply = adapt_reply( + devices, _service, reply_json, context_uuid_x, topology_uuid_x, optical_band_txt + ) + LOGGER.debug('optical_reply={:s}'.format( + grpc_message_to_json_string(optical_reply))) + + tasks_scheduler.compose_from_pathcompreply( + optical_reply, is_delete=False) + if num_disjoint_paths is None or num_disjoint_paths in {0, 1}: pathcomp_request.shortest_path.Clear() # pylint: disable=no-member else: diff --git a/src/service/service/service_handlers/oc/OCServiceHandler.py b/src/service/service/service_handlers/oc/OCServiceHandler.py index 89e9d23ed..8ae426393 100644 --- a/src/service/service/service_handlers/oc/OCServiceHandler.py +++ b/src/service/service/service_handlers/oc/OCServiceHandler.py @@ -15,20 +15,19 @@ import json, logging from typing import Any, List, Optional, Tuple, Union from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method -from common.proto.context_pb2 import ConfigRule, DeviceId, Service +from common.proto.context_pb2 import ConfigRule, DeviceId, EndPointId, Service 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 -from .ConfigRules import setup_config_rules, teardown_config_rules - -from common.proto.context_pb2 import EndPointId +#from .ConfigRules import setup_config_rules, teardown_config_rules from .OCTools import convert_endpoints_to_flows, handle_flows_names + LOGGER = logging.getLogger(__name__) -METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'l3nm_emulated'}) +METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'oc'}) class OCServiceHandler(_ServiceHandler): def __init__( # pylint: disable=super-init-not-called @@ -38,73 +37,6 @@ class OCServiceHandler(_ServiceHandler): self.__task_executor = task_executor self.__settings_handler = SettingsHandler(service.service_config, **settings) - - - - ''' - @metered_subclass_method(METRICS_POOL) - def SetEndpoint( - self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None - ) -> List[Union[bool, Exception]]: - - chk_type('endpoints', endpoints, list) - if len(endpoints) == 0: return [] - - service_uuid = self.__service.service_id.service_uuid.uuid - if self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)): - settings = self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)) - else: - settings = self.__settings_handler.get('/settings') - LOGGER.info("AAAAAAAAAAAAAAAAAAAA settings={}".format(settings)) - - settings = self.__settings_handler.get('/settings') - #new structure - #in, dev, out, topo(opt) - entries = List[Tuple[str, str, str Optional[str]]] - entry_tuple = device_uuid, endpoint_uuid, topology_uuid - entries.append(endpoint_id_tuple) - for i in range (1, len(endpoints)): - endpoint_x = endpoints[i] - dev_x = endpoint_x[0] - if_x = endpoint_x[1] - - - - - - results = [] - for endpoint in endpoints: - try: - device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) - - device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) - endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) - endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) - endpoint_name = endpoint_obj.name - - json_config_rules = setup_config_rules( - service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name, - settings, endpoint_settings) - LOGGER.info("Start configuring device %s",settings) - if (settings): - self.__task_executor.configure_optical_device(device_obj,settings) - if len(json_config_rules) > 0: - LOGGER.info("Start configuring device") - del device_obj.device_config.config_rules[:] - for json_config_rule in json_config_rules: - device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) - self.__task_executor.configure_optical_device(device_obj) - #self.__task_executor.configure_device(device_obj) - - results.append(True) - except Exception as e: # pylint: disable=broad-except - LOGGER.exception('Unable to SetEndpoint({:s})'.format(str(endpoint))) - results.append(e) - - return results - ''' - - @metered_subclass_method(METRICS_POOL) def SetEndpoint( self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None @@ -121,68 +53,29 @@ class OCServiceHandler(_ServiceHandler): else: settings = self.__settings_handler.get('/settings') - LOGGER.debug("Andrea111 settings={}".format(settings)) + LOGGER.debug("settings={}".format(settings)) # settings = self.__settings_handler.get('/settings') #flow is the new variable that stores input-output relationship flows = convert_endpoints_to_flows(endpoints) #handled_flows=handle_flows_names(flows=flows,task_executor=self.__task_executor) - LOGGER.debug("AndreaXXX dict of flows= {}".format(flows)) + LOGGER.debug("dict of flows= {}".format(flows)) #LOGGER.info("Handled Flows %s",handled_flows) results = [] #new cycle for setting optical devices - for device_uuid in flows.keys(): + for device_uuid, dev_flows in flows.items(): try: - dev_flows = flows[device_uuid] device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) - LOGGER.debug("Andrea567 device_obj={}".format(device_obj)) - ''' - #to be imported in the device handler - endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) - endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) - endpoint_name = endpoint_obj.name - ''' + LOGGER.debug("device_obj={}".format(device_obj)) if (settings): - LOGGER.debug("Andrea234 settings={}".format(settings)) + LOGGER.debug("settings={}".format(settings)) self.__task_executor.configure_optical_device(device_obj, settings, dev_flows, is_opticalband) results.append(True) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to configure Device({:s})'.format(str(device_uuid))) results.append(e) - - ''' - for endpoint in endpoints: - try: - device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) - - device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) - endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) - endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) - endpoint_name = endpoint_obj.name - - # json_config_rules = setup_config_rules( - # service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name, - # settings, endpoint_settings) - - if (settings): - LOGGER.debug("Andrea234 settings={}".format(settings)) - self.__task_executor.configure_optical_device(device_obj,settings,handled_flows,is_opticalband) - #we don't use config_rules - # if len(json_config_rules) > 0: - # LOGGER.debug("VBNMHGStart configuring device") - # del device_obj.device_config.config_rules[:] - # for json_config_rule in json_config_rules: - # device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) - # self.__task_executor.configure_optical_device(device_obj) - #self.__task_executor.configure_device(device_obj) - - results.append(True) - except Exception as e: # pylint: disable=broad-except - LOGGER.exception('Unable to SetEndpoint({:s})'.format(str(endpoint))) - results.append(e) - ''' return results @@ -193,29 +86,14 @@ class OCServiceHandler(_ServiceHandler): chk_type('endpoints', endpoints, list) if len(endpoints) == 0: return [] - service_uuid = self.__service.service_id.service_uuid.uuid - settings = self.__settings_handler.get('/settings') + # TODO: to be checked and elaborated results = [] for endpoint in endpoints: try: device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) - device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) - endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) - endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) - endpoint_name = endpoint_obj.name - - json_config_rules = teardown_config_rules( - service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name, - settings, endpoint_settings) - - if len(json_config_rules) > 0: - del device_obj.device_config.config_rules[:] - for json_config_rule in json_config_rules: - device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) - self.__task_executor.configure_device(device_obj) - + self.__task_executor.configure_device(device_obj) results.append(True) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to DeleteEndpoint({:s})'.format(str(endpoint))) diff --git a/src/service/service/service_handlers/oc/OCTools.py b/src/service/service/service_handlers/oc/OCTools.py index c8bddefb9..f40cb65be 100644 --- a/src/service/service/service_handlers/oc/OCTools.py +++ b/src/service/service/service_handlers/oc/OCTools.py @@ -11,6 +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 service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching from typing import Dict, Any, List, Optional, Tuple import logging @@ -114,14 +115,10 @@ def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]]) def get_device_endpint_name (endpoint_uuid:str,device_uuid:str,task_executor)->Tuple: - - - device_obj = task_executor.get_device(DeviceId(**json_device_id(device_uuid))) endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) endpoint_name = endpoint_obj.name - - return (device_obj.name,endpoint_name) + return (device_obj.name, endpoint_name) def handle_flows_names (task_executor,flows:dict)->Dict : new_flows={} @@ -140,4 +137,4 @@ def handle_flows_names (task_executor,flows:dict)->Dict : if (device_name not in new_flows): new_flows[device_name]=[] new_flows[device_name].append((source_port,destination_port)) - return new_flows \ No newline at end of file + return new_flows diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py index 3718c01f4..6d24da4c0 100644 --- a/src/service/service/task_scheduler/TaskExecutor.py +++ b/src/service/service/task_scheduler/TaskExecutor.py @@ -16,7 +16,9 @@ import logging #, json from enum import Enum from typing import TYPE_CHECKING, Any, Dict, Optional, Union from common.method_wrappers.ServiceExceptions import NotFoundException -from common.proto.context_pb2 import Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId,MyConfig,MyConfigId +from common.proto.context_pb2 import ( + Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId, MyConfig, MyConfigId +) from common.tools.context_queries.Connection import get_connection_by_id from common.tools.context_queries.Device import get_device from common.tools.context_queries.Service import get_service_by_id @@ -113,69 +115,32 @@ class TaskExecutor: self._device_client.ConfigureDevice(device) self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device) - # New function Andrea for Optical Devices - def configure_optical_device(self,device:Device,settings:str,flows:list,is_opticalband:bool): - - + # New function Andrea for Optical Devices + def configure_optical_device(self, device : Device, settings : str, flows : list, is_opticalband : bool): device_key = get_device_key(device.device_id) - myid=MyConfigId() - myid.myconfig_uuid=device.device_id.device_uuid.uuid - myConfig=MyConfig() + myid = MyConfigId() + myid.myconfig_uuid = device.device_id.device_uuid.uuid + myConfig = MyConfig() - setting =settings.value if settings else "" + setting = settings.value if settings else "" - new_config={} + new_config = {} try: - result=self._context_client.SelectMyConfig(myid) - new_config=eval(result.config) - LOGGER.info("result %s",result) - if result is not None : - - new_config["new_config"]=setting - new_config["is_opticalband"]=is_opticalband - new_config["flow"]=flows - result.config = str(new_config) - myConfig.CopyFrom(result) - - self._device_client.ConfigureOpticalDevice(myConfig) - - self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device) + result = self._context_client.SelectMyConfig(myid) + new_config = eval(result.config) + LOGGER.info("result %s",result) + if result is not None : + new_config["new_config"]=setting + new_config["is_opticalband"]=is_opticalband + new_config["flow"]=flows + result.config = str(new_config) + myConfig.CopyFrom(result) + self._device_client.ConfigureOpticalDevice(myConfig) + + self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device) except Exception as e: LOGGER.debug("error in config my config %s",e) - - ''' - # For Optical Devices - def configure_optical_device (self,device:Device,settings:str,flows:dict,is_opticalband:bool) : - - - device_key = get_device_key(device.device_id) - myid=MyConfigId() - myid.myconfig_uuid=device.device_id.device_uuid.uuid - myConfig=MyConfig() - - setting =settings.value if settings else "" - - new_config={} - try: - result=self._context_client.SelectMyConfig(myid) - new_config=eval(result.config) - - if result is not None : - - new_config["new_config"]=setting - new_config["is_opticalband"]=is_opticalband - new_config["flow"]=flows - result.config = str(new_config) - myConfig.CopyFrom(result) - - self._device_client.ConfigureOpticalDevice(myConfig) - - self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device) - except Exception as e: - LOGGER.debug("error in config my config %s",e) - ''' - - + def get_device_controller(self, device : Device) -> Optional[Device]: #json_controller = None #for config_rule in device.device_config.config_rules: -- GitLab