diff --git a/src/service/requirements.in b/src/service/requirements.in index a10f7da7aba3027a89bdd8e9b62bc4ab90fb5e02..86720da190136c84d14e343b45cc0c97fa68ec06 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.27.1 diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py index d7a983dc97cefd9a796ab97629ba2dbe58a71b22..b06295deee528656ae30ed33e4dacc7d7d04a178 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') @@ -242,6 +249,65 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): 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 = 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 +346,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 eaf8f715aeff435b67bce77928e726daeb4729e2..f0628110fbd5f2b15308f05c9061c699a09dbcff 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 0000000000000000000000000000000000000000..f4a46112e778bd01aa76322384d8adee942aaa5b --- /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 0000000000000000000000000000000000000000..8ae42639315287cada0ca288cd5593240819cfc5 --- /dev/null +++ b/src/service/service/service_handlers/oc/OCServiceHandler.py @@ -0,0 +1,152 @@ +# 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, 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 .OCTools import convert_endpoints_to_flows, handle_flows_names + +LOGGER = logging.getLogger(__name__) + +METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'oc'}) + +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 [] + 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("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("dict of flows= {}".format(flows)) + #LOGGER.info("Handled Flows %s",handled_flows) + + results = [] + #new cycle for setting optical devices + for device_uuid, dev_flows in flows.items(): + try: + device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) + LOGGER.debug("device_obj={}".format(device_obj)) + if (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) + + 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 [] + + # 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))) + 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 0000000000000000000000000000000000000000..f40cb65bef2af5b69628c4167218bed59c92e317 --- /dev/null +++ b/src/service/service/service_handlers/oc/OCTools.py @@ -0,0 +1,140 @@ +# 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 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 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612 --- /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 ae0f1be7da291a5dc025641cb606f7a7706059ca..6d24da4c0be05e1687536a836219bbfa15052504 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 +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,9 +110,36 @@ 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) def get_device_controller(self, device : Device) -> Optional[Device]: #json_controller = None diff --git a/src/service/service/tools/OpticalTools.py b/src/service/service/tools/OpticalTools.py new file mode 100644 index 0000000000000000000000000000000000000000..227be2765fbd6bbc779e53505b833fc8bf08873f --- /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 0000000000000000000000000000000000000000..5fcb393e9d8a5eaaeccc11a8c1dc8e4485b8cbc9 --- /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 + ] +} + """ +