diff --git a/manifests/opticalcontrollerservice.yaml b/manifests/opticalcontrollerservice.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ba1edcc563fe219d8fe4e6a45cc9bc05eda9bb7c --- /dev/null +++ b/manifests/opticalcontrollerservice.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: opticalcontrollerservice +spec: + selector: + matchLabels: + app: opticalcontrollerservice + replicas: 1 + template: + metadata: + annotations: + # Required for IETF L2VPN SBI when both parent and child run in same K8s cluster with Linkerd + config.linkerd.io/skip-outbound-ports: "8022" + labels: + app: opticalcontrollerservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: localhost:32000/tfs/opticalcontroller:dev + imagePullPolicy: Never + ports: + - containerPort: 5022 + - containerPort: 9192 + + env: + - name: LOG_LEVEL + value: "INFO" + + resources: + requests: + cpu: 500m + memory: 128Mi + limits: + cpu: 1000m + memory: 1024Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: opticalcontrollerservice + labels: + app: opticalcontrollerservice +spec: + type: ClusterIP + selector: + app: opticalcontrollerservice + ports: + - name: grpc + protocol: TCP + port: 5022 + targetPort: 5022 + - name: metrics + protocol: TCP + port: 9192 + targetPort: 9192 diff --git a/my_deploy.sh b/my_deploy.sh index 0c5ba03c5b9f63038a622f44ab2dfaaf1e7e6ada..524abc6cc8dc8dff25e559663cf73339ed1b2bd6 100755 --- a/my_deploy.sh +++ b/my_deploy.sh @@ -20,13 +20,10 @@ export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/" # Set the list of components, separated by spaces, you want to build images for, and deploy. -export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_generator" +export TFS_COMPONENTS="context device pathcomp opticalcontroller service slice webui " # Uncomment to activate Monitoring -#export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" - -# Uncomment to activate bgpls_speaker -#export TFS_COMPONENTS="${TFS_COMPONENTS} bgpls_speaker" +#export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring"../ # Uncomment to activate ZTP #export TFS_COMPONENTS="${TFS_COMPONENTS} ztp" diff --git a/proto/context.proto b/proto/context.proto index d5022ac292f04cd2e9b80f690be3077e7aedd868..e961816930c102fcc111a3abb5f49e5dfa277061 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -74,6 +74,16 @@ service ContextService { rpc SetConnection (Connection ) returns ( ConnectionId ) {} rpc RemoveConnection (ConnectionId ) returns ( Empty ) {} rpc GetConnectionEvents(Empty ) returns (stream ConnectionEvent ) {} + + +// ------------------------------ Experimental------------------------------ + rpc GetMyConfig (Empty ) returns ( MyConfigList ) {} + rpc SetMyConfig (MyConfig) returns (MyConfigId) {} + rpc SelectMyConfig (MyConfigId) returns (MyConfig) {} + + rpc SetOpticalLink (OpticalLink) returns (Empty) {} + rpc GetOpticalLink (OpticalLinkId) returns (OpticalLink) {} + rpc GetFiber (FiberId) returns (Fiber) {} } // ----- Generic ------------------------------------------------------------------------------------------------------- @@ -201,8 +211,9 @@ enum DeviceDriverEnum { DEVICEDRIVER_XR = 6; DEVICEDRIVER_IETF_L2VPN = 7; DEVICEDRIVER_GNMI_OPENCONFIG = 8; - DEVICEDRIVER_FLEXSCALE = 9; - DEVICEDRIVER_IETF_ACTN = 10; + DEVICEDRIVER_OC = 11; + DEVICEDRIVER_FLEXSCALE=10; + DEVICEDRIVER_IETF_ACTN=9; } enum DeviceOperationalStatusEnum { @@ -288,6 +299,7 @@ enum ServiceTypeEnum { SERVICETYPE_TAPI_CONNECTIVITY_SERVICE = 3; SERVICETYPE_TE = 4; SERVICETYPE_E2E = 5; +SERVICETYPE_OPTICAL_CONNECTIVITY = 6; } enum ServiceStatusEnum { @@ -612,3 +624,49 @@ message AuthenticationResult { ContextId context_id = 1; bool authenticated = 2; } + +// ---------------- Experimental ------------------------ +message MyConfigId { + string myconfig_uuid= 1; +} +message MyConfig { + MyConfigId myconfig_id=1; + string config =2 ; +} +message MyConfigList { + repeated MyConfig MyConfigs =1 ; +} +//----Optical Link ---- +message OpticalLinkId { + Uuid optical_link_uuid = 1; +} + +message FiberId { + Uuid fiber_uuid = 1; +} +message Fiber { + string ID=10; + string src_port=1; + string dst_port=2; + string local_peer_port= 3; + string remote_peer_port=4; + repeated int32 c_slots=5; + repeated int32 l_slots=6; + repeated int32 s_slots=7; + float length=8; + bool used=9; + FiberId fiber_uuid=11; + +} +message OpticalLinkDetails { + float length=1; + string source =2; + string target=3; + repeated Fiber fibers=4; +} + +message OpticalLink { + OpticalLinkId optical_link_uuid=3; + string name=1; + OpticalLinkDetails details=2; +} diff --git a/proto/openconfig_device.proto b/proto/openconfig_device.proto new file mode 100644 index 0000000000000000000000000000000000000000..d00e46645f79c659bd83fafe2c3295e3e65385ce --- /dev/null +++ b/proto/openconfig_device.proto @@ -0,0 +1,26 @@ +// 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. + +syntax = "proto3"; +package openconfig_device; + +import "context.proto"; +import "monitoring.proto"; + +service OpenConfigService { + rpc AddOpenConfigDevice (context.MyConfig ) returns (context.MyConfigId ) {} + + rpc ConfigureOpticalDevice (context.MyConfig) returns (context.Empty) {} + +} diff --git a/scripts/show_logs_opticalcontroller.sh b/scripts/show_logs_opticalcontroller.sh new file mode 100755 index 0000000000000000000000000000000000000000..e32ea7ef989402f6b739cbc0a555e506d9dc9a51 --- /dev/null +++ b/scripts/show_logs_opticalcontroller.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# 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. + +######################################################################################################################## +# Define your deployment settings here +######################################################################################################################## + +# If not already set, set the name of the Kubernetes namespace to deploy to. +export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"} + +######################################################################################################################## +# Automated steps start here +######################################################################################################################## + +kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/opticalcontrollerservice -c server > logs/opticalcontroller.log && vi logs/opticalcontroller.log diff --git a/src/common/Constants.py b/src/common/Constants.py index c7ba01f69978fd3c601dcfe30180015d524b1100..0a36c6ac5bec7e11fed563876441ebe6d17f2cdb 100644 --- a/src/common/Constants.py +++ b/src/common/Constants.py @@ -59,6 +59,7 @@ class ServiceNameEnum(Enum): TE = 'te' FORECASTER = 'forecaster' E2EORCHESTRATOR = 'e2eorchestrator' + OPTICALCONTROLLER = 'opticalcontroller' BGPLS = 'bgpls-speaker' # Used for test and debugging only diff --git a/src/common/DeviceTypes.py b/src/common/DeviceTypes.py index 72b3e21fdecd1019099eec03b3b473f56bcd403a..f4ade564b7b9b6df0dcfd2cdbf13d28c41f0c57a 100644 --- a/src/common/DeviceTypes.py +++ b/src/common/DeviceTypes.py @@ -47,6 +47,7 @@ class DeviceTypeEnum(Enum): PACKET_ROUTER = 'packet-router' PACKET_SWITCH = 'packet-switch' XR_CONSTELLATION = 'xr-constellation' + # ETSI TeraFlowSDN controller TERAFLOWSDN_CONTROLLER = 'teraflowsdn' diff --git a/src/common/Settings.py b/src/common/Settings.py index 5d6fba2fdca0530851fabdc06954976b29f2f2b4..fc503ea2d0fd428faf2bc81d2697337b77e1996d 100644 --- a/src/common/Settings.py +++ b/src/common/Settings.py @@ -37,6 +37,8 @@ ENVVAR_SUFIX_SERVICE_HOST = 'SERVICE_HOST' ENVVAR_SUFIX_SERVICE_PORT_GRPC = 'SERVICE_PORT_GRPC' ENVVAR_SUFIX_SERVICE_PORT_HTTP = 'SERVICE_PORT_HTTP' + + def find_environment_variables( environment_variable_names : List[str] = [] ) -> Dict[str, str]: diff --git a/src/common/tools/descriptor/Loader.py b/src/common/tools/descriptor/Loader.py index 4ab33beae8987ff2b38e5e2bc0252bacf557120c..eef41bbd8897b788b5ec25580cbdf18c055ba5c1 100644 --- a/src/common/tools/descriptor/Loader.py +++ b/src/common/tools/descriptor/Loader.py @@ -262,6 +262,7 @@ class DescriptorLoader: # Device, Service and Slice require to first create the entity and the configure it self.__devices_add, self.__devices_config = split_devices_by_rules(self.__devices) + self.__services_add = get_descriptors_add_services(self.__services) self.__slices_add = get_descriptors_add_slices(self.__slices) diff --git a/src/common/tools/descriptor/Tools.py b/src/common/tools/descriptor/Tools.py index b4a76ff4f00d0f6886895cca0ab6f27f7aa8aa43..a4792436ade2e9c5790f9602e1007ecff8f9b32a 100644 --- a/src/common/tools/descriptor/Tools.py +++ b/src/common/tools/descriptor/Tools.py @@ -12,9 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -import copy, json +import copy, json,logging from typing import Dict, List, Optional, Tuple, Union from common.DeviceTypes import DeviceTypeEnum +from common.proto.context_pb2 import DeviceDriverEnum def get_descriptors_add_contexts(contexts : List[Dict]) -> List[Dict]: contexts_add = copy.deepcopy(contexts) @@ -66,6 +67,8 @@ def format_device_custom_config_rules(device : Dict) -> Dict: config_rules = device.get('device_config', {}).get('config_rules', []) config_rules = format_custom_config_rules(config_rules) device['device_config']['config_rules'] = config_rules + + return device def format_service_custom_config_rules(service : Dict) -> Dict: @@ -83,7 +86,9 @@ def format_slice_custom_config_rules(slice_ : Dict) -> Dict: def split_devices_by_rules(devices : List[Dict]) -> Tuple[List[Dict], List[Dict]]: devices_add = [] devices_config = [] + for device in devices: + connect_rules = [] config_rules = [] for config_rule in device.get('device_config', {}).get('config_rules', []): @@ -95,13 +100,15 @@ def split_devices_by_rules(devices : List[Dict]) -> Tuple[List[Dict], List[Dict] if len(connect_rules) > 0: device_add = copy.deepcopy(device) - device_add['device_endpoints'] = [] + if (device['device_drivers'][0] != DeviceDriverEnum.DEVICEDRIVER_OC): + device_add['device_endpoints'] = [] device_add['device_config'] = {'config_rules': connect_rules} devices_add.append(device_add) if len(config_rules) > 0: device['device_config'] = {'config_rules': config_rules} devices_config.append(device) + return devices_add, devices_config diff --git a/src/context/client/ContextClient.py b/src/context/client/ContextClient.py index 13d9dc0035b45845bf11367e02c8830b5151c1d6..a1a6bcb086d8e9aeab36edcea4b9a6a94765e61b 100644 --- a/src/context/client/ContextClient.py +++ b/src/context/client/ContextClient.py @@ -26,7 +26,8 @@ from common.proto.context_pb2 import ( Link, LinkEvent, LinkId, LinkIdList, LinkList, Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, - Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList) + Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, + MyConfig,MyConfigId,MyConfigList) from common.proto.context_pb2_grpc import ContextServiceStub from common.proto.context_policy_pb2_grpc import ContextPolicyServiceStub from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule @@ -436,3 +437,24 @@ class ContextClient: response = self.policy_stub.RemovePolicyRule(request) LOGGER.debug('RemovePolicyRule result: {:s}'.format(grpc_message_to_json_string(response))) return response + #//////////////// Experimental ////////////////// + @RETRY_DECORATOR + def SetMyConfig (self,request:MyConfig) ->MyConfigId: + LOGGER.debug('SettingMyConfig request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.SetMyConfig(request) + LOGGER.debug('SettingMyconfig result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + @RETRY_DECORATOR + def GetMyConfig (self,request:Empty) ->MyConfigList: + LOGGER.debug('GettingMyConfig request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.GetMyConfig(request) + LOGGER.debug('GetMyConfig result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + @RETRY_DECORATOR + def SelectMyConfig (self,request:MyConfigId) ->MyConfigList: + LOGGER.debug('Selecting request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.SelectMyConfig(request) + LOGGER.debug('GetMyConfig result: {:s}'.format(grpc_message_to_json_string(response))) + return response diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py index 5aad7f9c9ff3a6fd063b1f364256e760f47e1c33..f4d2cc3071857da2103775827593ff416c59aea3 100644 --- a/src/context/service/ContextServiceServicerImpl.py +++ b/src/context/service/ContextServiceServicerImpl.py @@ -23,7 +23,8 @@ from common.proto.context_pb2 import ( Link, LinkEvent, LinkId, LinkIdList, LinkList, Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, - Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList) + Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, + MyConfigList,MyConfigId,MyConfig) from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule from common.proto.context_pb2_grpc import ContextServiceServicer from common.proto.context_policy_pb2_grpc import ContextPolicyServiceServicer @@ -43,6 +44,7 @@ from .database.Slice import ( slice_delete, slice_get, slice_list_ids, slice_list_objs, slice_select, slice_set, slice_unset) from .database.Topology import ( topology_delete, topology_get, topology_get_details, topology_list_ids, topology_list_objs, topology_set) +from .database.MyConfigOperator import (set_myconfig,select_MyConfig,get_myconfig) LOGGER = logging.getLogger(__name__) @@ -296,3 +298,21 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def RemovePolicyRule(self, request : PolicyRuleId, context: grpc.ServicerContext) -> Empty: return policyrule_delete(self.db_engine, self.messagebroker, request) + # ---------------------------- Experimental ------------------- + @safe_and_metered_rpc_method(METRICS_POOL,LOGGER) + def GetMyConfig(self,request:Empty,context:grpc.ServicerContext) -> MyConfigList: + + result =get_myconfig(db_engine=self.db_engine) + + return MyConfigList(MyConfigs=result) + def SetMyConfig(self,request:MyConfig,context:grpc.ServicerContext)-> MyConfigId: + + myconfig_id= set_myconfig(db_engine=self.db_engine,request=request) + + return MyConfigId(**myconfig_id) + def SelectMyConfig (self,request:MyConfigId,context:grpc.ServicerContext) -> MyConfig: + result =select_MyConfig(db_engine=self.db_engine,request=request) + logging.info(f"FromSelectMyConfig {result}") + myid =MyConfigId() + myid.CopyFrom(result.myconfig_id) + return MyConfig(config=result.config,myconfig_id=myid) diff --git a/src/context/service/database/ConfigModel.py b/src/context/service/database/ConfigModel.py new file mode 100644 index 0000000000000000000000000000000000000000..234e155f026164c14924b67a33a4db4812bae620 --- /dev/null +++ b/src/context/service/database/ConfigModel.py @@ -0,0 +1,125 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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 functools, logging, operator +from enum import Enum +from typing import Dict, List, Optional, Tuple, Union +from common.orm.Database import Database +from common.orm.HighLevel import get_object, get_or_create_object, update_or_create_object +from common.orm.backend.Tools import key_to_str +from common.orm.fields.EnumeratedField import EnumeratedField +from common.orm.fields.ForeignKeyField import ForeignKeyField +from common.orm.fields.IntegerField import IntegerField +from common.orm.fields.PrimaryKeyField import PrimaryKeyField +from common.orm.fields.StringField import StringField +from common.orm.model.Model import Model +from context.proto.context_pb2 import ConfigActionEnum +from .Tools import fast_hasher, grpc_to_enum, remove_dict_key + +LOGGER = logging.getLogger(__name__) + +class ORM_ConfigActionEnum(Enum): + UNDEFINED = ConfigActionEnum.CONFIGACTION_UNDEFINED + SET = ConfigActionEnum.CONFIGACTION_SET + DELETE = ConfigActionEnum.CONFIGACTION_DELETE + +grpc_to_enum__config_action = functools.partial( + grpc_to_enum, ConfigActionEnum, ORM_ConfigActionEnum) + +class ConfigModel(Model): # pylint: disable=abstract-method + pk = PrimaryKeyField() + + def dump(self) -> List[Dict]: + db_config_rule_pks = self.references(ConfigRuleModel) + config_rules = [ConfigRuleModel(self.database, pk).dump(include_position=True) for pk,_ in db_config_rule_pks] + config_rules = sorted(config_rules, key=operator.itemgetter('position')) + return [remove_dict_key(config_rule, 'position') for config_rule in config_rules] + +class ConfigRuleModel(Model): # pylint: disable=abstract-method + pk = PrimaryKeyField() + config_fk = ForeignKeyField(ConfigModel) + position = IntegerField(min_value=0, required=True) + action = EnumeratedField(ORM_ConfigActionEnum, required=True) + key = StringField(required=True, allow_empty=False) + value = StringField(required=True, allow_empty=False) + + def dump(self, include_position=True) -> Dict: # pylint: disable=arguments-differ + result = { + 'action': self.action.value, + 'resource_key': self.key, + 'resource_value': self.value, + } + if include_position: result['position'] = self.position + return result + +def set_config_rule( + database : Database, db_config : ConfigModel, position : int, resource_key : str, resource_value : str + ) -> Tuple[ConfigRuleModel, bool]: + + str_rule_key_hash = fast_hasher(resource_key) + str_config_rule_key = key_to_str([db_config.pk, str_rule_key_hash], separator=':') + result : Tuple[ConfigRuleModel, bool] = update_or_create_object(database, ConfigRuleModel, str_config_rule_key, { + 'config_fk': db_config, 'position': position, 'action': ORM_ConfigActionEnum.SET, + 'key': resource_key, 'value': resource_value}) + db_config_rule, updated = result + return db_config_rule, updated + +def delete_config_rule( + database : Database, db_config : ConfigModel, resource_key : str + ) -> None: + + str_rule_key_hash = fast_hasher(resource_key) + str_config_rule_key = key_to_str([db_config.pk, str_rule_key_hash], separator=':') + db_config_rule : Optional[ConfigRuleModel] = get_object( + database, ConfigRuleModel, str_config_rule_key, raise_if_not_found=False) + if db_config_rule is None: return + db_config_rule.delete() + +def delete_all_config_rules( + database : Database, db_config : ConfigModel + ) -> None: + + db_config_rule_pks = db_config.references(ConfigRuleModel) + for pk,_ in db_config_rule_pks: ConfigRuleModel(database, pk).delete() + +def grpc_config_rules_to_raw(grpc_config_rules) -> List[Tuple[ORM_ConfigActionEnum, str, str]]: + def translate(grpc_config_rule): + action = grpc_to_enum__config_action(grpc_config_rule.action) + return action, grpc_config_rule.resource_key, grpc_config_rule.resource_value + return [translate(grpc_config_rule) for grpc_config_rule in grpc_config_rules] + +def update_config( + database : Database, db_parent_pk : str, config_name : str, + raw_config_rules : List[Tuple[ORM_ConfigActionEnum, str, str]] + ) -> List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]]: + + str_config_key = key_to_str([db_parent_pk, config_name], separator=':') + result : Tuple[ConfigModel, bool] = get_or_create_object(database, ConfigModel, str_config_key) + db_config, created = result + + db_objects : List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]] = [(db_config, created)] + + for position,(action, resource_key, resource_value) in enumerate(raw_config_rules): + if action == ORM_ConfigActionEnum.SET: + result : Tuple[ConfigRuleModel, bool] = set_config_rule( + database, db_config, position, resource_key, resource_value) + db_config_rule, updated = result + db_objects.append((db_config_rule, updated)) + elif action == ORM_ConfigActionEnum.DELETE: + delete_config_rule(database, db_config, resource_key) + else: + msg = 'Unsupported action({:s}) for resource_key({:s})/resource_value({:s})' + raise AttributeError(msg.format(str(ConfigActionEnum.Name(action)), str(resource_key), str(resource_value))) + + return db_objects diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py index 3aff20ade14532dcb7fbf8ec1033c084aaeead3c..76eac944ed55be45cdf15a6500d06640223a2328 100644 --- a/src/context/service/database/Device.py +++ b/src/context/service/database/Device.py @@ -21,7 +21,8 @@ from typing import Dict, List, Optional, Set, Tuple from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException from common.message_broker.MessageBroker import MessageBroker from common.proto.context_pb2 import ( - Device, DeviceFilter, DeviceId, DeviceIdList, DeviceList, Empty, EventTypeEnum, TopologyId) + Device, DeviceFilter, DeviceId, DeviceIdList + , DeviceList, Empty, EventTypeEnum, TopologyId,DeviceDriverEnum) from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.object_factory.Device import json_device_id from context.service.database.uuids.Topology import topology_get_uuid @@ -76,6 +77,7 @@ def device_get(db_engine : Engine, request : DeviceId) -> Device: return Device(**obj) def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Device) -> DeviceId: + raw_device_uuid = request.device_id.device_uuid.uuid raw_device_name = request.name device_name = raw_device_uuid if len(raw_device_name) == 0 else raw_device_name @@ -87,6 +89,7 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi controller_uuid = None device_type = request.device_type + oper_status = grpc_to_enum__device_operational_status(request.device_operational_status) device_drivers = [grpc_to_enum__device_driver(d) for d in request.device_drivers] @@ -94,7 +97,7 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi topology_uuids : Set[str] = set() related_topologies : List[Dict] = list() - + # By default, always add device to default Context/Topology _,topology_uuid = topology_get_uuid(TopologyId(), allow_random=False, allow_default=True) related_topologies.append({ @@ -103,10 +106,14 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi }) topology_uuids.add(topology_uuid) + + is_oc_driver= [d for d in request.device_drivers][0]==DeviceDriverEnum.DEVICEDRIVER_OC + + endpoints_data : List[Dict] = list() for i, endpoint in enumerate(request.device_endpoints): endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid - if len(endpoint_device_uuid) == 0: endpoint_device_uuid = device_uuid + if len(endpoint_device_uuid) == 0 or is_oc_driver : endpoint_device_uuid = device_uuid if endpoint_device_uuid not in {raw_device_uuid, device_uuid}: raise InvalidArgumentException( 'request.device_endpoints[{:d}].device_id.device_uuid.uuid'.format(i), endpoint_device_uuid, diff --git a/src/context/service/database/MyConfigOperator.py b/src/context/service/database/MyConfigOperator.py new file mode 100644 index 0000000000000000000000000000000000000000..0ca58f6cab15dae870dd0d949ec395d09454991d --- /dev/null +++ b/src/context/service/database/MyConfigOperator.py @@ -0,0 +1,129 @@ +# 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 uuid,json + +import datetime, logging +from sqlalchemy.dialects.postgresql import insert +from sqlalchemy.engine import Engine +from sqlalchemy.orm import Session, selectinload, sessionmaker +from sqlalchemy_cockroachdb import run_transaction +from typing import Dict, List, Optional, Set, Tuple +from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException +from common.proto.context_pb2 import Device, DeviceFilter, DeviceId, TopologyId,MyConfig,MyConfigId,MyConfigList +from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Device import json_device_id +from context.service.database.uuids.Topology import topology_get_uuid +from .models.DeviceModel import DeviceModel +from .models.EndPointModel import EndPointModel +from .models.TopologyModel import TopologyDeviceModel +from .models.enums.DeviceDriver import grpc_to_enum__device_driver +from .models.enums.DeviceOperationalStatus import grpc_to_enum__device_operational_status +from .models.enums.KpiSampleType import grpc_to_enum__kpi_sample_type +from .uuids.Device import device_get_uuid +from .uuids.EndPoint import endpoint_get_uuid +from .ConfigRule import compose_config_rules_data, upsert_config_rules +from .models.MyConfigModel import MyConfigModel +LOGGER = logging.getLogger(__name__) + +def get_myconfig (db_engine:Engine): + + def callback(session:Session): + + lst = list() + results = session.query(MyConfigModel).all() + + for obj in results: + myconfig=MyConfig() + myconfig.config=json.dump(obj.config) + myid=MyConfigId() + myid.myconfig_uuid=obj.myconfig_uuid + myconfig.myconfig_id.CopyFrom(myid) + + lst.append(myconfig) + return lst + obj=run_transaction(sessionmaker(bind=db_engine),callback) + return obj + + + + +def set_myconfig (db_engine:Engine,request:MyConfig): + + myconfig_id=MyConfigId() + myconfig_id.myconfig_uuid=request.myconfig_id.myconfig_uuid + my_config_data=[] + if (request.config): + channels=[] + transceivers=[] + config = json.loads(request.config) + + if ( "channels" in config and len(config["channels"])>0): + channels=[channel['name']['index'] for channel in config["channels"]] + if ("transceivers" in config and len(config["transceivers"]["transceiver"])>0): + transceivers=[transceiver for transceiver in config["transceivers"]["transceiver"]] + + + my_config_data=[ + { + "myconfig_uuid":request.myconfig_id.myconfig_uuid, + "channels":channels, + "transcievers":transceivers, + "interfaces":json.dumps(config["interfaces"]["interface"]), + "channel_namespace":config["channel_namespace"], + "endpoints":[json.dumps(endpoint) for endpoint in config["endpoints"]], + "frequency":config["frequency"] if "frequency" in config else 0, + "operational_mode":config["operational_mode"] if "operational_mode" in config else 0, + "output_power":config["output_power"] if "output_power" in config else '', + } + ] + + def callback(session:Session)->bool: + + stmt = insert(MyConfigModel).values(my_config_data) + stmt = stmt.on_conflict_do_update( + index_elements=[MyConfigModel.myconfig_uuid], + set_=dict( + + channel_namespace=stmt.excluded.channel_namespace + ) + ) + + stmt = stmt.returning(MyConfigModel.myconfig_uuid) + + id = session.execute(stmt).fetchone() + + myconfig_id =run_transaction(sessionmaker(bind=db_engine),callback) + + return {'myconfig_uuid': myconfig_id} + + + +def select_MyConfig(db_engine:Engine,request:MyConfigId): + + def callback(session : Session) -> MyConfig: + result=MyConfig() + obj = session.query(MyConfigModel).filter_by(myconfig_uuid=request.myconfig_uuid).first() + + if (obj is not None): + + + myid=MyConfigId() + myid.myconfig_uuid=obj.myconfig_uuid + result.config=json.dumps(obj.dump()) + result.myconfig_id.CopyFrom(myid) + + + return result + + return run_transaction(sessionmaker(bind=db_engine,expire_on_commit=False), callback) \ No newline at end of file diff --git a/src/context/service/database/Service.py b/src/context/service/database/Service.py index fc196ddded291aa82c8f9df932c15611d13121e4..38e5d5ec1e48b21c09832858296fb22e902aba38 100644 --- a/src/context/service/database/Service.py +++ b/src/context/service/database/Service.py @@ -82,8 +82,10 @@ def service_set(db_engine : Engine, messagebroker : MessageBroker, request : Ser raw_service_name = request.name service_name = raw_service_uuid if len(raw_service_name) == 0 else raw_service_name context_uuid,service_uuid = service_get_uuid(request.service_id, service_name=service_name, allow_random=True) - + service_type = grpc_to_enum__service_type(request.service_type) + service_type="OPTICAL_CONNECTIVITY" if service_type is None and request.service_type==6 else service_type + service_status = grpc_to_enum__service_status(request.service_status.service_status) now = datetime.datetime.utcnow() diff --git a/src/context/service/database/models/MyConfigModel.py b/src/context/service/database/models/MyConfigModel.py new file mode 100644 index 0000000000000000000000000000000000000000..960f7368ba0edddc984170f585cf17c54909a130 --- /dev/null +++ b/src/context/service/database/models/MyConfigModel.py @@ -0,0 +1,51 @@ +# 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 sqlalchemy import Column, String ,Integer +from sqlalchemy.dialects.postgresql import ARRAY + + +from ._Base import _Base + + + + +class MyConfigModel (_Base): + __tablename__="MyConfig" + myconfig_uuid = Column(String, primary_key=True) + channels=Column(ARRAY(String),nullable=True) + transcievers= Column(ARRAY(String),nullable=True) + interfaces =Column(String,nullable=True) + channel_namespace=Column(String,nullable=True) + endpoints=Column(ARRAY(String),nullable=True) + frequency=Column(Integer,nullable=True) + operational_mode=Column(Integer,nullable=True) + output_power=Column(String,nullable=True) + + + + def dump (self): + + return { + "channels":[{'name':{'index':channel}} for channel in self.channels], + "transceivers":{"transceiver":[transciever for transciever in self.transcievers]}, + "interfaces":{"interface":json.loads(self.interfaces)}, + "channel_namespace":self.channel_namespace, + "endpoints":[json.loads(endpoint) for endpoint in self.endpoints], + "frequency":self.frequency, + "output_power":self.output_power, + "operational_mode":self.operational_mode + } + diff --git a/src/context/service/database/models/enums/DeviceDriver.py b/src/context/service/database/models/enums/DeviceDriver.py index 8e15bf058599eeed0629fc1249af0d052183db28..2ccdda2725a7f7bb13ba296d4eca25f88b1e73d1 100644 --- a/src/context/service/database/models/enums/DeviceDriver.py +++ b/src/context/service/database/models/enums/DeviceDriver.py @@ -33,6 +33,7 @@ class ORM_DeviceDriverEnum(enum.Enum): GNMI_OPENCONFIG = DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG FLEXSCALE = DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE IETF_ACTN = DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN + OC = DeviceDriverEnum.DEVICEDRIVER_OC grpc_to_enum__device_driver = functools.partial( grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum) diff --git a/src/context/service/database/models/enums/ServiceType.py b/src/context/service/database/models/enums/ServiceType.py index ce198f8c1f795f25da547e2d5974059062489709..01ed68c1708dc617a46edc31e94fc07d79e278e1 100644 --- a/src/context/service/database/models/enums/ServiceType.py +++ b/src/context/service/database/models/enums/ServiceType.py @@ -28,6 +28,7 @@ class ORM_ServiceTypeEnum(enum.Enum): TAPI_CONNECTIVITY_SERVICE = ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE TE = ServiceTypeEnum.SERVICETYPE_TE E2E = ServiceTypeEnum.SERVICETYPE_E2E + OPTICAL_CONNECTIVITY = ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY grpc_to_enum__service_type = functools.partial( grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum) diff --git a/src/device/client/DeviceClient.py b/src/device/client/DeviceClient.py index 32fa685b953232808acba273e7d30514922c04eb..9b4880c04752c0d19a6d1cc12b4f38b5ed7b744d 100644 --- a/src/device/client/DeviceClient.py +++ b/src/device/client/DeviceClient.py @@ -15,7 +15,7 @@ import grpc, logging from common.Constants import ServiceNameEnum from common.Settings import get_service_host, get_service_port_grpc -from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty, MyConfig, MyConfigId +from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty,MyConfig,MyConfigId from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceStub from common.tools.client.RetryDecorator import retry, delay_exponential @@ -82,7 +82,6 @@ class DeviceClient: response = self.stub.MonitorDeviceKpi(request) LOGGER.debug('MonitorDeviceKpi result: {:s}'.format(grpc_message_to_json_string(response))) return response - def ConfigureOpticalDevice(self, request : MyConfig) -> MyConfigId: LOGGER.debug('ConfigureOpticalDevice request: {:s}'.format(grpc_message_to_json_string(request))) response = self.openconfig_stub.ConfigureOpticalDevice(request) diff --git a/src/device/service/DeviceService.py b/src/device/service/DeviceService.py index c7868e44579fb27b6eecc6806f64e3bb531d7cd4..544f250f6bc8685513fb874ec0a8754872a0d176 100644 --- a/src/device/service/DeviceService.py +++ b/src/device/service/DeviceService.py @@ -39,6 +39,7 @@ class DeviceService(GenericGrpcService): self.monitoring_loops.start() add_DeviceServiceServicer_to_server(self.device_servicer, self.server) add_OpenConfigServiceServicer_to_server(self.openconfig_device_servicer,self.server) + def stop(self): super().stop() diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py index 7592e5b58f45d7745a045643f4669e4d957134f3..da5d1134e0d310836211c07a4f157ec56602514d 100644 --- a/src/device/service/DeviceServiceServicerImpl.py +++ b/src/device/service/DeviceServiceServicerImpl.py @@ -20,8 +20,7 @@ from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.proto.context_pb2 import ( - Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link, MyConfig, MyConfigId -) + Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link,MyConfig,MyConfigId) from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer from common.tools.context_queries.Device import get_device @@ -55,12 +54,13 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def AddDevice(self, request : Device, context : grpc.ServicerContext) -> DeviceId: + t0 = time.time() device_uuid = request.device_id.device_uuid.uuid connection_config_rules = check_connect_rules(request.device_config) - if (request.device_drivers[0]!= 9) : + if (request.device_drivers[0]!= DeviceDriverEnum.DEVICEDRIVER_OC) : check_no_endpoints(request.device_endpoints) t1 = time.time() @@ -143,12 +143,13 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED # temporary line - if (request.device_drivers[0]== 9 and len(request.device_endpoints)>0): + if (request.device_drivers[0]== DeviceDriverEnum.DEVICEDRIVER_OC and len(request.device_endpoints)>0): for endpoint in request.device_endpoints: #endpoint.endpoint_id.device_id.CopyFrom(device.device_id) pass device.device_endpoints.extend(request.device_endpoints) + device_id = context_client.SetDevice(device) t10 = time.time() diff --git a/src/device/service/OpenConfigServicer.py b/src/device/service/OpenConfigServicer.py index 5be11cb31ec69825a2b6009159e5202b54936009..329bceef227783b45441ecf460fdb082145b23e0 100644 --- a/src/device/service/OpenConfigServicer.py +++ b/src/device/service/OpenConfigServicer.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import grpc, logging, os, time +import grpc, logging, os, time,json from typing import Dict from prometheus_client import Histogram from common.Constants import ServiceNameEnum @@ -20,9 +20,7 @@ from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.proto.context_pb2 import ( - Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link, MyConfig, MyConfigId, - MyConfig, MyConfigList -) + Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link,MyConfig,MyConfigId ,MyConfig,MyConfigList) from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer from common.tools.context_queries.Device import get_device @@ -59,9 +57,7 @@ class OpenConfigServicer(DeviceServiceServicer): def AddOpenConfigDevice(self, request : MyConfig, context : grpc.ServicerContext) -> DeviceId: device_uuid = request.device_id.device_uuid.uuid - device_type=request.device_type - ocdriver=OCDriver() - connection_config_rules = check_connect_rules(request.device_config) + check_no_endpoints(request.device_endpoints) context_client = ContextClient() @@ -74,39 +70,43 @@ class OpenConfigServicer(DeviceServiceServicer): device.device_type = request.device_type device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED device.device_drivers.extend(request.device_drivers) # pylint: disable=no-member - device.device_config.CopyFrom(request.device_config) # pylint: disable=no-member + device.device_config.CopyFrom(request.device_config) + device.device_endpoints.extend(request.device_endpoints) + # pylint: disable=no-member device_id = context_client.SetDevice(device) device = get_device(context_client, device_id.device_uuid.uuid, rw_copy=True) # update device_uuid to honor UUID provided by Context device_uuid = device.device_id.device_uuid.uuid - LOGGER.debug('device type %s',device) - t2 = time.time() + + self.mutex_queues.wait_my_turn(device_uuid) - t3 = time.time() - #temp fix to solve the error - #todo check what to pass here - resources_to_get = [] + try: - #driver : _Driver = get_driver(self.driver_instance_cache, device) - results_getconfig=ocdriver.GetConfig(resource_keys=resources_to_get,device_uuid=device_uuid) - #results_getconfig = driver.GetConfig(resources_to_get,device_uuid) + + device_id = context_client.SetDevice(device) except Exception as error : LOGGER.debug("error %s",error) + + + + #modified Andrea @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def ConfigureOpticalDevice (self, request : MyConfig, context:grpc.ServicerContext) -> Empty: - LOGGER.info('Setting from ConfigureOpticalDevice with Flows %s',request) - #device_id = request.myconfig_id - #device_uuid = device_id.myconfig_uuid + device_uuid = request.myconfig_id.myconfig_uuid - LOGGER.info("device uuid {}".format(device_uuid)) + resources=[] result=None - config = eval(request.config) - filter_fields= ["frequency", "target-output-power", "interface", "operational-mode"] + + config =json.loads(request.config) + + + try: + context_client = ContextClient() device = get_device( @@ -114,12 +114,11 @@ class OpenConfigServicer(DeviceServiceServicer): include_config_rules=False) if device is None: - LOGGER.info("device is none") + raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice') resources,conditions=extract_resources(config=config,device=device) driver : _Driver = get_driver(self.driver_instance_cache, device) - LOGGER.info("resource %s conditions %s",resources,conditions) - + result = driver.SetConfig(resources=resources,conditions=conditions) #todo #add a control with the NETCONF get @@ -129,6 +128,6 @@ class OpenConfigServicer(DeviceServiceServicer): LOGGER.info("error in configuring %s",e) - LOGGER.info("result %s",result) + return Empty() \ No newline at end of file diff --git a/src/device/service/Tools.py b/src/device/service/Tools.py index 8ccb77afa712d77a66f4d971340f93231bbaf0a6..c4b41020ae70158e9a103bd3f2e95bca09d1f327 100644 --- a/src/device/service/Tools.py +++ b/src/device/service/Tools.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - from uuid import UUID, uuid4, uuid5 import json, logging from typing import Any, Dict, List, Optional, Tuple, Union @@ -455,7 +454,6 @@ def update_endpoints(src_device : Device, dst_device : Device) -> None: dst_topology_id = dst_endpoint_id.topology_id if len(src_topology_uuid) > 0: dst_topology_id.topology_uuid.uuid = src_topology_uuid if len(src_context_uuid) > 0: dst_topology_id.context_id.context_uuid.uuid = src_context_uuid - def oc_default_endpoints( device : Device, driver : _Driver, monitoring_loops : MonitoringLoops, new_sub_devices : Dict[str, Device], new_sub_links : Dict[str, Link] @@ -471,61 +469,62 @@ def get_edit_target (device:Device,is_opticalband:bool)-> str: if device.device_type =='optical-roadm': return 'media-channel' else : return 'optical-channel' -def extract_resources (config : dict, device : Device)-> list: - conditions={} - resources=[] - resources.append({"resource_key":"channel_namespace","value":config["channel_namespace"] if "channel_namespace" in config else None}) - resources.append({"resource_key":'add_transceiver',"value":config['add_transceiver'] if 'add_transceiver' in config else None}) - resources.append({"resource_key":"interface","value":config["update_interface"] if 'update_interface' in config else None}) - is_opticalband=config['is_opticalband'] if 'is_opticalband' in config else False - conditions["is_opticalband"]=is_opticalband - conditions["edit_type"]=get_edit_target(device=device,is_opticalband=is_opticalband) - if ('flow' in config): - #for tuple_value in config['flow'][device.name]: - source_vals = [] - dest_vals = [] - for tuple_value in config['flow']: - source_port=None - destination_port=None - #resources.append({"resource_key":"source_port","value":source_port}) - #resources.append({"resource_key":"destination_port","value":destination_port}) - source_port_uuid,destination_port_uuid=tuple_value - if (source_port_uuid !='0'): - src_endpoint_obj = get_endpoint_matching(device, source_port_uuid) - source_port = src_endpoint_obj.name - source_vals.append(source_port) - if (destination_port_uuid !='0'): - dst_endpoint_obj = get_endpoint_matching(device, destination_port_uuid) - destination_port = dst_endpoint_obj.name - dest_vals.append(destination_port) - resources.append({"resource_key":"source_port","value":source_vals}) - resources.append({"resource_key":"destination_port","value":dest_vals}) - if ('new_config' in config): - lower_frequency=None - upper_frequency=None - resources.append({"resource_key":"target-output-power","value":config["new_config"]["target-output-power"] if "target-output-power" in config["new_config"] else None }) - #resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config else config["new_config"]["freqency"]}) - resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config["new_config"] else None}) - resources.append({"resource_key":"operational-mode","value":config["new_config"]["operational-mode"] if "operational-mode" in config["new_config"] else None}) - resources.append({"resource_key":"line-port","value":config["new_config"]["line-port"] if "line-port" in config["new_config"] else None}) - - resources.append({"resource_key":"name","value":config['new_config']['band_type'] if 'band_type' in config['new_config'] else None}) - resources.append({"resource_key":"optical-band-parent","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None }) - resources.append({"resource_key":"channel_name","value":config["new_config"]["name"] if "name" in config["new_config"] else None}) - - if not is_opticalband : - if 'frequency' in config['new_config'] and 'band' in config['new_config'] and conditions["edit_type"] == 'media-channel': - lower_frequency= int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2)) - upper_frequency= int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2)) - - #lower_frequency= (config['new_config']['frequency']- config['new_config']['band'])/2 - #upper_frequency=(config['new_config']['frequency']+ config['new_config']['band'])/2 - resources.append({"resource_key":"index","value":config["new_config"]["flow_id"] if "flow_id" in config["new_config"] else None}) - else : - lower_frequency=config['new_config']['low-freq'] if "low-freq" in config['new_config'] else None - upper_frequency=config['new_config']['up-freq'] if 'up-freq' in config['new_config'] else None - resources.append({"resource_key":"index","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None}) +def extract_resources (config:dict,device:Device)-> list : + conditions={} + resources=[] + resources.append({"resource_key":"channel_namespace","value":config["channel_namespace"] if "channel_namespace" in config else None}) + resources.append({"resource_key":'add_transceiver',"value":config['add_transceiver'] if 'add_transceiver' in config else None}) + resources.append({"resource_key":"interface","value":config["update_interface"] if 'update_interface' in config else None}) + is_opticalband=config['is_opticalband'] if 'is_opticalband' in config else False + conditions["is_opticalband"]=is_opticalband + conditions["edit_type"]=get_edit_target(device=device,is_opticalband=is_opticalband) + if ('flow' in config): + #for tuple_value in config['flow'][device.name]: + source_vals = [] + dest_vals = [] + for tuple_value in config['flow']: + source_port=None + destination_port=None + #resources.append({"resource_key":"source_port","value":source_port}) + #resources.append({"resource_key":"destination_port","value":destination_port}) + source_port_uuid,destination_port_uuid=tuple_value + if (source_port_uuid !='0'): + src_endpoint_obj = get_endpoint_matching(device, source_port_uuid) + source_port = src_endpoint_obj.name + source_vals.append(source_port) + if (destination_port_uuid !='0'): + dst_endpoint_obj = get_endpoint_matching(device, destination_port_uuid) + destination_port = dst_endpoint_obj.name + dest_vals.append(destination_port) + resources.append({"resource_key":"source_port","value":source_vals}) + resources.append({"resource_key":"destination_port","value":dest_vals}) + if ('new_config' in config): + lower_frequency=None + upper_frequency=None + resources.append({"resource_key":"target-output-power","value":config["new_config"]["target-output-power"] if "target-output-power" in config["new_config"] else None }) + #resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config else config["new_config"]["freqency"]}) + resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config["new_config"] else None}) + resources.append({"resource_key":"operational-mode","value":config["new_config"]["operational-mode"] if "operational-mode" in config["new_config"] else None}) + resources.append({"resource_key":"line-port","value":config["new_config"]["line-port"] if "line-port" in config["new_config"] else None}) + + resources.append({"resource_key":"name","value":config['new_config']['band_type'] if 'band_type' in config['new_config'] else None}) + resources.append({"resource_key":"optical-band-parent","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None }) + resources.append({"resource_key":"channel_name","value":config["new_config"]["name"] if "name" in config["new_config"] else None}) + + if not is_opticalband : + if 'frequency' in config['new_config'] and 'band' in config['new_config'] and conditions["edit_type"] == 'media-channel': + lower_frequency= int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2)) + upper_frequency= int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2)) + + #lower_frequency= (config['new_config']['frequency']- config['new_config']['band'])/2 + #upper_frequency=(config['new_config']['frequency']+ config['new_config']['band'])/2 + resources.append({"resource_key":"index","value":config["new_config"]["flow_id"] if "flow_id" in config["new_config"] else None}) + else : + lower_frequency=config['new_config']['low-freq'] if "low-freq" in config['new_config'] else None + upper_frequency=config['new_config']['up-freq'] if 'up-freq' in config['new_config'] else None + resources.append({"resource_key":"index","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None}) + + resources.append({"resource_key":"lower-frequency","value":lower_frequency}) + resources.append({"resource_key":"upper-frequency","value":upper_frequency}) + return [resources,conditions] - resources.append({"resource_key":"lower-frequency","value":lower_frequency}) - resources.append({"resource_key":"upper-frequency","value":upper_frequency}) - return [resources,conditions] diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py index 09c4d33b70ffce893ce9ea08b2e67e0a12d350ef..4c0a89ebdeb967764990ffb893f62ddb64b7f16b 100644 --- a/src/device/service/drivers/__init__.py +++ b/src/device/service/drivers/__init__.py @@ -167,7 +167,6 @@ if LOAD_ALL_DEVICE_DRIVERS: FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE, } ])) - if LOAD_ALL_DEVICE_DRIVERS: from .oc_driver.OCDriver import OCDriver # pylint: disable=wrong-import-position DRIVERS.append( @@ -175,11 +174,12 @@ if LOAD_ALL_DEVICE_DRIVERS: { # Real Packet Router, specifying OpenConfig Driver => use OpenConfigDriver - FilterFieldEnum.DEVICE_TYPE: [ - DeviceTypeEnum.NETCONFIG_AGENT, + FilterFieldEnum.DEVICE_TYPE:[ + DeviceTypeEnum.OPTICAL_ROADM, DeviceTypeEnum.OPTICAL_TRANSPONDER - ], + + ], FilterFieldEnum.DRIVER : DeviceDriverEnum.DEVICEDRIVER_OC, } ])) diff --git a/src/device/service/drivers/oc_driver/OCDriver.py b/src/device/service/drivers/oc_driver/OCDriver.py index 512ec49baa66ed7a5cb4062c2ddf34bff81f9cde..8467a8cebb41160bc6311f75c320f593ded75e11 100644 --- a/src/device/service/drivers/oc_driver/OCDriver.py +++ b/src/device/service/drivers/oc_driver/OCDriver.py @@ -1,4 +1,4 @@ -# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -135,8 +135,7 @@ class NetconfSessionHandler: response= self.__manager.edit_config( config, target=target, default_operation=default_operation, test_option=test_option, error_option=error_option, format=format) - logging.info("response message %s",response) - + @RETRY_DECORATOR def locked(self, target): @@ -154,17 +153,12 @@ def edit_config( commit_per_rule=False, target='running', default_operation='merge', test_option=None, error_option=None, format='xml' ): - str_method = 'DeleteConfig' if delete else 'SetConfig' + #str_method = 'DeleteConfig' if delete else 'SetConfig' results = [] str_config_messages=[] - #try: - # if add_proccess: - # str_config_messages = add_transceiver(resources[0]['value']) - # elif update_interface: - # str_config_messages = interface_template(resources[0]["value"]) - # else: + if (conditions['edit_type']=='optical-channel'): #transponder str_config_messages = create_optical_channel(resources) @@ -174,14 +168,8 @@ def edit_config( else : #roadm media-channel str_config_messages=create_media_channel(resources) - logging.info("config message %s",str_config_messages) - # if (add_proccess or update_interface): - - # netconf_handler.edit_config( # configure the device - # config=str_config_messages, target=target, default_operation=default_operation, - # test_option=test_option, error_option=error_option, format=format) - # if commit_per_rule: - # netconf_handler.commit() + + for str_config_message in str_config_messages: # configuration of the received templates @@ -195,23 +183,7 @@ def edit_config( #results[i] = True results.append(True) - # except Exception as e: # pylint: disable=broad-except - # str_operation = 'preparing' if target == 'candidate' else ('deleting' if delete else 'setting') - # msg = '[{:s}] Exception {:s} {:s}: {:s}' - # logger.info("error %s",e) - # logger.exception(msg.format(e)) - # #results[i] = e # if validation fails, store the exception - # results.append(e) - - # if not commit_per_rule: - # try: - # netconf_handler.commit() - # except Exception as e: # pylint: disable=broad-except - # msg = '[{:s}] Exception committing: {:s}' - # str_operation = 'preparing' if target == 'candidate' else ('deleting' if delete else 'setting') - # logger.exception(msg.format(str_method, str_operation, str(resources))) - # results = [e for _ in resources] # if commit fails, set exception in each resource - # return results + class OCDriver(_Driver): def __init__(self, address : str, port : int,device_uuid=None, **settings) -> None: @@ -232,7 +204,7 @@ class OCDriver(_Driver): self._temp_address=f"{address}{port}" self.__out_samples = queue.Queue() self.__netconf_handler = NetconfSessionHandler(self.address, self.port, **(self.settings)) - self.__logger.info("settings are %s",settings) + self.__device_uuid=device_uuid self.Connect() @@ -267,7 +239,7 @@ class OCDriver(_Driver): @metered_subclass_method(METRICS_POOL) def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: - self.__logger.info("device_uuid %s",self.__device_uuid) + chk_type('resources', resource_keys, list) results = [] myConfig= MyConfig() @@ -275,7 +247,7 @@ class OCDriver(_Driver): with self.__lock: - self.__logger.info(" resources_key %s",resource_keys) + context_client.connect() config={} channels_lst=[] @@ -301,10 +273,8 @@ class OCDriver(_Driver): value_dic["interfaces"]=interfaces value_dic["channel_namespace"]=channel_namespace value_dic["endpoints"]=endpoints - self.__logger.info("config from get config %s",str(value_dic)) - myConfig.config=str(value_dic) - - myconfig_id=MyConfigId() + + myConfig.config=json.dumps(value_dic) myConfig.myconfig_id.myconfig_uuid=self.__device_uuid if self.__device_uuid is not None else "" config_id=context_client.SetMyConfig(myConfig) diff --git a/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py b/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py index b4df7c2bff7b050e665de9afa5b44a7c6d85db18..8d3049cfedf8258ed4099ed29f0eafa055f8e90f 100644 --- a/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py +++ b/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py @@ -1,4 +1,4 @@ -# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/src/device/service/drivers/oc_driver/templates/Tools.py b/src/device/service/drivers/oc_driver/templates/Tools.py index 4370495c912dafbc2c5165e00fc79ec885536a4d..1af7b9b7f98d78bb2b5b9ea7c6d1036bfb499347 100644 --- a/src/device/service/drivers/oc_driver/templates/Tools.py +++ b/src/device/service/drivers/oc_driver/templates/Tools.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - import re,logging import json import lxml.etree as ET @@ -92,7 +91,6 @@ def extract_channels_based_on_channelnamespace (xml_data:str,channel_namespace:s xml_bytes = xml_data.encode("utf-8") root = ET.fromstring(xml_bytes) channels=[] - logging.info("channel namespace %s opticalband %s",channel_namespace ,is_opticalband) # Find the component names whose children include the "optical-channel" element if (not is_opticalband): @@ -122,7 +120,6 @@ def extract_channels_based_on_channelnamespace (xml_data:str,channel_namespace:s # Retrieve port-name for dest - logging.info("extract channels %s",channels) return channels def extract_channels_based_on_type (xml_data:str): xml_bytes = xml_data.encode("utf-8") @@ -230,10 +227,10 @@ def has_opticalbands(xml_data:str): return has_opticalbands def extractor(data_xml:str,resource_keys:list,dic:dict): - logging.info('data xml %s',data_xml) + endpoints=[] is_opticalband=has_opticalbands(xml_data=data_xml) - logging.info("from extractor opticalband %s",is_opticalband) + channel_namespace=extract_channel_xmlns(data_xml=data_xml,is_opticalband=is_opticalband) # channel_names=extract_channels_based_on_type(xml_data=data_xml) # if len(channel_names)==0 : diff --git a/src/device/service/drivers/oc_driver/templates/VPN/physical.py b/src/device/service/drivers/oc_driver/templates/VPN/physical.py index ba0de7ea6fded64b457ffa348f80ca294c89cfdf..def67a9a8b85af5b45040d0712bf764e969bc323 100644 --- a/src/device/service/drivers/oc_driver/templates/VPN/physical.py +++ b/src/device/service/drivers/oc_driver/templates/VPN/physical.py @@ -1,4 +1,4 @@ -# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ def seperate_port_config(resources:list,unwanted_keys:list[str])->list[list,dict ports={} index=None for item in resources : - logging.info("Andrea223344 item={}".format(item['resource_key'])) + if (item['value'] is not None and (item['resource_key'] not in unwanted_keys)): config.append({'resource_key':item['resource_key'], 'value':item['value']} ) #if (item['resource_key'] == 'destination_port' or item['resource_key'] == 'source_port') and item['value'] is not None: @@ -30,25 +30,24 @@ def seperate_port_config(resources:list,unwanted_keys:list[str])->list[list,dict ports[item['resource_key']]=item['value'] if (item['resource_key']=='index' and item['value'] is not None) : index=item['value'] - logging.info("from create_templates config %s ports %s index %s",config,ports,index) + return [config,ports,index] def create_optical_channel(resources): - logging.debug("TRANSPONDERconfiguration, resources={}".format(resources)) + unwanted_keys=['destination_port','source_port','channel_namespace','optical-band-parent','index', 'name'] results =[] data={"name":i["value"] for i in resources if i["resource_key"]=="channel_name"} data["channel_namespace"]=next((i["value"] for i in resources if i["resource_key"] == "channel_namespace"), None) config,ports,index=seperate_port_config(resources,unwanted_keys=unwanted_keys) - logging.info("from physical %s",resources) - + port_val = "" if 'destination_port' in ports and ports['destination_port'][0] is not None: port_val = ports['destination_port'][0] else: port_val = ports['source_port'][0] - logging.info("transponder port={}".format(port_val)) + doc, tag, text = Doc().tagtext() #with tag('config'): @@ -69,7 +68,7 @@ def create_optical_channel(resources): ) results.append(result) - logging.info("xml %s",results) + return results def add_transceiver (transceiver_name:str): @@ -184,7 +183,7 @@ def create_media_channel (resources): with tag('config'): #with tag('index'):text(index) for resource in config: - logging.info("Andrea223344 resources_key= {}".format(resource['resource_key'])) + if resource['resource_key'] == "index": with tag('index'):text(str(int(index)+i)) else: diff --git a/src/opticalcontroller/OpticalController.py b/src/opticalcontroller/OpticalController.py index e8e0e2164a81f6ea621decba92350b04cdcba814..ceaa97ecf4d0186a92ce257e59f58c3a14ef92cc 100644 --- a/src/opticalcontroller/OpticalController.py +++ b/src/opticalcontroller/OpticalController.py @@ -1,17 +1,3 @@ -# 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 flask import Flask from flask import render_template from flask_restplus import Resource, Api @@ -198,7 +184,7 @@ class GetBands(Resource): return "Error", 404 -@optical.route('/GetOpticalBand/<string:ob_id>') +@optical.route('/GetOpticalBand/<int:ob_id>') @optical.response(200, 'Success') @optical.response(404, 'Error, not found') class GetBand(Resource): @@ -238,9 +224,9 @@ if __name__ == '__main__': nodes_dict, links_dict = readTopologyData(nodes_json, topology_json) - topologies,links= getTopology() - print ("topologies{} and devices {}".format(topologies,links)) + #topologies,links= getTopology() + #print ("topologies{} and devices {}".format(topologies,links)) rsa = RSA(nodes_dict, links_dict) - LOGGER.info(rsa.init_link_slots(testing)) + app.run(host='0.0.0.0', port=5022,debug=True) diff --git a/src/opticalcontroller/RSA.py b/src/opticalcontroller/RSA.py index acf080d7f9c223766409551051b7cacae1610db1..919e5dfcf460d95daa12845654e16ddce47f1dcf 100644 --- a/src/opticalcontroller/RSA.py +++ b/src/opticalcontroller/RSA.py @@ -1,3 +1,5 @@ +<<<<<<< HEAD +======= # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +>>>>>>> e19583176d771a8f8c1216d8a79488d0e50097c1 import dijsktra from tools import * from variables import * @@ -322,11 +325,21 @@ class RSA(): return fiber_list def get_link_by_name (self, key): +<<<<<<< HEAD + result = None +======= +>>>>>>> e19583176d771a8f8c1216d8a79488d0e50097c1 for link in self.links_dict["links"]: if link["optical_link"]["name"] == key: if debug: print(link) +<<<<<<< HEAD + result = link + break + return result +======= return link +>>>>>>> e19583176d771a8f8c1216d8a79488d0e50097c1 def get_fiber_details(self, link_key, fiber_id): for link in self.links_dict["links"]: @@ -787,6 +800,16 @@ class RSA(): return self.flow_id, [] optical_band_id, temp_links = self.create_optical_band(links, path, bidir, num_slots_ob) return None, optical_band_id +<<<<<<< HEAD + self.flow_id += 1 + self.db_flows[self.flow_id] = {} + self.db_flows[self.flow_id]["flow_id"] = self.flow_id + self.db_flows[self.flow_id]["src"] = src + self.db_flows[self.flow_id]["dst"] = dst + self.db_flows[self.flow_id]["bitrate"] = rate + self.db_flows[self.flow_id]["bidir"] = bidir +======= +>>>>>>> e19583176d771a8f8c1216d8a79488d0e50097c1 print("INFO: TP to TP connection") if band is None: temp_links2 = [] @@ -806,6 +829,9 @@ class RSA(): temp_path.append(roadm_dst) temp_path.append(t_dst) existing_ob = self.get_optical_bands(roadm_src, roadm_dst) +<<<<<<< HEAD + +======= self.flow_id += 1 self.db_flows[self.flow_id] = {} self.db_flows[self.flow_id]["flow_id"] = self.flow_id @@ -813,6 +839,7 @@ class RSA(): self.db_flows[self.flow_id]["dst"] = dst self.db_flows[self.flow_id]["bitrate"] = rate self.db_flows[self.flow_id]["bidir"] = bidir +>>>>>>> e19583176d771a8f8c1216d8a79488d0e50097c1 if len(existing_ob) > 0: print("INFO: Evaluating existing OB {}".format(existing_ob)) @@ -875,6 +902,15 @@ class RSA(): links, path = self.compute_path(src, dst) optical_band_id, temp_links = self.create_optical_band(links, path, bidir, num_slots_ob) op, num_slots = map_rate_to_slot(rate) +<<<<<<< HEAD + # self.flow_id += 1 + # self.db_flows[self.flow_id] = {} + # self.db_flows[self.flow_id]["flow_id"] = self.flow_id + # self.db_flows[self.flow_id]["src"] = src + # self.db_flows[self.flow_id]["dst"] = dst + # self.db_flows[self.flow_id]["bitrate"] = rate + # self.db_flows[self.flow_id]["bidir"] = bidir +======= self.flow_id += 1 self.db_flows[self.flow_id] = {} self.db_flows[self.flow_id]["flow_id"] = self.flow_id @@ -882,6 +918,7 @@ class RSA(): self.db_flows[self.flow_id]["dst"] = dst self.db_flows[self.flow_id]["bitrate"] = rate self.db_flows[self.flow_id]["bidir"] = bidir +>>>>>>> e19583176d771a8f8c1216d8a79488d0e50097c1 if debug: print(temp_links) diff --git a/src/opticalcontroller/dijsktra.py b/src/opticalcontroller/dijsktra.py index a86d1d93dcbc30b9e4e3b95a34a0922439871bf6..5be78c6242d26fc0b0332321559ac17b3c72f2d5 100644 --- a/src/opticalcontroller/dijsktra.py +++ b/src/opticalcontroller/dijsktra.py @@ -1,21 +1,3 @@ -# 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. - -# TODO: migrate to NetworkX: -# https://networkx.org/documentation/stable/index.html -# https://networkx.org/documentation/stable/reference/algorithms/shortest_paths.html - import sys class Vertex: @@ -237,4 +219,4 @@ if __name__ == '__main__': print ('The shortest path : %s' %(path[::-1]))""" p = shortest_path(g, g.get_vertex('a'), g.get_vertex('e')) - print(p) + print(p) \ No newline at end of file diff --git a/src/opticalcontroller/json_files/tfs copy.json b/src/opticalcontroller/json_files/tfs copy.json new file mode 100644 index 0000000000000000000000000000000000000000..a108ed13ee5fe85c974e41e8ff6fe5ed5dd7d2ed --- /dev/null +++ b/src/opticalcontroller/json_files/tfs copy.json @@ -0,0 +1,1286 @@ +{ + "links": [ + { + "link_id": { + "link_uuid": { + "uuid": "T1->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T1" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "12" + } + } + ], + "optical_link": { + "name": "T1-R1", + "details": { + "length": 0, + "source": "muxT", + "target": "srgR", + "fibers": [ + { + "ID": "M1", + "length": 0, + "src_port": "1", + "dst_port": "2001", + "local_peer_port": "1", + "remote_peer_port": "1001", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + }, + { + "ID": "M2", + "length": 0, + "src_port": "2", + "dst_port": "2002", + "local_peer_port": "2", + "remote_peer_port": "1002", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + }, + { + "ID": "M3", + "length": 0, + "src_port": "3", + "dst_port": "2003", + "local_peer_port": "3", + "remote_peer_port": "1003", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + } + ] + } + } + }, + { + "link_id": { + "link_uuid": { + "uuid": "R1->T1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "2" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T1" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + } + ], + "optical_link": { + "name": "R1-T1", + "details": { + "length": 0, + "source": "srgT", + "target": "muxT", + "fibers": [ + { + "ID": "M1", + "length": 0, + "src_port": "1001", + "dst_port": "1", + "local_peer_port": "2001", + "remote_peer_port": "1", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + }, + { + "ID": "M2", + "length": 0, + "src_port": "1002", + "dst_port": "2", + "local_peer_port": "2002", + "remote_peer_port": "2", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + }, + { + "ID": "M3", + "length": 0, + "src_port": "1003", + "dst_port": "3", + "local_peer_port": "2003", + "remote_peer_port": "3", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + } + ] + } + } + }, + { + "link_id": { + "link_uuid": { + "uuid": "R1->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "13" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "24" + } + } + ], + "optical_link": { + "name": "R1-R2", + "details": { + "length": 0, + "source": "D1", + "target": "D1", + "fibers": [ + { + "ID": "D11", + "length": 0, + "src_port": "13", + "dst_port": "24", + "local_peer_port": "23", + "remote_peer_port": "14", + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + } + ] + } + } + }, + { + "link_id": { + "link_uuid": { + "uuid": "R2->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "14" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "23" + } + } + ], + "optical_link": { + "name": "R2-R1", + "details": { + "length": 0, + "source": "D1", + "target": "D1", + "fibers": [ + { + "ID": "D11", + "length": 0, + "src_port": "14", + "dst_port": "23", + "local_peer_port": "24", + "remote_peer_port": "13", + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + } + ] + } + } + }, + { + "link_id": { + "link_uuid": { + "uuid": "T2->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T2" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "1001" + } + } + ], + "optical_link": { + "name": "T2-R2", + "details": { + "length": 0, + "source": "srgT", + "target": "muxT", + "fibers": [ + { + "ID": "M1", + "length": 0, + "src_port": "1", + "dst_port": "1001", + "local_peer_port": "1", + "remote_peer_port": "2001", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + }, + { + "ID": "M2", + "length": 0, + "src_port": "2", + "dst_port": "1002", + "local_peer_port": "2", + "remote_peer_port": "2002", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + }, + { + "ID": "M3", + "length": 0, + "src_port": "3", + "dst_port": "1003", + "local_peer_port": "3", + "remote_peer_port": "2003", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + } + ] + } + } + }, + { + "link_id": { + "link_uuid": { + "uuid": "R2->T2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "5" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T2" + } + }, + "endpoint_uuid": { + "uuid": "6" + } + } + ], + "optical_link": { + "name": "R2-T2", + "details": { + "length": 0, + "source": "srgT", + "target": "muxT", + "fibers": [ + { + "ID": "M1", + "length": 0, + "src_port": "1001", + "dst_port": "1", + "local_peer_port": "2001", + "remote_peer_port": "1", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + }, + { + "ID": "M2", + "length": 0, + "src_port": "1002", + "dst_port": "2", + "local_peer_port": "2002", + "remote_peer_port": "2", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + }, + { + "ID": "M3", + "length": 0, + "src_port": "1003", + "dst_port": "3", + "local_peer_port": "2003", + "remote_peer_port": "3", + "used": false, + "c_slots": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "l_slots": [ + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120 + ], + "s_slots": [ + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520 + ] + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/src/opticalcontroller/json_files/tfs.json b/src/opticalcontroller/json_files/tfs.json index a108ed13ee5fe85c974e41e8ff6fe5ed5dd7d2ed..31803b893b5639e957be33465599573baa475ca2 100644 --- a/src/opticalcontroller/json_files/tfs.json +++ b/src/opticalcontroller/json_files/tfs.json @@ -39,159 +39,9 @@ "ID": "M1", "length": 0, "src_port": "1", - "dst_port": "2001", + "dst_port": "12", "local_peer_port": "1", - "remote_peer_port": "1001", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M2", - "length": 0, - "src_port": "2", - "dst_port": "2002", - "local_peer_port": "2", - "remote_peer_port": "1002", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M3", - "length": 0, - "src_port": "3", - "dst_port": "2003", - "local_peer_port": "3", - "remote_peer_port": "1003", + "remote_peer_port": "2", "used": false, "c_slots": [ 1, @@ -302,9 +152,9 @@ { "ID": "M1", "length": 0, - "src_port": "1001", + "src_port": "2", "dst_port": "1", - "local_peer_port": "2001", + "local_peer_port": "12", "remote_peer_port": "1", "used": false, "c_slots": [ @@ -373,15 +223,53 @@ 519, 520 ] - }, + } + ] + } + } + }, + { + "link_id": { + "link_uuid": { + "uuid": "R1->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "3" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "14" + } + } + ], + "optical_link": { + "name": "R1-R2", + "details": { + "length": 0, + "source": "D1", + "target": "D1", + "fibers": [ { - "ID": "M2", + "ID": "D11", "length": 0, - "src_port": "1002", - "dst_port": "2", - "local_peer_port": "2002", - "remote_peer_port": "2", - "used": false, + "src_port": "3", + "dst_port": "14", + "local_peer_port": "13", + "remote_peer_port": "4", "c_slots": [ 1, 2, @@ -448,15 +336,53 @@ 519, 520 ] - }, + } + ] + } + } + }, + { + "link_id": { + "link_uuid": { + "uuid": "R2->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "4" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "13" + } + } + ], + "optical_link": { + "name": "R2-R1", + "details": { + "length": 0, + "source": "D1", + "target": "D1", + "fibers": [ { - "ID": "M3", + "ID": "D11", "length": 0, - "src_port": "1003", - "dst_port": "3", - "local_peer_port": "2003", + "src_port": "4", + "dst_port": "13", + "local_peer_port": "14", "remote_peer_port": "3", - "used": false, "c_slots": [ 1, 2, @@ -531,18 +457,18 @@ { "link_id": { "link_uuid": { - "uuid": "R1->R2" + "uuid": "T2->R2" } }, "link_endpoint_ids": [ { "device_id": { "device_uuid": { - "uuid": "R1" + "uuid": "T2" } }, "endpoint_uuid": { - "uuid": "13" + "uuid": "6" } }, { @@ -552,24 +478,25 @@ } }, "endpoint_uuid": { - "uuid": "24" + "uuid": "15" } } ], "optical_link": { - "name": "R1-R2", + "name": "T2-R2", "details": { "length": 0, - "source": "D1", - "target": "D1", + "source": "srgT", + "target": "muxT", "fibers": [ { - "ID": "D11", + "ID": "M1", "length": 0, - "src_port": "13", - "dst_port": "24", - "local_peer_port": "23", - "remote_peer_port": "14", + "src_port": "6", + "dst_port": "15", + "local_peer_port": "6", + "remote_peer_port": "5", + "used": false, "c_slots": [ 1, 2, @@ -644,7 +571,7 @@ { "link_id": { "link_uuid": { - "uuid": "R2->R1" + "uuid": "R2->T2" } }, "link_endpoint_ids": [ @@ -655,561 +582,34 @@ } }, "endpoint_uuid": { - "uuid": "14" + "uuid": "5" } }, { "device_id": { "device_uuid": { - "uuid": "R1" + "uuid": "T2" } }, "endpoint_uuid": { - "uuid": "23" + "uuid": "6" } } ], "optical_link": { - "name": "R2-R1", + "name": "R2-T2", "details": { "length": 0, - "source": "D1", - "target": "D1", + "source": "srgT", + "target": "muxT", "fibers": [ { - "ID": "D11", + "ID": "M1", "length": 0, - "src_port": "14", - "dst_port": "23", - "local_peer_port": "24", - "remote_peer_port": "13", - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - } - ] - } - } - }, - { - "link_id": { - "link_uuid": { - "uuid": "T2->R2" - } - }, - "link_endpoint_ids": [ - { - "device_id": { - "device_uuid": { - "uuid": "T2" - } - }, - "endpoint_uuid": { - "uuid": "1" - } - }, - { - "device_id": { - "device_uuid": { - "uuid": "R2" - } - }, - "endpoint_uuid": { - "uuid": "1001" - } - } - ], - "optical_link": { - "name": "T2-R2", - "details": { - "length": 0, - "source": "srgT", - "target": "muxT", - "fibers": [ - { - "ID": "M1", - "length": 0, - "src_port": "1", - "dst_port": "1001", - "local_peer_port": "1", - "remote_peer_port": "2001", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M2", - "length": 0, - "src_port": "2", - "dst_port": "1002", - "local_peer_port": "2", - "remote_peer_port": "2002", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M3", - "length": 0, - "src_port": "3", - "dst_port": "1003", - "local_peer_port": "3", - "remote_peer_port": "2003", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - } - ] - } - } - }, - { - "link_id": { - "link_uuid": { - "uuid": "R2->T2" - } - }, - "link_endpoint_ids": [ - { - "device_id": { - "device_uuid": { - "uuid": "R2" - } - }, - "endpoint_uuid": { - "uuid": "5" - } - }, - { - "device_id": { - "device_uuid": { - "uuid": "T2" - } - }, - "endpoint_uuid": { - "uuid": "6" - } - } - ], - "optical_link": { - "name": "R2-T2", - "details": { - "length": 0, - "source": "srgT", - "target": "muxT", - "fibers": [ - { - "ID": "M1", - "length": 0, - "src_port": "1001", - "dst_port": "1", - "local_peer_port": "2001", - "remote_peer_port": "1", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M2", - "length": 0, - "src_port": "1002", - "dst_port": "2", - "local_peer_port": "2002", - "remote_peer_port": "2", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M3", - "length": 0, - "src_port": "1003", - "dst_port": "3", - "local_peer_port": "2003", - "remote_peer_port": "3", + "src_port": "5", + "dst_port": "6", + "local_peer_port": "15", + "remote_peer_port": "6", "used": false, "c_slots": [ 1, diff --git a/src/opticalcontroller/tools.py b/src/opticalcontroller/tools.py index 3b3223d81b2fe4e80956c02afae1a71c429493cf..d91240d45c2d6896b93e338520b50b7e0ed2744d 100644 --- a/src/opticalcontroller/tools.py +++ b/src/opticalcontroller/tools.py @@ -1,17 +1,3 @@ -# 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 numpy as np from variables import * import json diff --git a/src/opticalcontroller/variables.py b/src/opticalcontroller/variables.py index cbb65200f2f0c5ef9cd490c1435fb7a9120e5d63..32fe4bd8d67a12af84864f0aba73c1059f26d394 100644 --- a/src/opticalcontroller/variables.py +++ b/src/opticalcontroller/variables.py @@ -1,17 +1,3 @@ -# 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. - debug = 1 Fl = 184800 diff --git a/src/service/Dockerfile b/src/service/Dockerfile index aed4ce64c60a7cfca5b80dc46e03bad18a017ca9..c48f1ab0ac47a2f6ddbc33e9a30075f9dea8d94c 100644 --- a/src/service/Dockerfile +++ b/src/service/Dockerfile @@ -62,15 +62,16 @@ RUN python3 -m pip install -r requirements.txt # Add component files into working directory WORKDIR /var/teraflow -COPY src/context/__init__.py context/__init__.py -COPY src/context/client/. context/client/ +COPY src/service/. service/ +#COPY src/context/__init__.py context/__init__.py +#COPY src/context/client/. context/client/ +COPY src/context/. context/. COPY src/device/__init__.py device/__init__.py COPY src/device/client/. device/client/ COPY src/pathcomp/frontend/__init__.py pathcomp/frontend/__init__.py COPY src/pathcomp/frontend/client/. pathcomp/frontend/client/ COPY src/e2e_orchestrator/__init__.py e2e_orchestrator/__init__.py COPY src/e2e_orchestrator/client/. e2e_orchestrator/client/ -COPY src/service/. service/ # Start the service ENTRYPOINT ["python", "-m", "service.service"] diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py index b06295deee528656ae30ed33e4dacc7d7d04a178..d9789be5d3c8d3a2385a38866cdb7baec731f45a 100644 --- a/src/service/service/ServiceServiceServicerImpl.py +++ b/src/service/service/ServiceServiceServicerImpl.py @@ -248,81 +248,80 @@ 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 = 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)) + 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.info('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('expected optical band not found') + LOGGER.debug('Using existing optical band') 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: - pathcomp_request.k_disjoint_path.num_disjoint = num_disjoint_paths # pylint: disable=no-member + if reply_txt is not None: + optical_reply = adapt_reply(devices, _service, reply_json, context_uuid_x, topology_uuid_x, optical_band_txt) + LOGGER.info('optical_reply={:s}'.format( + grpc_message_to_json_string(optical_reply))) + + tasks_scheduler.compose_from_pathcompreply( + optical_reply, is_delete=False) + else: + if num_disjoint_paths is None or num_disjoint_paths in {0, 1} : + pathcomp_request.shortest_path.Clear() # pylint: disable=no-member + else: + pathcomp_request.k_disjoint_path.num_disjoint = num_disjoint_paths # pylint: disable=no-member - LOGGER.debug('pathcomp_request={:s}'.format(grpc_message_to_json_string(pathcomp_request))) - pathcomp = PathCompClient() - pathcomp_reply = pathcomp.Compute(pathcomp_request) - pathcomp.close() - LOGGER.debug('pathcomp_reply={:s}'.format(grpc_message_to_json_string(pathcomp_reply))) + + pathcomp = PathCompClient() + pathcomp_reply = pathcomp.Compute(pathcomp_request) + pathcomp.close() + # Feed TaskScheduler with this path computation reply. TaskScheduler identifies inter-dependencies among # the services and connections retrieved and produces a schedule of tasks (an ordered list of tasks to be # executed) to implement the requested create/update operation. - tasks_scheduler.compose_from_pathcompreply(pathcomp_reply, is_delete=False) + tasks_scheduler.compose_from_pathcompreply(pathcomp_reply, is_delete=False) tasks_scheduler.execute_all() return service_with_uuids.service_id @@ -365,9 +364,10 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): 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) + if ("flow_id" in c_rules_dict): + flow_id = c_rules_dict["flow_id"] + + reply = delete_lightpath(flow_id, src, dst, bitrate) # Normal service diff --git a/src/service/service/__main__.py b/src/service/service/__main__.py index f2b6e38d6181a0c56b4f1dfca3116717d1400ced..52210c8ab41ede6cf8fefc02dad08f0e3ffa42e9 100644 --- a/src/service/service/__main__.py +++ b/src/service/service/__main__.py @@ -12,12 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging, signal, sys, threading +import logging, signal, sys, threading,os from prometheus_client import start_http_server from common.Constants import ServiceNameEnum from common.Settings import ( ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name, get_log_level, get_metrics_port, - wait_for_environment_variables) + wait_for_environment_variables,find_environment_variables) from .ServiceService import ServiceService from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory from .service_handlers import SERVICE_HANDLERS @@ -43,8 +43,16 @@ def main(): get_env_var_name(ServiceNameEnum.DEVICE, ENVVAR_SUFIX_SERVICE_PORT_GRPC), get_env_var_name(ServiceNameEnum.PATHCOMP, ENVVAR_SUFIX_SERVICE_HOST ), get_env_var_name(ServiceNameEnum.PATHCOMP, ENVVAR_SUFIX_SERVICE_PORT_GRPC), + get_env_var_name(ServiceNameEnum.PATHCOMP, ENVVAR_SUFIX_SERVICE_HOST), + get_env_var_name(ServiceNameEnum.PATHCOMP, ENVVAR_SUFIX_SERVICE_PORT_GRPC) + + ]) - + variables= find_environment_variables([ + get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER,ENVVAR_SUFIX_SERVICE_HOST), + get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER,ENVVAR_SUFIX_SERVICE_PORT_GRPC), + ]) + signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) diff --git a/src/service/service/service_handler_api/FilterFields.py b/src/service/service/service_handler_api/FilterFields.py index e771e24f17b2ea97c61158b65cb62c87ee9f37c5..633f41b63c71727d9ead0ee57b79002dc3a6cd97 100644 --- a/src/service/service/service_handler_api/FilterFields.py +++ b/src/service/service/service_handler_api/FilterFields.py @@ -26,6 +26,7 @@ SERVICE_TYPE_VALUES = { ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE, ServiceTypeEnum.SERVICETYPE_TE, ServiceTypeEnum.SERVICETYPE_E2E, + ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY } DEVICE_DRIVER_VALUES = { @@ -40,6 +41,7 @@ DEVICE_DRIVER_VALUES = { DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE, DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN, + DeviceDriverEnum.DEVICEDRIVER_OC } # Map allowed filter fields to allowed values per Filter field. If no restriction (free text) None is specified diff --git a/src/service/service/service_handlers/oc/OCServiceHandler.py b/src/service/service/service_handlers/oc/OCServiceHandler.py index 8ae42639315287cada0ca288cd5593240819cfc5..b2b0a86ee12e8ca335efd8cf5f445b647397fe58 100644 --- a/src/service/service/service_handlers/oc/OCServiceHandler.py +++ b/src/service/service/service_handlers/oc/OCServiceHandler.py @@ -15,19 +15,20 @@ 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.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 .OCTools import convert_endpoints_to_flows, handle_flows_names +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': 'oc'}) +METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'l3nm_emulated'}) class OCServiceHandler(_ServiceHandler): def __init__( # pylint: disable=super-init-not-called @@ -37,6 +38,73 @@ 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 @@ -53,29 +121,68 @@ class OCServiceHandler(_ServiceHandler): 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(): + 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("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("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 @@ -86,14 +193,29 @@ class OCServiceHandler(_ServiceHandler): chk_type('endpoints', endpoints, list) if len(endpoints) == 0: return [] - # TODO: to be checked and elaborated + 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))) - self.__task_executor.configure_device(device_obj) + 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))) diff --git a/src/service/service/service_handlers/oc/OCTools.py b/src/service/service/service_handlers/oc/OCTools.py index f40cb65bef2af5b69628c4167218bed59c92e317..529a1bc7f595bdfd32ce10a65599c4a7af2e8e12 100644 --- a/src/service/service/service_handlers/oc/OCTools.py +++ b/src/service/service/service_handlers/oc/OCTools.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - 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 @@ -26,7 +25,8 @@ def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]]) #entries = Dict[str: List[Tuple[str, str]]] entries = {} #tuple is in, out - end = len(endpoints) + #end = len(endpoints) if isinstance(endpoints,list) else 0 + end=len(endpoints) i = 0 bidir = 0 log.debug("end={}".format(end)) @@ -115,10 +115,14 @@ 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={} @@ -137,4 +141,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 + return new_flows \ No newline at end of file diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py index 6d24da4c0be05e1687536a836219bbfa15052504..48449e4d97573961f067141b2effb43a0825e2c3 100644 --- a/src/service/service/task_scheduler/TaskExecutor.py +++ b/src/service/service/task_scheduler/TaskExecutor.py @@ -12,13 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging #, json +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 @@ -115,32 +113,70 @@ 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=json.loads(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.info("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 index 227be2765fbd6bbc779e53505b833fc8bf08873f..a5529adc809f2b7d20c65093ab60ce9287eec787 100644 --- a/src/service/service/tools/OpticalTools.py +++ b/src/service/service/tools/OpticalTools.py @@ -15,14 +15,16 @@ import json import requests -import uuid +import uuid ,os 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 common.Constants import ServiceNameEnum +from common.Settings import ( + ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, find_environment_variables ,get_env_var_name) from context.service.database.uuids.EndPoint import endpoint_get_uuid @@ -30,9 +32,15 @@ from service.service.tools.replies import reply_uni_txt, optical_band_uni_txt, r log = logging.getLogger(__name__) -testing = True +testing = False - +opticalcontrollers_url= find_environment_variables([ + get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER,ENVVAR_SUFIX_SERVICE_HOST), + get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER,ENVVAR_SUFIX_SERVICE_PORT_GRPC), + ]) +OPTICAL_IP=opticalcontrollers_url[get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER,ENVVAR_SUFIX_SERVICE_HOST)] +OPTICAL_PORT=opticalcontrollers_url[get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER,ENVVAR_SUFIX_SERVICE_PORT_GRPC)] +log.info(OPTICAL_IP,OPTICAL_PORT) def get_uuids_from_names(devices: List[Device], device_name: str, port_name: str): device_uuid = "" @@ -134,6 +142,7 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b #add optical band connection first rules_ob= [] ob_id = 0 + connection_ob=None if optical_band_txt != "": ob_json = json.loads(optical_band_txt) ob = ob_json @@ -176,7 +185,7 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b 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)) + 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) @@ -184,21 +193,21 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b 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)) + 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)) + 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.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"] @@ -223,39 +232,39 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b 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)) + 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)) + 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)) + 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)) + 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: + if connection_ob is not None and 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"] + band = r["band"] if "band" in r else None + op_mode = r["op-mode"] if "op-mode" in r else None + frequency = r["freq"] if "freq" in r else None + flow_id = r["flow_id"] if "flow_id" in r else None + r_type = r["band_type"] if "band_type" in r else None if r_type == "l_slots": band_type = "L_BAND" elif r_type == "s_slots": @@ -263,14 +272,14 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b else: band_type = "C_BAND" - if ob_id is not 0: + if ob_id != 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) @@ -287,4 +296,4 @@ def add_service_to_reply(reply : PathCompReply, service : Service)-> Service: def add_connection_to_reply(reply : PathCompReply)-> Connection: conn = reply.connections.add() - return conn + return conn \ No newline at end of file diff --git a/startExtraNetConfigAgent.sh b/startExtraNetConfigAgent.sh new file mode 100755 index 0000000000000000000000000000000000000000..79efe377339ed5e911faefc96177dafbdf574035 --- /dev/null +++ b/startExtraNetConfigAgent.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +Docker_Container=$1 +Docker_Port=$2 +if [ -n "$Docker_Container" ] && [ -n "$Docker_Port" ];then + sudo docker stop "$Docker_Container" -t 1 + + sudo docker rm "$Docker_Container" + + + echo "Creating TPs" + screen -dmS t1 -T xterm sh -c "docker run -p 10.0.2.15:"$Docker_Port":2022 -v ~/tfs-ctrl/tempOC/files:/files --name $Docker_Container -it asgamb1/oc23bgp.img:latest" + sleep 2 + if [ "$( docker container inspect -f '{{.State.Running}}' "$Docker_Container")" = "true" ]; then + + docker exec "$Docker_Container" cp /files/demoECOC21_4.xml demoECOC21.xml + + docker exec "$Docker_Container" /confd/examples.confd/OC23/startNetconfAgent.sh + else + echo "your container is not running yet" + fi +else + echo "Please define the docker container name and port" +fi + diff --git a/start_topo.sh b/start_topo.sh new file mode 100755 index 0000000000000000000000000000000000000000..574d0c1d52ee6d12655dd66b950f2e5ffffc9c26 --- /dev/null +++ b/start_topo.sh @@ -0,0 +1,23 @@ +#!/bin/bash +asgamb1/flexscale-node.imgasgamb1/flexscale-node.imgasgamb1/flexscale-node.imgasgamb1/flexscale-node.img#!/bin/bash + +sudo docker stop na1 -t 1 +sudo docker stop na2 -t 1 +sudo docker stop na3 -t 1 +sudo docker stop na4 -t 1 + +sudo docker rm na2 +sudo docker rm na1 +sudo docker rm na3 +sudo docker rm na4 + +echo "Creating NewAgent" +echo " It may take a while , Hang on ..." +source "./startExtraNetConfigAgent.sh" "na1" "2023" +sleep 3 + +source "./startExtraNetConfigAgent.sh" "na2" "2024" +sleep 3 + +screen -dmS t3 -T xterm sh -c 'docker run -p 10.0.2.15:2025:2022 -v ~/tfs-ctrl/tempOC/files:/files --name na3 -it asgamb1/flexscale-node.img:latest ./startNetconfAgent.sh' +screen -dmS t4 -T xterm sh -c 'docker run -p 10.0.2.15:2026:2022 -v ~/tfs-ctrl/tempOC/files:/files --name na4 -it asgamb1/flexscale-node.img:latest ./startNetconfAgent.sh' \ No newline at end of file