From ca8d23f90f679da71c99c2ef15e674b51c2509d9 Mon Sep 17 00:00:00 2001 From: ismaeel <mohammad.ismaael@cnit.it> Date: Mon, 22 Apr 2024 05:16:33 +0000 Subject: [PATCH] Optical Link Integral --- .context.log.swp | Bin 0 -> 8192 bytes config.lo | 1 + deploy/tfs.sh | 1 + my_deploy.sh | 4 +- proto/context.proto | 54 +- src/common/tools/descriptor/Loader.py | 15 +- src/context/client/ContextClient.py | 30 +- .../service/ContextServiceServicerImpl.py | 23 +- src/context/service/database/Device.py | 37 +- src/context/service/database/Link.py | 2 + src/context/service/database/OpticalConfig.py | 9 +- src/context/service/database/OpticalLink.py | 194 ++ src/context/service/database/Topology.py | 11 +- .../service/database/models/DeviceModel.py | 3 + .../database/models/OpticalEndPointModel.py | 69 + .../database/models/OpticalLinkModel.py | 149 +- .../service/database/models/TopologyModel.py | 21 + .../service/database/uuids/EndPoint.py | 5 + .../service/database/uuids/OpticalEndPoint.py | 45 + .../service/database/uuids/OpticalLink.py | 21 + .../service/database/uuids/_Builder.py | 4 +- .../oc_driver/templates/VPN/physical.py | 28 +- src/opticalcontroller/Dockerfile | 22 +- src/opticalcontroller/OpticalController.py | 93 +- src/opticalcontroller/RSA.py | 383 ++-- src/opticalcontroller/__init__.py | 1 + src/opticalcontroller/dijsktra.py | 20 +- src/opticalcontroller/json_files/nodes.json | 32 +- src/opticalcontroller/json_files/tfs.json | 1790 ++++++++++++----- .../json_files/tfs_dict.json | 1458 ++++++++++++++ src/opticalcontroller/requirements.in | 29 +- src/opticalcontroller/requirements_opt.txt | 7 + src/opticalcontroller/test.py | 12 + src/opticalcontroller/tools.py | 66 +- src/opticalcontroller/variables.py | 16 +- .../service/ServiceServiceServicerImpl.py | 3 +- src/service/service/__main__.py | 7 +- src/service/service/tools/OpticalTools.py | 8 +- src/tests/ofc24/r_t.sh | 31 + src/tests/ofc24/roadms.sh | 26 + src/tests/ofc24/tempOC/files/platform_r1.xml | 121 +- src/tests/ofc24/tempOC/files/platform_r2.xml | 133 +- src/tests/ofc24/{copy.sh => transponders.sh} | 0 src/webui/service/__init__.py | 6 + src/webui/service/base_optical/__init__.py | 14 + src/webui/service/base_optical/route.py | 29 + src/webui/service/main/routes.py | 18 +- src/webui/service/optical_link/__init__.py | 14 + src/webui/service/optical_link/routes.py | 93 + src/webui/service/templates/base.html | 6 +- .../service/templates/base_optical/home.html | 40 + src/webui/service/templates/js/topology.js | 15 + src/webui/service/templates/link/detail.html | 3 +- src/webui/service/templates/link/home.html | 2 +- .../templates/optical_link/detail.html | 126 ++ .../service/templates/optical_link/home.html | 98 + .../service/templates/opticalconfig/home.html | 28 +- test.py | 80 +- 58 files changed, 4602 insertions(+), 954 deletions(-) create mode 100644 .context.log.swp create mode 100644 config.lo create mode 100644 src/context/service/database/OpticalLink.py create mode 100644 src/context/service/database/models/OpticalEndPointModel.py create mode 100644 src/context/service/database/uuids/OpticalEndPoint.py create mode 100644 src/context/service/database/uuids/OpticalLink.py create mode 100644 src/opticalcontroller/json_files/tfs_dict.json create mode 100644 src/opticalcontroller/requirements_opt.txt create mode 100644 src/opticalcontroller/test.py create mode 100644 src/tests/ofc24/r_t.sh create mode 100644 src/tests/ofc24/roadms.sh rename src/tests/ofc24/{copy.sh => transponders.sh} (100%) create mode 100644 src/webui/service/base_optical/__init__.py create mode 100644 src/webui/service/base_optical/route.py create mode 100644 src/webui/service/optical_link/__init__.py create mode 100644 src/webui/service/optical_link/routes.py create mode 100644 src/webui/service/templates/base_optical/home.html create mode 100644 src/webui/service/templates/optical_link/detail.html create mode 100644 src/webui/service/templates/optical_link/home.html diff --git a/.context.log.swp b/.context.log.swp new file mode 100644 index 0000000000000000000000000000000000000000..bab7729c124bd1a470885e2307011e49de2ddb1e GIT binary patch literal 8192 zcmeIuJqp4=5QgE2g`MEf1!Ao8V{CE-3(MFF24fSA=px$ajXaze&|O$l*ldwT;hko7 zmv4vRStrZ+!q1{qboE89tDp??Odij!sPbf9ouzZ(dFPDDO$TEWF4VD#i+Zm%7Zp|Y z*8P<P0tmDg=*cXdCT7ee82h7P-g+Vf5I_I{1Q0*~0R#|0;C}?v!IQgQ_hoBfSNCl1 ie06(m+9%gMa6kY71Q0*~0R#|0009ILKmdWC6L<qCxgNv- literal 0 HcmV?d00001 diff --git a/config.lo b/config.lo new file mode 100644 index 000000000..f35fe4763 --- /dev/null +++ b/config.lo @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8"?><data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"><interfaces xmlns="http://openconfig.net/yang/interfaces"><interface><name>eth0</name><config><name>eth0</name><enabled>true</enabled></config><ipv4 xmlns="http://openconfig.net/yang/interfaces/ip"><addresses><address><ip>192.168.1.1</ip><config><ip>192.168.1.1</ip><prefix-length>24</prefix-length></config></address></addresses></ipv4></interface></interfaces><components xmlns="http://openconfig.net/yang/platform"><component><name>channel-1</name><config><name>channel-1</name></config><state><name>channel-1</name><type xmlns:oc-opt-types="http://openconfig.net/yang/transport-types">oc-opt-types:OPTICAL_CHANNEL</type></state><optical-channel xmlns="http://openconfig.net/yang/terminal-device"><config><frequency>191600000</frequency><target-output-power>100.0</target-output-power><operational-mode>0</operational-mode><line-port>transceiver-1</line-port></config><state><frequency>191600000</frequency><target-output-power>0.0</target-output-power><operational-mode>0</operational-mode><line-port>transceiver-1</line-port><group-id>1</group-id><output-power><instant>0.0</instant><avg>0.0</avg><min>0.0</min><max>0.0</max><interval>0</interval></output-power><input-power><instant>0.0</instant><avg>0.0</avg><min>0.0</min><max>0.0</max><interval>0</interval></input-power><laser-bias-current><instant>0.0</instant><avg>0.0</avg><min>0.0</min><max>0.0</max><interval>0</interval></laser-bias-current><chromatic-dispersion><instant>0.0</instant><avg>0.0</avg><min>0.0</min><max>0.0</max></chromatic-dispersion><polarization-mode-dispersion><instant>0.0</instant><avg>0.0</avg><min>0.0</min><max>0.0</max></polarization-mode-dispersion><second-order-polarization-mode-dispersion><instant>0.0</instant><avg>0.0</avg><min>0.0</min><max>0.0</max></second-order-polarization-mode-dispersion><polarization-dependent-loss><instant>0.0</instant><avg>0.0</avg><min>0.0</min><max>0.0</max><interval>0</interval></polarization-dependent-loss></state></optical-channel></component><component><name>device</name><config><name>device</name></config><state><name>MellanoxSwitch</name><type xmlns:oc-platform-types="http://openconfig.net/yang/platform-types">oc-platform-types:OPERATING_SYSTEM</type><mfg-name>SSSA-CNIT</mfg-name><hardware-version>1.0.0</hardware-version><firmware-version>1.0.0</firmware-version><software-version>1.0.0</software-version><serial-no>610610</serial-no></state></component><component><name>port-1</name><config><name>port-1</name></config><state><name>port-1</name><type xmlns:oc-platform-types="http://openconfig.net/yang/platform-types">oc-platform-types:PORT</type></state><properties><property><name>odtn-port-type</name><config><name>odtn-port-type</name><value>line</value></config><state><name>odtn-port-type</name><value>line</value></state></property><property><name>onos-index</name><config><name>onos-index</name><value>4</value></config><state><name>onos-index</name><value>4</value></state></property></properties><subcomponents><subcomponent><name>channel-1</name><config><name>channel-1</name></config><state><name>channel-1</name></state></subcomponent></subcomponents></component><component><name>transceiver-1</name><config><name>transceiver-1</name></config><state><name>transceiver-1</name><type xmlns:oc-platform-types="http://openconfig.net/yang/platform-types">oc-platform-types:TRANSCEIVER</type></state><transceiver xmlns="http://openconfig.net/yang/platform/transceiver"><config><enabled>true</enabled><form-factor-preconf xmlns:oc-opt-types="http://openconfig.net/yang/transport-types">oc-opt-types:QSFP56_DD_TYPE1</form-factor-preconf><ethernet-pmd-preconf xmlns:oc-opt-types="http://openconfig.net/yang/transport-types">oc-opt-types:ETH_400GBASE_ZR</ethernet-pmd-preconf><fec-mode xmlns:oc-platform-types="http://openconfig.net/yang/platform-types">oc-platform-types:FEC_AUTO</fec-mode><module-functional-type xmlns:oc-opt-types="http://openconfig.net/yang/transport-types">oc-opt-types:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type></config><state><enabled>true</enabled><form-factor-preconf xmlns:oc-opt-types="http://openconfig.net/yang/transport-types">oc-opt-types:QSFP56_DD_TYPE1</form-factor-preconf><ethernet-pmd-preconf xmlns:oc-opt-types="http://openconfig.net/yang/transport-types">oc-opt-types:ETH_400GBASE_ZR</ethernet-pmd-preconf><fec-mode xmlns:oc-platform-types="http://openconfig.net/yang/platform-types">oc-platform-types:FEC_AUTO</fec-mode><module-functional-type xmlns:oc-opt-types="http://openconfig.net/yang/transport-types">oc-opt-types:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type><vendor>Cisco</vendor><vendor-part>400zr-QSFP-DD</vendor-part><vendor-rev>01</vendor-rev><serial-no>1567321</serial-no></state><physical-channels><channel><index>1</index><config><index>1</index><associated-optical-channel>channel-1</associated-optical-channel></config></channel></physical-channels></transceiver></component></components><bgp-instance xmlns="http://openconfig.net/yang/protocols"><bgp><neighbors><neighbor><neighbor-address>192.168.1.1</neighbor-address><config><neighbor-address>192.168.1.1</neighbor-address><neighbor-port>88</neighbor-port><enabled>true</enabled><peer-as>65432</peer-as></config></neighbor></neighbors></bgp></bgp-instance><terminal-device xmlns="http://openconfig.net/yang/terminal-device"><logical-channels><channel><index>1</index><config><index>1</index><description>Logical channel 1</description><admin-state>DISABLED</admin-state><logical-channel-type xmlns:oc-opt-types="http://openconfig.net/yang/transport-types">oc-opt-types:PROT_OTN</logical-channel-type><loopback-mode>NONE</loopback-mode></config><state><index>1</index><description>Logical channel 1</description><admin-state>DISABLED</admin-state><logical-channel-type xmlns:oc-opt-types="http://openconfig.net/yang/transport-types">oc-opt-types:PROT_OTN</logical-channel-type><loopback-mode>NONE</loopback-mode><link-state>UP</link-state></state><ingress><config><transceiver>transceiver-1</transceiver></config><state><transceiver>transceiver-1</transceiver></state></ingress><logical-channel-assignments><assignment><index>1</index><config><index>1</index><description>Optical channel assigned 100</description><assignment-type>OPTICAL_CHANNEL</assignment-type><optical-channel>channel-1</optical-channel><allocation>100.0</allocation></config><state><index>1</index><description>Optical channel assigned 100</description><assignment-type>OPTICAL_CHANNEL</assignment-type><optical-channel>channel-1</optical-channel><allocation>100.0</allocation></state></assignment></logical-channel-assignments></channel></logical-channels><operational-modes><mode><mode-id>1</mode-id><state><mode-id>1</mode-id><description>FEC1</description><vendor-id>Ericsson</vendor-id></state></mode><mode><mode-id>2</mode-id><state><mode-id>2</mode-id><description>FEC2</description><vendor-id>Ericsson</vendor-id></state></mode></operational-modes></terminal-device><aaa xmlns="http://tail-f.com/ns/aaa/1.1"><authentication><users><user><name>admin</name><uid>9000</uid><gid>100</gid><password>$1$HWfCFyTg$TOxt04aLi5ONWrSB8X94U.</password><ssh_keydir>/var/confd/homes/admin/.ssh</ssh_keydir><homedir>/var/confd/homes/admin</homedir></user><user><name>oper</name><uid>9003</uid><gid>103</gid><password>$1$D8R6MYXb$ah52S1b/zOYSlbVU9MS/21</password><ssh_keydir>/var/confd/homes/oper/.ssh</ssh_keydir><homedir>/var/confd/homes/oper</homedir></user><user><name>optical</name><uid>9001</uid><gid>101</gid><password>$1$qJM5YOJZ$Y1ECCKsRIgMFJBk.hrjkv1</password><ssh_keydir>/var/confd/homes/optical/.ssh</ssh_keydir><homedir>/var/confd/homes/optical</homedir></user><user><name>packet</name><uid>9002</uid><gid>102</gid><password>$1$Fmz.hLNd$8yG5nYZhSPNPjinrCWId8.</password><ssh_keydir>/var/confd/homes/packet/.ssh</ssh_keydir><homedir>/var/confd/homes/packet</homedir></user><user><name>private</name><uid>9005</uid><gid>103</gid><password>$1$4uQVo9HU$xjyOZc8JhotXBtfcFV7MX.</password><ssh_keydir>/var/confd/homes/private/.ssh</ssh_keydir><homedir>/var/confd/homes/private</homedir></user><user><name>public</name><uid>9004</uid><gid>100</gid><password>$1$YhqvvCDs$LAGH/GQUMGMbqTUMWpapD1</password><ssh_keydir>/var/confd/homes/public/.ssh</ssh_keydir><homedir>/var/confd/homes/public</homedir></user></users></authentication><ios><level><nr>0</nr><prompt>\h> </prompt></level><level><nr>15</nr><prompt>\h# </prompt></level><privilege><mode>exec</mode><level><nr>0</nr><command><name>action</name></command><command><name>autowizard</name></command><command><name>enable</name></command><command><name>exit</name></command><command><name>help</name></command><command><name>startup</name></command></level><level><nr>15</nr><command><name>configure</name></command></level></privilege></ios></aaa><nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"><enable-nacm>true</enable-nacm><read-default>permit</read-default><write-default>permit</write-default><exec-default>permit</exec-default><enable-external-groups>true</enable-external-groups><groups><group><name>admin</name><user-name>admin</user-name><user-name>private</user-name></group><group><name>oper</name><user-name>oper</user-name><user-name>public</user-name></group><group><name>opt</name><user-name>optical</user-name></group><group><name>pck</name><user-name>packet</user-name></group></groups><rule-list><name>any-group</name><group>*</group><rule><name>get</name><module-name>*</module-name><path>/</path><access-operations>read</access-operations><action>permit</action></rule><rule><name>tailf-aaa-authentication</name><module-name>tailf-aaa</module-name><path>/aaa/authentication/users/user[name='$USER']</path><access-operations>read update</access-operations><action>permit</action></rule><rule><name>tailf-aaa-user</name><module-name>tailf-aaa</module-name><path>/user[name='$USER']</path><access-operations>create read update delete</access-operations><action>permit</action></rule><rule><name>tailf-webui-user</name><module-name>tailf-webui</module-name><path>/webui/data-stores/user-profile[username='$USER']</path><access-operations>create read update delete</access-operations><action>permit</action></rule></rule-list><rule-list><name>packet</name><group>pck</group><rule><name>vlan</name><module-name>vlan</module-name><path>/switched-vlans</path><access-operations>create read update delete</access-operations><action>permit</action></rule><rule><name>terminal-device</name><module-name>*</module-name><path>/terminal-device</path><access-operations>create update delete</access-operations><action>deny</action></rule><rule><name>components</name><module-name>*</module-name><path>/components</path><access-operations>create update delete</access-operations><action>deny</action></rule></rule-list><rule-list><name>optical</name><group>opt</group><rule><name>terminal-device</name><module-name>*</module-name><path>/terminal-device</path><access-operations>create read update delete</access-operations><action>permit</action></rule><rule><name>components</name><module-name>*</module-name><path>/components</path><access-operations>create read update delete</access-operations><action>permit</action></rule><rule><name>vlan</name><module-name>vlan</module-name><path>/switched-vlans</path><access-operations>create update delete</access-operations><action>deny</action></rule></rule-list><rule-list><name>admin</name><group>admin</group><rule><name>any-access</name><action>permit</action></rule></rule-list></nacm></data> diff --git a/deploy/tfs.sh b/deploy/tfs.sh index fd49c9758..96c1b6186 100755 --- a/deploy/tfs.sh +++ b/deploy/tfs.sh @@ -368,6 +368,7 @@ printf "\n" for COMPONENT in $TFS_COMPONENTS; do echo "Waiting for '$COMPONENT' component..." COMPONENT_OBJNAME=$(echo "${COMPONENT}" | sed "s/\_/-/") + kubectl wait --namespace $TFS_K8S_NAMESPACE \ --for='condition=available' --timeout=90s deployment/${COMPONENT_OBJNAME}service WAIT_EXIT_CODE=$? diff --git a/my_deploy.sh b/my_deploy.sh index 9e4447349..7bb15dd96 100755 --- a/my_deploy.sh +++ b/my_deploy.sh @@ -20,7 +20,7 @@ export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/" # Set the list of components, separated by spaces, you want to build images for, and deploy. -export TFS_COMPONENTS="context device pathcomp opticalcontroller service slice nbi webui " +export TFS_COMPONENTS="context device pathcomp opticalcontroller service slice webui " # Uncomment to activate Monitoring #export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" @@ -102,7 +102,7 @@ export CRDB_DEPLOY_MODE="single" export CRDB_DROP_DATABASE_IF_EXISTS="" # Disable flag for re-deploying CockroachDB from scratch. -export CRDB_REDEPLOY="" +export CRDB_REDEPLOY="YES" # ----- NATS ------------------------------------------------------------------- diff --git a/proto/context.proto b/proto/context.proto index 55c412119..465e235d4 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -83,9 +83,10 @@ service ContextService { rpc DeleteOpticalConfig(OpticalConfigId) returns (Empty ) {} rpc SetOpticalLink (OpticalLink ) returns (Empty ) {} - rpc GetOpticalLink (OpticalLinkId ) returns (OpticalLink ) {} - rpc GetFiber (FiberId ) returns (Fiber ) {} -} + rpc GetOpticalLink (LinkId ) returns (OpticalLink ) {} + rpc DeleteOpticalLink (LinkId ) returns (Empty ) {} + rpc GetOpticalLinkList (Empty) returns (OpticalLinkList) {} + } // ----- Generic ------------------------------------------------------------------------------------------------------- message Empty {} @@ -149,6 +150,8 @@ message Topology { string name = 2; repeated DeviceId device_ids = 3; repeated LinkId link_ids = 4; + + repeated LinkId optical_link_ids=5; } message TopologyDetails { @@ -156,6 +159,8 @@ message TopologyDetails { string name = 2; repeated Device devices = 3; repeated Link links = 4; + + repeated OpticalLink optical_links =5 ; } message TopologyIdList { @@ -647,37 +652,34 @@ message OpticalConfigEvent { // ---- Optical Link ---- -message OpticalLinkId { - Uuid optical_link_uuid = 1; +message OpticalEndPointId { + + DeviceId device_id = 2; + Uuid endpoint_uuid = 3; } -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 OpticalLinkList { + repeated OpticalLink optical_links = 1; } + + + message OpticalLinkDetails { float length = 1; - string source = 2; - string target = 3; - repeated Fiber fibers = 4; + string src_port = 2; + string dst_port = 3; + string local_peer_port = 4; + string remote_peer_port = 5 ; + bool used = 6 ; + map< string ,int32 > c_slots = 7; + map< string ,int32 > l_slots = 8; + map< string ,int32 > s_slots = 9; } message OpticalLink { string name = 1; - OpticalLinkDetails details = 2; - OpticalLinkId optical_link_uuid = 3; + OpticalLinkDetails optical_details = 2; + LinkId link_id = 3; + repeated EndPointId link_endpoint_ids=4; } diff --git a/src/common/tools/descriptor/Loader.py b/src/common/tools/descriptor/Loader.py index 4ab33beae..6def79da6 100644 --- a/src/common/tools/descriptor/Loader.py +++ b/src/common/tools/descriptor/Loader.py @@ -37,7 +37,7 @@ import concurrent.futures, json, logging, operator from typing import Any, Dict, List, Optional, Tuple, Union from common.proto.context_pb2 import ( Connection, Context, ContextId, Device, DeviceId, Empty, Link, LinkId, Service, ServiceId, Slice, SliceId, - Topology, TopologyId) + Topology, TopologyId , OpticalLink) from common.tools.object_factory.Context import json_context_id from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient @@ -107,6 +107,12 @@ class DescriptorLoader: self.__services = self.__descriptors.get('services' , []) self.__slices = self.__descriptors.get('slices' , []) self.__connections = self.__descriptors.get('connections', []) + + #--------------- Experimental Optical Link -------------- + + self.__optical_links = self.__descriptors.get("optical_links",[]) + + self.__contexts_add = None self.__topologies_add = None @@ -211,6 +217,10 @@ class DescriptorLoader: @property def num_connections(self) -> int: return len(self.__connections) + + #------------- Experimental --------------- + @property + def optical_links(self) -> List[Dict]: return self.__optical_links def process(self) -> TypeResults: # Format CustomConfigRules in Devices, Services and Slices provided in JSON format @@ -282,6 +292,9 @@ class DescriptorLoader: self._process_descr('service', 'update', self.__svc_cli.UpdateService, Service, self.__services ) self._process_descr('slice', 'add', self.__slc_cli.CreateSlice, Slice, self.__slices_add ) self._process_descr('slice', 'update', self.__slc_cli.UpdateSlice, Slice, self.__slices ) + + #----------------------------------- Experimental --------------------------------------- + self._process_descr('link', 'add', self.__ctx_cli.SetOpticalLink, OpticalLink, self.__optical_links ) # By default the Context component automatically assigns devices and links to topologies based on their # endpoints, and assigns topologies, services, and slices to contexts based on their identifiers. diff --git a/src/context/client/ContextClient.py b/src/context/client/ContextClient.py index 3ca4ea16a..b325bece3 100644 --- a/src/context/client/ContextClient.py +++ b/src/context/client/ContextClient.py @@ -27,7 +27,7 @@ from common.proto.context_pb2 import ( Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, - OpticalConfig, OpticalConfigId, OpticalConfigList + OpticalConfig, OpticalConfigId, OpticalConfigList , OpticalLink ,OpticalLinkList ) from common.proto.context_pb2_grpc import ContextServiceStub from common.proto.context_policy_pb2_grpc import ContextPolicyServiceStub @@ -467,3 +467,31 @@ class ContextClient: response = self.stub.DeleteOpticalConfig(request) LOGGER.debug('DeleteOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response))) return response + + #--------------------------- Optical Link ------------------------ + def GetOpticalLinkList(self, request: Empty) -> OpticalLinkList: + LOGGER.debug('ListOpticalLinks request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.GetOpticalLinkList(request) + LOGGER.debug('ListOpticalLinks result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + @RETRY_DECORATOR + def GetOpticalLink(self, request: LinkId) -> OpticalLink: + LOGGER.debug('GetOpticalLink request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.GetOpticalLink(request) + LOGGER.debug('GetOpticalLink result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + @RETRY_DECORATOR + def SetOpticalLink(self, request: OpticalLink) -> LinkId: + LOGGER.debug('SetOpticalLink request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.SetOpticalLink(request) + LOGGER.debug('SetOpticalLink result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + @RETRY_DECORATOR + def DeleteOpticalLink(self, request: LinkId) -> Empty: + LOGGER.debug('RemoveOpticalLink request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.DeleteOpticalLink(request) + LOGGER.debug('RemoveOpticalLink result: {:s}'.format(grpc_message_to_json_string(response))) + return response \ No newline at end of file diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py index 2b6c61ebe..e75f3a5c7 100644 --- a/src/context/service/ContextServiceServicerImpl.py +++ b/src/context/service/ContextServiceServicerImpl.py @@ -24,7 +24,7 @@ from common.proto.context_pb2 import ( Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, - OpticalConfigList, OpticalConfigId, OpticalConfig + OpticalConfigList, OpticalConfigId, OpticalConfig ,OpticalLink , OpticalLinkList, ) from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule from common.proto.context_pb2_grpc import ContextServiceServicer @@ -47,6 +47,7 @@ from .database.Topology import ( topology_delete, topology_get, topology_get_details, topology_list_ids, topology_list_objs, topology_set) from .database.OpticalConfig import set_opticalconfig, select_opticalconfig, get_opticalconfig ,delete_opticalconfig +from .database.OpticalLink import optical_link_delete,optical_link_get,optical_link_list_objs,optical_link_set LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Context', 'RPC') @@ -324,3 +325,23 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer delete_opticalconfig(self.db_engine,self.messagebroker, request) return Empty() + + + #--------------------- Experimental Optical Link ------------------- + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def GetOpticalLinkList(self, request : Empty, context : grpc.ServicerContext) -> OpticalLinkList: + return optical_link_list_objs(self.db_engine) + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def GetOpticalLink(self, request : LinkId, context : grpc.ServicerContext) -> OpticalLink: + return optical_link_get(self.db_engine, request) + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def SetOpticalLink(self, request : Link, context : grpc.ServicerContext) -> LinkId: + return optical_link_set(self.db_engine, self.messagebroker, request) + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def DeleteOpticalLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty: + return optical_link_delete(self.db_engine, self.messagebroker, request) + diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py index 6c3bd24e0..942e6f115 100644 --- a/src/context/service/database/Device.py +++ b/src/context/service/database/Device.py @@ -39,6 +39,7 @@ from .uuids.EndPoint import endpoint_get_uuid from .ConfigRule import compose_config_rules_data, upsert_config_rules from .Component import compose_components_data from .Events import notify_event_context, notify_event_device, notify_event_topology +from .models.OpticalEndPointModel import OpticalEndPointModel LOGGER = logging.getLogger(__name__) @@ -106,7 +107,8 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi topology_uuids.add(topology_uuid) is_oc_driver = DeviceDriverEnum.DEVICEDRIVER_OC in set(request.device_drivers) - + optical_endpoints_data : List[Dict] = list() + LOGGER.info(f"is_oc_driver {is_oc_driver}") endpoints_data : List[Dict] = list() for i, endpoint in enumerate(request.device_endpoints): endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid @@ -136,7 +138,21 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi 'created_at' : now, 'updated_at' : now, }) - LOGGER.info(f"endpoint data {endpoints_data}") + # ------------------- Experimental ----------------------- + + if is_oc_driver: + + optical_endpoints_data.append({ + 'endpoint_uuid' : endpoint_uuid, + 'device_uuid' : endpoint_device_uuid, + 'name' : endpoint_name, + 'endpoint_type' : endpoint.endpoint_type, + 'created_at' : now, + 'updated_at' : now, + }) + + + if endpoint_topology_uuid not in topology_uuids: related_topologies.append({ @@ -192,6 +208,23 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi stmt = stmt.returning(EndPointModel.created_at, EndPointModel.updated_at) endpoint_updates = session.execute(stmt).fetchall() updated_endpoints = any([(updated_at > created_at) for created_at,updated_at in endpoint_updates]) + + #---------------------- Experimental --------------------------------- + + if len(optical_endpoints_data) > 0: + LOGGER.info(f"Optical endpoint data_ device_model {optical_endpoints_data}") + stmt = insert(OpticalEndPointModel).values(optical_endpoints_data) + stmt = stmt.on_conflict_do_update( + index_elements=[OpticalEndPointModel.endpoint_uuid], + set_=dict( + name = stmt.excluded.name, + endpoint_type = stmt.excluded.endpoint_type, + updated_at = stmt.excluded.updated_at, + ) + ) + stmt = stmt.returning(OpticalEndPointModel.created_at, OpticalEndPointModel.updated_at) + optical_endpoint_updates = session.execute(stmt).fetchall() + updated_optical_endpoints = any([(updated_at > created_at) for created_at,updated_at in endpoint_updates]) device_topology_ids = [] if not updated or len(related_topologies) > 1: diff --git a/src/context/service/database/Link.py b/src/context/service/database/Link.py index ccc22a472..119571dd8 100644 --- a/src/context/service/database/Link.py +++ b/src/context/service/database/Link.py @@ -63,6 +63,7 @@ def link_get(db_engine : Engine, request : LinkId) -> Link: return Link(**obj) def link_set(db_engine : Engine, messagebroker : MessageBroker, request : Link) -> LinkId: + raw_link_uuid = request.link_id.link_uuid.uuid raw_link_name = request.name link_name = raw_link_uuid if len(raw_link_name) == 0 else raw_link_name @@ -83,6 +84,7 @@ def link_set(db_engine : Engine, messagebroker : MessageBroker, request : Link) link_endpoints_data : List[Dict] = list() for i,endpoint_id in enumerate(request.link_endpoint_ids): + logging.info(f"links endpoint_id is {endpoint_id}") endpoint_topology_uuid, _, endpoint_uuid = endpoint_get_uuid( endpoint_id, allow_random=False) diff --git a/src/context/service/database/OpticalConfig.py b/src/context/service/database/OpticalConfig.py index 3884e5f57..281634df8 100644 --- a/src/context/service/database/OpticalConfig.py +++ b/src/context/service/database/OpticalConfig.py @@ -31,7 +31,7 @@ def get_opticalconfig(db_engine : Engine): results = session.query(OpticalConfigModel).all() for obj in results: - LOGGER.info(f"opticaln config obj from context {obj.dump()}") + optical_config = OpticalConfig() optical_config.config = json.dumps(obj.dump()) @@ -42,7 +42,7 @@ def get_opticalconfig(db_engine : Engine): return obj def set_opticalconfig(db_engine : Engine, request : OpticalConfig): - LOGGER.info(f"request {request} ") + opticalconfig_id = OpticalConfigId() opticalconfig_id.opticalconfig_uuid = request.opticalconfig_id.opticalconfig_uuid OpticalConfig_data = [] @@ -79,8 +79,7 @@ def set_opticalconfig(db_engine : Engine, request : OpticalConfig): ) - LOGGER.info(f"optical config to set {OpticalConfig_data} ") - LOGGER.info(f"channels {channels}") + def callback(session:Session)->bool: stmt = insert(OpticalConfigModel).values(OpticalConfig_data) @@ -109,7 +108,7 @@ def set_opticalconfig(db_engine : Engine, request : OpticalConfig): ) stmt = stmt.returning(OpticalChannelModel.channel_uuid) opticalChannel_id = session.execute(stmt).fetchone() - LOGGER.info(f"new optical channel config {opticalChannel_id}") + opticalconfig_id = run_transaction(sessionmaker(bind=db_engine), callback) return {'opticalconfig_uuid': opticalconfig_id} diff --git a/src/context/service/database/OpticalLink.py b/src/context/service/database/OpticalLink.py new file mode 100644 index 000000000..b6efabbff --- /dev/null +++ b/src/context/service/database/OpticalLink.py @@ -0,0 +1,194 @@ +# 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 datetime, logging +from sqlalchemy.dialects.postgresql import insert +from sqlalchemy.engine import Engine +from sqlalchemy import inspect +from sqlalchemy.orm import Session, selectinload, sessionmaker +from sqlalchemy_cockroachdb import run_transaction +from typing import Dict, List, Optional, Set, Tuple +from common.proto.context_pb2 import Empty, EventTypeEnum, OpticalLink, LinkId, OpticalLinkList, TopologyId +from common.message_broker.MessageBroker import MessageBroker +from common.method_wrappers.ServiceExceptions import NotFoundException +from common.tools.object_factory.Link import json_link_id +from context.service.database.uuids.Topology import topology_get_uuid +from .models.OpticalLinkModel import OpticalLinkModel,OpticalLinkEndPointModel +from .models.OpticalEndPointModel import OpticalEndPointModel +from .models.TopologyModel import TopologyOpticalLinkModel, TopologyModel +from .uuids.OpticalEndPoint import optical_endpoint_get_uuid +from .uuids.Link import link_get_uuid +from .uuids.OpticalLink import opticaldetail_get_uuid +from .Events import notify_event_context, notify_event_link, notify_event_topology +from .uuids.EndPoint import endpoint_get_uuid + +LOGGER = logging.getLogger(__name__) + + + +def optical_link_list_objs(db_engine : Engine) -> OpticalLinkList: + def callback(session : Session) -> List[Dict]: + obj_list : List[OpticalLinkModel] = session.query(OpticalLinkModel)\ + .options(selectinload(OpticalLinkModel.opticallink_endpoints))\ + .all() + return [obj.dump() for obj in obj_list] + links = run_transaction(sessionmaker(bind=db_engine), callback) + return OpticalLinkList(optical_links=links) + +def optical_link_get(db_engine : Engine, request : LinkId) -> OpticalLink: + link_uuid = link_get_uuid(request, allow_random=False) + def callback(session : Session) -> Optional[Dict]: + obj : Optional[OpticalLinkModel] = session.query(OpticalLinkModel)\ + .options(selectinload(OpticalLinkModel.opticallink_endpoints))\ + .filter_by(opticallink_uuid=link_uuid).one_or_none() + return None if obj is None else obj.dump() + obj = run_transaction(sessionmaker(bind=db_engine), callback) + if obj is None: + raw_link_uuid = request.link_uuid.uuid + raise NotFoundException('Optical Link', raw_link_uuid, extra_details=[ + 'link_uuid generated was: {:s}'.format(link_uuid) + ]) + return OpticalLink(**obj) + +def optical_link_set(db_engine : Engine, messagebroker : MessageBroker, request : OpticalLink) -> LinkId: + raw_link_uuid = request.link_id.link_uuid.uuid + raw_link_name = request.name + link_name = raw_link_uuid if len(raw_link_name) == 0 else raw_link_name + link_uuid = link_get_uuid(request.link_id, link_name=link_name, allow_random=True) + + now = datetime.datetime.utcnow() + + # By default, always add link to default Context/Topology + + + topology_uuids : Set[str] = set() + related_topologies : List[Dict] = list() + _,topology_uuid = topology_get_uuid(TopologyId(), allow_random=False, allow_default=True) + related_topologies.append({ + 'topology_uuid': topology_uuid, + 'optical_link_uuid' : link_uuid, + }) + topology_uuids.add(topology_uuid) + + link_endpoints_data : List[Dict] = list() + + for i,endpoint_id in enumerate(request.link_endpoint_ids): + endpoint_topology_uuid, endpoint_device_uuid, endpoint_uuid = endpoint_get_uuid( + endpoint_id, endpoint_name="", allow_random=True) + + link_endpoints_data.append({ + 'link_uuid' : link_uuid, + 'endpoint_uuid': endpoint_uuid, + + }) + + if endpoint_topology_uuid not in topology_uuids: + related_topologies.append({ + 'topology_uuid': endpoint_topology_uuid, + 'optical_link_uuid' : link_uuid, + }) + topology_uuids.add(endpoint_topology_uuid) + + + + + + optical_link_data = [{ + 'opticallink_uuid' : link_uuid, + 'name' : link_name, + 'created_at' : now, + 'updated_at' : now, + 'length' : request.optical_details.length, + "src_port" : request.optical_details.src_port, + "dst_port" : request.optical_details.dst_port, + "local_peer_port" : request.optical_details.local_peer_port, + "remote_peer_port" : request.optical_details.remote_peer_port, + "used" : request.optical_details.used, + "c_slots" : request.optical_details.c_slots , + "l_slots" : request.optical_details.l_slots, + "s_slots" : request.optical_details.s_slots, + + }] + + LOGGER.info(f"setting Optical link data {optical_link_data}") + def callback(session : Session) -> Tuple[bool, List[Dict]]: + stmt = insert(OpticalLinkModel).values(optical_link_data) + stmt = stmt.on_conflict_do_update( + index_elements=[OpticalLinkModel.opticallink_uuid], + set_=dict( + name = stmt.excluded.name, + updated_at = stmt.excluded.updated_at, + ) + ) + stmt = stmt.returning(OpticalLinkModel.created_at, OpticalLinkModel.updated_at) + created_at,updated_at = session.execute(stmt).fetchone() + updated = updated_at > created_at + + updated_endpoints = False + + + + if len(link_endpoints_data) > 0: + LOGGER.info(f"from OpticalLink Model endpoint data {link_endpoints_data}") + stmt = insert(OpticalLinkEndPointModel).values(link_endpoints_data) + stmt = stmt.on_conflict_do_nothing( + index_elements=[OpticalLinkEndPointModel.link_uuid, OpticalLinkEndPointModel.endpoint_uuid] + ) + link_endpoint_inserts = session.execute(stmt) + updated_endpoints = int(link_endpoint_inserts.rowcount) > 0 + + if not updated or len(related_topologies) > 1: + # Only update topology-link relations when link is created (not updated) or when endpoint_ids are + # modified (len(related_topologies) > 1). + stmt = insert(TopologyOpticalLinkModel).values(related_topologies) + stmt = stmt.on_conflict_do_nothing( + index_elements=[TopologyOpticalLinkModel.topology_uuid, TopologyOpticalLinkModel.optical_link_uuid] + ) + stmt = stmt.returning(TopologyOpticalLinkModel.topology_uuid) + topology_uuids = session.execute(stmt).fetchall() + + #LOGGER.warning('RAW topology_uuids={:s}'.format(str(topology_uuids))) + if len(topology_uuids) > 0: + topology_uuids = [topology_uuid[0] for topology_uuid in topology_uuids] + #LOGGER.warning('NEW topology_uuids={:s}'.format(str(topology_uuids))) + query = session.query(TopologyModel) + query = query.filter(TopologyModel.topology_uuid.in_(topology_uuids)) + link_topologies : List[TopologyModel] = query.all() + link_topology_ids = [obj.dump_id() for obj in link_topologies] + #LOGGER.warning('link_topology_ids={:s}'.format(str(link_topology_ids))) + + + return updated or updated_endpoints + + updated = run_transaction(sessionmaker(bind=db_engine), callback ) + link_id = json_link_id(link_uuid) + event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE + notify_event_link(messagebroker, event_type, link_id) + + return LinkId(**link_id) + +def optical_link_delete(db_engine : Engine, messagebroker : MessageBroker, request : LinkId) -> Empty: + link_uuid = link_get_uuid(request, allow_random=False) + def callback(session : Session) -> bool: + + query = query.filter_by(link_uuid=link_uuid) + + num_deleted = session.query(OpticalLinkModel).filter_by(opticallink_uuid=link_uuid).delete() + return num_deleted > 0 + deleted = run_transaction(sessionmaker(bind=db_engine), callback) + link_id = json_link_id(link_uuid) + if deleted: + notify_event_link(messagebroker, EventTypeEnum.EVENTTYPE_REMOVE, link_id) + + return Empty() diff --git a/src/context/service/database/Topology.py b/src/context/service/database/Topology.py index e8f994155..c94d336a0 100644 --- a/src/context/service/database/Topology.py +++ b/src/context/service/database/Topology.py @@ -27,13 +27,15 @@ from common.tools.object_factory.Topology import json_topology_id from context.Config import ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY, ALLOW_EXPLICIT_ADD_LINK_TO_TOPOLOGY from .models.DeviceModel import DeviceModel from .models.LinkModel import LinkModel -from .models.TopologyModel import TopologyDeviceModel, TopologyLinkModel, TopologyModel +from .models.TopologyModel import TopologyDeviceModel, TopologyLinkModel, TopologyModel , TopologyOpticalLinkModel from .uuids.Context import context_get_uuid from .uuids.Device import device_get_uuid from .uuids.Link import link_get_uuid from .uuids.Topology import topology_get_uuid from .Events import notify_event_context, notify_event_topology +from .models.OpticalLinkModel import OpticalLinkModel + LOGGER = logging.getLogger(__name__) def topology_list_ids(db_engine : Engine, request : ContextId) -> TopologyIdList: @@ -77,9 +79,10 @@ def topology_get_details(db_engine : Engine, request : TopologyId) -> TopologyDe _,topology_uuid = topology_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: obj : Optional[TopologyModel] = session.query(TopologyModel)\ - .options(selectinload(TopologyModel.topology_devices, TopologyDeviceModel.device, DeviceModel.endpoints))\ - .options(selectinload(TopologyModel.topology_links, TopologyLinkModel.link, LinkModel.link_endpoints))\ - .filter_by(topology_uuid=topology_uuid).one_or_none() + .options(selectinload(TopologyModel.topology_devices, TopologyDeviceModel.device, DeviceModel.endpoints))\ + .options(selectinload(TopologyModel.topology_links, TopologyLinkModel.link, LinkModel.link_endpoints))\ + .options(selectinload(TopologyModel.topology_optical_links, TopologyOpticalLinkModel.optical_link, OpticalLinkModel.opticallink_endpoints))\ + .filter_by(topology_uuid=topology_uuid).one_or_none() #.options(selectinload(DeviceModel.components))\ return None if obj is None else obj.dump_details() obj = run_transaction(sessionmaker(bind=db_engine), callback) diff --git a/src/context/service/database/models/DeviceModel.py b/src/context/service/database/models/DeviceModel.py index 376dc98c4..fb7f80e71 100644 --- a/src/context/service/database/models/DeviceModel.py +++ b/src/context/service/database/models/DeviceModel.py @@ -38,6 +38,9 @@ class DeviceModel(_Base): endpoints = relationship('EndPointModel', passive_deletes=True) # lazy='joined', back_populates='device' components = relationship('ComponentModel', passive_deletes=True) # lazy='joined', back_populates='device' controller = relationship('DeviceModel', remote_side=[device_uuid], passive_deletes=True) # lazy='joined', back_populates='device' + + # ------------------- Experimental ----------------------------------- + optical_endpoints= relationship('OpticalEndPointModel',passive_deletes=True) def dump_id(self) -> Dict: return {'device_uuid': {'uuid': self.device_uuid}} diff --git a/src/context/service/database/models/OpticalEndPointModel.py b/src/context/service/database/models/OpticalEndPointModel.py new file mode 100644 index 000000000..0500bedf3 --- /dev/null +++ b/src/context/service/database/models/OpticalEndPointModel.py @@ -0,0 +1,69 @@ +# 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 operator +from sqlalchemy import CheckConstraint, Column, DateTime, Float, ForeignKey, Integer, String ,Boolean +from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.types import ARRAY +from sqlalchemy.orm import relationship +from typing import Dict +from ._Base import _Base + + + + +class OpticalEndPointModel(_Base): + __tablename__ = 'optical_endpoint' + + endpoint_uuid = Column(UUID(as_uuid=False), primary_key=True) + device_uuid = Column(ForeignKey('device.device_uuid', ondelete='CASCADE' ), nullable=False, index=True) + + name = Column(String, nullable=False) + endpoint_type = Column(String, nullable=False) + + created_at = Column(DateTime, nullable=False) + updated_at = Column(DateTime, nullable=False) + + device = relationship('DeviceModel', back_populates='optical_endpoints') # lazy='selectin' + + #link_endpoints = relationship('LinkEndPointModel', back_populates='endpoint' ) + #service_endpoints = relationship('ServiceEndPointModel', back_populates='endpoint' ) + + def dump_id(self) -> Dict: + result = { + + 'device_id' : self.device.dump_id(), + 'endpoint_uuid': {'uuid': self.endpoint_uuid}, + } + return result + + def dump(self) -> Dict: + return { + 'endpoint_id' : self.dump_id(), + 'name' : self.name, + 'endpoint_type' : self.endpoint_type, + + } + + def dump_name(self) -> Dict: + return { + 'endpoint_id' : self.dump_id(), + 'device_name' : self.device.device_name, + 'endpoint_name': self.name, + 'endpoint_type': self.endpoint_type, + } \ No newline at end of file diff --git a/src/context/service/database/models/OpticalLinkModel.py b/src/context/service/database/models/OpticalLinkModel.py index b94eeda93..28c71675e 100644 --- a/src/context/service/database/models/OpticalLinkModel.py +++ b/src/context/service/database/models/OpticalLinkModel.py @@ -1,78 +1,117 @@ +# 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 operator from sqlalchemy import CheckConstraint, Column, DateTime, Float, ForeignKey, Integer, String ,Boolean from sqlalchemy.dialects.postgresql import UUID -from sqlalchemy.types import ARRAY +from sqlalchemy.types import PickleType , TypeDecorator from sqlalchemy.orm import relationship +import json,logging from typing import Dict from ._Base import _Base + + + +class SlotType(TypeDecorator): + + impl = String + + def process_bind_param(self, value, dialect): + if value is not None: + slot={} + for k,v in value.items(): + slot[k]=v + logging.info(f"dict from slotType {slot}") + value = json.dumps(slot) + + return value + + def process_result_value(self, value, dialect): + if value is not None: + value = json.loads(value) + return value + + + + + class OpticalLinkModel(_Base): __tablename__ = 'opticallink' - optical_link_uuid = Column(UUID(as_uuid=False), primary_key=True) - optical_link_name = Column(String, nullable=False) - length = Column(Integer, nullable=True) - source = Column(String, nullable=True) - target = Column(String, nullable=True) - optical_link_fiber= relationship("FiberModel") - created_at = Column(DateTime, nullable=False) - updated_at = Column(DateTime, nullable=False) + opticallink_uuid = Column(UUID(as_uuid=False), primary_key=True) + name = Column(String, nullable=False) + created_at = Column(DateTime, nullable=False) + updated_at = Column(DateTime, nullable=False) + length = Column(Integer, nullable=True) + src_port = Column(String, nullable=True) + dst_port = Column(String, nullable=True) + local_peer_port = Column(String, nullable=True) + remote_peer_port = Column(String, nullable=True) + used = Column(Boolean ,nullable=True) + c_slots = Column (SlotType,nullable=True) + l_slots = Column (SlotType,nullable=True) + s_slots = Column (SlotType,nullable=True) + opticallink_endpoints = relationship("OpticalLinkEndPointModel") + topology_optical_links = relationship('TopologyOpticalLinkModel', back_populates='optical_link') + def dump_id(self) -> Dict: - return {'optical_link_uuid': {'uuid': self.link_uuid}} + return {'link_uuid': {'uuid': self.opticallink_uuid}} def dump(self) -> Dict: + result = { - 'optical_link_id' : self.dump_id(), - 'name' : self.optical_link_name, - 'details': { - "length" : self.length, - 'source' : self.source, - "target" : self.target, - 'fibers' : [ fiber.dump() for fiber in self.optical_link_fiber ] - } - + + 'link_id' : self.dump_id(), + 'name' : self.name, + 'optical_details' :{ + + 'length' : self.length, + "src_port" : self.src_port, + "dst_port" : self.dst_port, + "local_peer_port" : self.local_peer_port, + "remote_peer_port" : self.remote_peer_port, + "used" : self.used, + "c_slots" : self.c_slots , + "l_slots" : self.l_slots, + "s_slots" : self.s_slots + }, + "link_endpoint_ids" : [optical_endpoint.endpoint.dump_id() for optical_endpoint in self.opticallink_endpoints] + } return result -class FiberModel(_Base): - __tablename__ = 'fiber' - fiber_uuid = Column(UUID(as_uuid=False), primary_key=True) - fiber_length = Column(Integer, nullable=True) - source_port = Column(String, nullable=True) - destination_port = Column(String, nullable=True) - local_peer_port = Column(String, nullable=True) - remote_peer_port = Column(String, nullable=True) - used = Column(Boolean ,nullable=true) - c_slots = Column (ARRAY(Integer),nullable=True) - l_slots = Column (ARRAY(Integer),nullable=True) - s_slots = Column (ARRAY(Integer),nullable=True) - optical_link_uuid = Column(ForeignKey('opticallink.optical_link_uuid', ondelete='CASCADE' ), primary_key=True) - optical_link = relationship('OpticalLinkModel', back_populates='optical_link_fibers') - - - def dump_id(self) -> Dict: - return {'fiber_uuid': {'uuid': self.fiber_uuid}} - - - def dump(self) -> Dict: - result = { - 'ID' : self.dump_id(), - 'length' : self.fiber_length, - "src_port" : self.source_port, - "dst_port" : self.destination_port, - "local_peer_port" : self.local_peer_port, - "remote_peer_port" : self.remote_peer_port, - "used" : self.used, - "c_slots" : self.c_slots , - "l_slots" : self.l_slots, - "s_slots" : self.s_slots - - } - - return result \ No newline at end of file + + + +class OpticalLinkEndPointModel(_Base): + __tablename__ = 'opticallink_endpoint' + + link_uuid = Column(ForeignKey('opticallink.opticallink_uuid', ondelete='CASCADE' ), primary_key=True) + endpoint_uuid = Column(ForeignKey('optical_endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True, index=True) + + + optical_link = relationship('OpticalLinkModel', back_populates='opticallink_endpoints') #, lazy='selectin' + endpoint = relationship('OpticalEndPointModel', lazy='selectin') # back_populates='link_endpoints' + + + diff --git a/src/context/service/database/models/TopologyModel.py b/src/context/service/database/models/TopologyModel.py index 68d97edf3..f0e3da3aa 100644 --- a/src/context/service/database/models/TopologyModel.py +++ b/src/context/service/database/models/TopologyModel.py @@ -30,6 +30,9 @@ class TopologyModel(_Base): context = relationship('ContextModel', back_populates='topologies', lazy='selectin') topology_devices = relationship('TopologyDeviceModel') # back_populates='topology' topology_links = relationship('TopologyLinkModel' ) # back_populates='topology' + + #-------------------------- Experimental --------------------------- + topology_optical_links= relationship("TopologyOpticalLinkModel") def dump_id(self) -> Dict: return { @@ -43,6 +46,8 @@ class TopologyModel(_Base): 'name' : self.topology_name, 'device_ids' : [{'device_uuid': {'uuid': td.device_uuid}} for td in self.topology_devices], 'link_ids' : [{'link_uuid' : {'uuid': tl.link_uuid }} for tl in self.topology_links ], + 'optical_link_ids' : [{'link_uuid' : {'uuid': to.optical_link_uuid }} for to in self.topology_optical_links ], + } def dump_details(self) -> Dict: @@ -54,11 +59,16 @@ class TopologyModel(_Base): tl.link.dump() for tl in self.topology_links ] + optical_links=[ + ol.optical_link.dump() + for ol in self.topology_optical_links + ] return { 'topology_id': self.dump_id(), 'name' : self.topology_name, 'devices' : devices, 'links' : links, + 'optical_links':optical_links } class TopologyDeviceModel(_Base): @@ -78,3 +88,14 @@ class TopologyLinkModel(_Base): topology = relationship('TopologyModel', lazy='selectin', viewonly=True) # back_populates='topology_links' link = relationship('LinkModel', lazy='selectin') # back_populates='topology_links' + +#---------------------------------------- Experimental --------------------------------------- + +class TopologyOpticalLinkModel(_Base): + __tablename__ = 'topology_optical_link' + + topology_uuid = Column(ForeignKey('topology.topology_uuid', ondelete='RESTRICT'), primary_key=True, index=True) + optical_link_uuid = Column(ForeignKey('opticallink.opticallink_uuid', ondelete='CASCADE' ), primary_key=True, index=True) + + topology = relationship('TopologyModel', lazy='selectin', viewonly=True) # back_populates='topology_optical_links' + optical_link = relationship('OpticalLinkModel', lazy='selectin') # back_populates='topology_optical_links' diff --git a/src/context/service/database/uuids/EndPoint.py b/src/context/service/database/uuids/EndPoint.py index bf5f30ec3..aef2c6de4 100644 --- a/src/context/service/database/uuids/EndPoint.py +++ b/src/context/service/database/uuids/EndPoint.py @@ -18,21 +18,26 @@ from common.method_wrappers.ServiceExceptions import InvalidArgumentsException from ._Builder import get_uuid_from_string, get_uuid_random from .Device import device_get_uuid from .Topology import topology_get_uuid +import logging def endpoint_get_uuid( endpoint_id : EndPointId, endpoint_name : str = '', allow_random : bool = False ) -> Tuple[str, str, str]: + logging.info(f"endpoint_id is {endpoint_id}") device_uuid = device_get_uuid(endpoint_id.device_id, allow_random=False) _,topology_uuid = topology_get_uuid(endpoint_id.topology_id, allow_random=False, allow_default=True) raw_endpoint_uuid = endpoint_id.endpoint_uuid.uuid if len(raw_endpoint_uuid) > 0: prefix_for_name = '{:s}/{:s}'.format(topology_uuid, device_uuid) + logging.info(f" e_raw_endpoint_uuid , e {raw_endpoint_uuid} and endpoint{get_uuid_from_string(raw_endpoint_uuid, prefix_for_name=prefix_for_name)}") return topology_uuid, device_uuid, get_uuid_from_string(raw_endpoint_uuid, prefix_for_name=prefix_for_name) if len(endpoint_name) > 0: + prefix_for_name = '{:s}/{:s}'.format(topology_uuid, device_uuid) return topology_uuid, device_uuid, get_uuid_from_string(endpoint_name, prefix_for_name=prefix_for_name) if allow_random: + return topology_uuid, device_uuid, get_uuid_random() raise InvalidArgumentsException([ diff --git a/src/context/service/database/uuids/OpticalEndPoint.py b/src/context/service/database/uuids/OpticalEndPoint.py new file mode 100644 index 000000000..b31bc7d71 --- /dev/null +++ b/src/context/service/database/uuids/OpticalEndPoint.py @@ -0,0 +1,45 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Tuple +from common.proto.context_pb2 import EndPointId +from common.method_wrappers.ServiceExceptions import InvalidArgumentsException +from ._Builder import get_uuid_from_string, get_uuid_random +from .Device import device_get_uuid +from .Topology import topology_get_uuid +import logging + +def optical_endpoint_get_uuid( + endpoint_id : EndPointId, endpoint_name : str = '', allow_random : bool = False +) -> Tuple[str, str, str]: + device_uuid = device_get_uuid(endpoint_id.device_id, allow_random=False) + + raw_endpoint_uuid = endpoint_id.endpoint_uuid.uuid + + if len(raw_endpoint_uuid) > 0: + prefix_for_name = '{:s}'.format( device_uuid) + logging.info(f" raw_endpoint uuid {raw_endpoint_uuid} and endpoint {get_uuid_from_string(raw_endpoint_uuid, prefix_for_name=prefix_for_name)}") + return device_uuid, get_uuid_from_string(raw_endpoint_uuid, prefix_for_name=prefix_for_name) + if len(endpoint_name) > 0: + + prefix_for_name = '{:s}'.format( device_uuid) + return device_uuid, get_uuid_from_string(endpoint_name, prefix_for_name=prefix_for_name) + if allow_random: + + return device_uuid, get_uuid_random() + + raise InvalidArgumentsException([ + ('optical_endpoint_id.endpoint_uuid.uuid', raw_endpoint_uuid), + ('name', endpoint_name), + ], extra_details=['At least one is required to produce a OpticalEndPoint UUID']) diff --git a/src/context/service/database/uuids/OpticalLink.py b/src/context/service/database/uuids/OpticalLink.py new file mode 100644 index 000000000..0caead511 --- /dev/null +++ b/src/context/service/database/uuids/OpticalLink.py @@ -0,0 +1,21 @@ + +from common.proto.context_pb2 import LinkId +from common.method_wrappers.ServiceExceptions import InvalidArgumentsException +from ._Builder import get_uuid_from_string, get_uuid_random + +optical_detail_sp="Optical_link_detail" +def opticaldetail_get_uuid( + link_id : LinkId,allow_random=False +) -> str: + link_uuid = link_id.link_uuid.uuid + + if len(link_uuid) > 0: + str_uuid=f"{link_uuid}{optical_detail_sp}" + return get_uuid_from_string(str_uuid) + + if allow_random: return get_uuid_random() + + raise InvalidArgumentsException([ + ('link_id.link_uuid.uuid', link_uuid), + + ], extra_details=['At least one is required to produce a Optical Link Detail UUID']) diff --git a/src/context/service/database/uuids/_Builder.py b/src/context/service/database/uuids/_Builder.py index 75fe51bc0..338b3ac97 100644 --- a/src/context/service/database/uuids/_Builder.py +++ b/src/context/service/database/uuids/_Builder.py @@ -14,7 +14,7 @@ from typing import Optional, Union from uuid import UUID, uuid4, uuid5 - +import logging # Generate a UUIDv5-like from the SHA-1 of "TFS" and no namespace to be used as the NAMESPACE for all # the context UUIDs generated. For efficiency purposes, the UUID is hardcoded; however, it is produced # using the following code: @@ -32,10 +32,12 @@ def get_uuid_from_string(str_uuid_or_name : Union[str, UUID], prefix_for_name : raise Exception(MSG.format(str(repr(str_uuid_or_name)))) try: # try to parse as UUID + return str(UUID(str_uuid_or_name)) except: # pylint: disable=bare-except # produce a UUID within TFS namespace from parameter if prefix_for_name is not None: + logging.info(f"playing with its suit {prefix_for_name} and {str_uuid_or_name}") str_uuid_or_name = '{:s}/{:s}'.format(prefix_for_name, str_uuid_or_name) return str(uuid5(NAMESPACE_TFS, str_uuid_or_name)) 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 7835b4778..f368ca10e 100644 --- a/src/device/service/drivers/oc_driver/templates/VPN/physical.py +++ b/src/device/service/drivers/oc_driver/templates/VPN/physical.py @@ -207,4 +207,30 @@ def create_media_channel (resources): return results - \ No newline at end of file + + + +def disable_optical_channel (index,state) : + + results=[] + doc, tag, text = Doc().tagtext() + #with tag('config'): + with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"): + with tag('components', xmlns="http://openconfig.net/yang/platform"): + with tag('terminal-device',xmlns="http://openconfig.net/yang/terminal-device"): + with tag("logical-channels"): + with tag('channel'): + with tag('index'):text("{}".format(index)) + with tag('config'): + with tag('admin-state'):text("{}".format(state)) + + result = indent( + doc.getvalue(), + indentation = ' '*2, + newline = '' + ) + results.append(result) + + + return results + diff --git a/src/opticalcontroller/Dockerfile b/src/opticalcontroller/Dockerfile index d54566ccb..70bae4223 100644 --- a/src/opticalcontroller/Dockerfile +++ b/src/opticalcontroller/Dockerfile @@ -1,4 +1,4 @@ -# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -34,19 +34,20 @@ RUN python3 -m pip install --upgrade pip-tools # Get common Python packages # Note: this step enables sharing the previous Docker build steps among all the Python components -WORKDIR /var/teraflow +WORKDIR /var/teraflow/opticalcontroller/ + COPY common_requirements.in common_requirements.in RUN pip-compile --quiet --output-file=common_requirements.txt common_requirements.in RUN python3 -m pip install -r common_requirements.txt # Add common files into working directory -WORKDIR /var/teraflow/common +WORKDIR /var/teraflow/opticalcontroller/common COPY src/common/. ./ RUN rm -rf proto # Create proto sub-folder, copy .proto files, and generate Python code -RUN mkdir -p /var/teraflow/common/proto -WORKDIR /var/teraflow/common/proto +RUN mkdir -p /var/teraflow/opticalcontroller/common/proto +WORKDIR /var/teraflow/opticalcontroller/common/proto RUN touch __init__.py COPY proto/*.proto ./ RUN python3 -m grpc_tools.protoc -I=. --python_out=. --grpc_python_out=. *.proto @@ -54,18 +55,19 @@ RUN rm *.proto RUN find . -type f -exec sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' {} \; # Create component sub-folders, get specific Python packages -RUN mkdir -p /var/teraflow/opticalcontroller -WORKDIR /var/teraflow/opticalcontroller + +WORKDIR /var/teraflow/ COPY src/opticalcontroller/requirements.in requirements.in RUN pip-compile --quiet --output-file=requirements.txt requirements.in RUN python3 -m pip install -r requirements.txt # Add component files into working directory -WORKDIR /var/teraflow +WORKDIR /var/teraflow/opticalcontroller/ + COPY src/context/__init__.py context/__init__.py COPY src/context/client/. context/client/ -COPY src/opticalcontroller/. opticalcontroller/ +COPY src/opticalcontroller/. ./ # Start the service -WORKDIR /var/teraflow/opticalcontroller + ENTRYPOINT ["python", "OpticalController.py"] diff --git a/src/opticalcontroller/OpticalController.py b/src/opticalcontroller/OpticalController.py index c2805695a..c91c76e9f 100644 --- a/src/opticalcontroller/OpticalController.py +++ b/src/opticalcontroller/OpticalController.py @@ -1,30 +1,16 @@ -# 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 - from tools import * from variables import * from RSA import RSA -import time -import logging +import time , logging +from common.proto.context_pb2 import TopologyId + rsa = None -LOGGER = logging.getLogger(__name__) + app = Flask(__name__) api = Api(app, version='1.0', title='Optical controller API', @@ -47,7 +33,7 @@ class AddLightpath(Resource): @staticmethod def put(src, dst, bitrate, bidir=1): - LOGGER.info("INFO: New Lightpath request from {} to {} with rate {} ".format(src, dst, bitrate)) + print("INFO: New Lightpath request from {} to {} with rate {} ".format(src, dst, bitrate)) t0 = time.time()*1000.0 if debug: rsa.g.printGraph() @@ -56,9 +42,9 @@ class AddLightpath(Resource): flow_id = rsa.rsa_computation(src, dst, bitrate, bidir) if rsa.db_flows[flow_id]["op-mode"] == 0: return 'No path found', 404 - t1 = time.time()*1000.0 + t1 = time.time() * 1000.0 elapsed = t1 - t0 - LOGGER.info("INFO: time elapsed = {} ms".format(elapsed)) + print("INFO: time elapsed = {} ms".format(elapsed)) return rsa.db_flows[flow_id], 200 else: return "Error", 404 @@ -74,17 +60,15 @@ class AddLightpath(Resource): @optical.response(404, 'Error, not found') class AddFlexLightpath(Resource): @staticmethod - def put(src, dst, bitrate,bidir=1, band=None): - + def put(src, dst, bitrate, bidir=1, band=None): + print("INFO: New FlexLightpath request from {} to {} with rate {} ".format(src, dst, bitrate)) - LOGGER.info("INFO: New FlexLightpath request from {} to {} with rate {} ".format(src, dst, bitrate)) t0 = time.time()*1000.0 if debug: rsa.g.printGraph() if rsa is not None: flow_id, optical_band_id = rsa.rsa_fs_computation(src, dst, bitrate, bidir, band) - print (f"flow_id {flow_id} and optical_band_id {optical_band_id} ") if flow_id is not None: if rsa.db_flows[flow_id]["op-mode"] == 0: return 'No path found', 404 @@ -99,7 +83,7 @@ class AddFlexLightpath(Resource): else: t1 = time.time() * 1000.0 elapsed = t1 - t0 - LOGGER.info("INFO: time elapsed = {} ms".format(elapsed)) + print("INFO: time elapsed = {} ms".format(elapsed)) return rsa.optical_bands[optical_band_id], 200 else: @@ -108,7 +92,7 @@ class AddFlexLightpath(Resource): @optical.route('/DelFlexLightpath/<int:flow_id>/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>') @optical.response(200, 'Success') @optical.response(404, 'Error, not found') -class DelLightpath(Resource): +class DelFLightpath(Resource): @staticmethod def delete(flow_id, src, dst, bitrate, o_band_id): if flow_id in rsa.db_flows.keys(): @@ -122,12 +106,12 @@ class DelLightpath(Resource): rsa.del_flow(flow, ob_id) rsa.db_flows[flow_id]["is_active"] = False rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id) - if rsa.optical_bands[ob_id]["reverse_optical_band_id"] != 0: - rev_ob_id = rsa.optical_bands[ob_id]["reverse_optical_band_id"] - rsa.optical_bands[rev_ob_id]["served_lightpaths"].remove(flow_id) + #if rsa.optical_bands[ob_id]["reverse_optical_band_id"] != 0: + # rev_ob_id = rsa.optical_bands[ob_id]["reverse_optical_band_id"] + # rsa.optical_bands[rev_ob_id]["served_lightpaths"].remove(flow_id) if debug: - LOGGER.info(links_dict) + print(links_dict) return "flow {} deleted".format(flow_id), 200 else: return "flow {} not matching".format(flow_id), 404 @@ -138,7 +122,7 @@ class DelLightpath(Resource): rsa.db_flows[flow_id]["is_active"] = False rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id) if debug: - LOGGER.info(links_dict) + print(links_dict) return "flow {} deleted".format(flow_id), 200 else: return "flow {} not matching".format(flow_id), 404 @@ -161,7 +145,7 @@ class DelLightpath(Resource): rsa.del_flow(flow) rsa.db_flows[flow_id]["is_active"] = False if debug: - LOGGER.info(links_dict) + print(links_dict) return "flow {} deleted".format(flow_id), 200 else: return "flow {} not matching".format(flow_id), 404 @@ -177,7 +161,7 @@ class GetFlows(Resource): def get(): try: if debug: - LOGGER.info(rsa.db_flows) + print(rsa.db_flows) return rsa.db_flows, 200 except: return "Error", 404 @@ -188,11 +172,9 @@ class GetFlows(Resource): class GetBands(Resource): @staticmethod def get(): - print("Getting ") - LOGGER.info("Getting") try: if debug: - LOGGER.info(rsa.optical_bands) + print(rsa.optical_bands) return rsa.optical_bands, 200 except: return "Error", 404 @@ -207,7 +189,7 @@ class GetBand(Resource): for ob_idx in rsa.optical_bands.keys(): if str(ob_idx) == str(ob_id): if debug: - LOGGER.info(rsa.optical_bands[ob_id]) + print(rsa.optical_bands[ob_id]) return rsa.optical_bands[ob_idx], 200 return {}, 404 @@ -221,25 +203,36 @@ class GetFlows(Resource): global links_dict try: if debug: - LOGGER.info(links_dict) + print(links_dict) return links_dict, 200 except: return "Error", 404 + +@optical.route('/GetTopology/<path:topology_id>',methods=(['GET'])) +@optical.response(200, 'Success') +@optical.response(404, 'Error, not found') +class GetTopology(Resource): + @staticmethod + def get(topology_id:TopologyId): + + try: + nodes , links = readTopologyDataFromContext(topology_id) + print(f"nodes {nodes} and links {links}") + return "Done" + except Exception as e: + print(f"err {e}") + return "Error", 404 + -if __name__ == '__main__': - - # Start metrics server - - LOGGER.info('Starting...') - - - +if __name__ == '__main__': + + nodes_dict, links_dict = readTopologyData(nodes_json, topology_json) - #topologies, links = getTopology() - #print("topologies{} and devices {}".format(topologies,links)) + rsa = RSA(nodes_dict, links_dict) + #print(rsa.init_link_slots2(testing)) - app.run(host='0.0.0.0', port=10060, debug=True) + app.run(host='0.0.0.0', port=5000,debug=True) diff --git a/src/opticalcontroller/RSA.py b/src/opticalcontroller/RSA.py index 9b12b1ac8..b6f9b0cbd 100644 --- a/src/opticalcontroller/RSA.py +++ b/src/opticalcontroller/RSA.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 dijsktra from tools import * from variables import * @@ -26,15 +12,15 @@ class RSA(): self.flow_id = 0 self.opt_band_id = 0 self.db_flows = {} - self.initGraph() + self.initGraph2() self.c_slot_number = 0 self.l_slot_number = 0 self.s_slot_number = 0 self.optical_bands = {} - + print(f"node_ctxt {nodes} links_ctxt {links}") def init_link_slots(self, testing): if not testing: - for l in self.links_dict["links"]: + for l in self.links_dict["optical_links"]: for fib in l["optical_link"]["details"]["fibers"]: #fib = self.links_dict[l]["fibers"][f] if len(fib["c_slots"]) > 0: @@ -45,7 +31,7 @@ class RSA(): fib["s_slots"] = list(range(0, Ns)) if debug: print(fib) - for l1 in self.links_dict["links"]: + for l1 in self.links_dict["optical_links"]: for fib1 in l1["optical_link"]["details"]["fibers"]: #fib1 = self.links_dict[l1]["details"]["fibers"][f1] @@ -58,11 +44,35 @@ class RSA(): break return "{},{},{}".format(self.c_slot_number, self.l_slot_number, self.s_slot_number) + def init_link_slots2(self, testing): + if not testing: + for l in self.links_dict["optical_links"]: + fib = l["optical_details"] + #fib = self.links_dict[l]["fibers"][f] + if len(fib["c_slots"]) > 0: + for c in range(0, Nc): + fib["c_slots"][c] = 1 + if len(fib["l_slots"]) > 0: + for c in range(0, Nl): + fib["l_slots"][c] = 1 + if len(fib["s_slots"]) > 0: + for c in range(0, Ns): + fib["s_slots"][c] = 1 + if debug: + print(fib) + for l1 in self.links_dict["optical_links"]: + fib1 = l1["optical_details"] + self.c_slot_number = len(fib1["c_slots"].keys()) + self.l_slot_number = len(fib1["l_slots"].keys()) + self.s_slot_number = len(fib1["s_slots"].keys()) + break + return "{},{},{}".format(self.c_slot_number, self.l_slot_number, self.s_slot_number) + def initGraph(self): self.g = dijsktra.Graph() for n in self.nodes_dict: self.g.add_vertex(n) - for l in self.links_dict["links"]: + for l in self.links_dict["optical_links"]: if debug: print(l) [s, d] = l["optical_link"]["name"].split('-') @@ -74,6 +84,22 @@ class RSA(): if debug: self.g.printGraph() + def initGraph2(self): + self.g = dijsktra.Graph() + for n in self.nodes_dict: + self.g.add_vertex(n) + for l in self.links_dict["optical_links"]: + if debug: + print(l) + [s, d] = l["name"].split('-') + ps = l["optical_details"]["src_port"] + pd = l["optical_details"]["dst_port"] + self.g.add_edge(s, d, ps, pd, 1) + + print("INFO: Graph initiated.2") + if debug: + self.g.printGraph() + def compute_path(self, src, dst): path = dijsktra.shortest_path(self.g, self.g.get_vertex(src), self.g.get_vertex(dst)) print("INFO: Path from {} to {} with distance: {}".format(src, dst, self.g.get_vertex(dst).get_distance())) @@ -95,7 +121,7 @@ class RSA(): self.g.reset_graph() return links, path - def get_slots(self, links, slots, optical_band_id = None): + def get_slots(self, links, slots, optical_band_id=None): if isinstance(slots, int): val_c = slots @@ -120,38 +146,40 @@ class RSA(): add = links[0] if self.nodes_dict[dst_2]["type"] == "OC-TP": drop = links[-1] - + found = 0 for l in links: c_slots[l] = [] l_slots[l] = [] s_slots[l] = [] - found = 0 - for link in self.links_dict["links"]: - if link["optical_link"]["name"] == l: - #for f in self.links_dict[l]['fibers'].keys(): - for fib in link["optical_link"]["details"]["fibers"]: - if l == add: - if 'used' in fib: - if fib["used"]: - #if debug: - print("WARNING!!!: link {}, fiber {} is already in use".format(l, fib["ID"])) - continue - if l == drop: - if 'used' in fib: - if fib["used"]: - #if debug: - print("WARNING!!!: link {}, fiber {} is already in use".format(l, fib["ID"])) - continue - if len(fib["c_slots"]) > 0: - c_slots[l] = combine(c_slots[l], consecutives(fib["c_slots"], val_c)) - if len(fib["l_slots"]) > 0: - l_slots[l] = combine(l_slots[l], consecutives(fib["l_slots"], val_l)) - if len(fib["s_slots"]) > 0: - s_slots[l] = combine(s_slots[l], consecutives(fib["s_slots"], val_s)) - if debug: - print(l, c_slots[l]) - found = 1 - if found == 0: + + link = self.get_link_by_name(l) + fib = link["optical_details"] + if l == add: + if 'used' in fib: + if fib["used"]: + #if debug: + print("WARNING!!!: link {}, is already in use".format(l)) + return [], [], [] + if l == drop: + if 'used' in fib: + if fib["used"]: + #if debug: + print("WARNING!!!: link {} is already in use".format(l)) + return [], [], [] + c_found = l_found = s_found = 0 + if len(fib["c_slots"].keys()) > 0: + #c_slots[l] = combine(c_slots[l], consecutives(fib["c_slots"], val_c)) + c_slots[l] = combine(c_slots[l], consecutives(fib["c_slots"], val_c)) + c_found = 1 + if len(fib["l_slots"].keys()) > 0: + l_slots[l] = combine(l_slots[l], consecutives(fib["l_slots"], val_l)) + l_found = 1 + if len(fib["s_slots"].keys()) > 0: + s_slots[l] = combine(s_slots[l], consecutives(fib["s_slots"], val_s)) + s_found = 1 + if debug: + print(l, c_slots[l]) + if c_found == 0 and l_found == 0 and s_found == 0: return [], [], [] keys = list(c_slots.keys()) @@ -185,58 +213,61 @@ class RSA(): c_sts = common_slots(a_c, b_c) l_sts = common_slots(a_l, b_l) s_sts = common_slots(a_s, b_s) + ''' + if len(fib["l_slots"]) > 0: + l_slots[l] = combine(l_slots[l], consecutives(fib["l_slots"], val_l)) + l_found = 1''' if optical_band_id is not None: if "c_slots" in self.optical_bands[optical_band_id].keys(): if len(self.optical_bands[optical_band_id]["c_slots"]) > 0: a_c = c_sts - b_c = self.optical_bands[optical_band_id]["c_slots"] + #MOD + b_c = consecutives(self.optical_bands[optical_band_id]["c_slots"], val_c) + #b_c = self.optical_bands[optical_band_id]["c_slots"] c_sts = common_slots(a_c, b_c) - else: - c_sts = [] else: c_sts = [] if "l_slots" in self.optical_bands[optical_band_id].keys(): if len(self.optical_bands[optical_band_id]["l_slots"]) > 0: a_l = l_sts - b_l = self.optical_bands[optical_band_id]["l_slots"] + b_l = consecutives(self.optical_bands[optical_band_id]["l_slots"], val_c) l_sts = common_slots(a_l, b_l) - else: - l_sts = [] else: l_sts = [] if "s_slots" in self.optical_bands[optical_band_id].keys(): if len(self.optical_bands[optical_band_id]["s_slots"]) > 0: a_s = s_sts - b_s = self.optical_bands[optical_band_id]["s_slots"] + b_s = consecutives(str_list_to_int(self.optical_bands[optical_band_id]["s_slots"].keys()), val_c) s_sts = common_slots(a_s, b_s) - else: - s_sts = [] else: s_sts = [] return c_sts, l_sts, s_sts def update_link(self, fib, slots, band): + print(fib) for i in slots: - fib[band].remove(i) + fib[band][str(i)] = 0 if 'used' in fib: fib['used'] = True + print(fib) def update_optical_band(self, optical_band_id, slots, band): for i in slots: - self.optical_bands[optical_band_id][band].remove(i) + self.optical_bands[optical_band_id][band][str(i)] = 0 def restore_link(self, fib, slots, band): for i in slots: - fib[band].append(int(i)) + fib[band][str(i)] = 1 if 'used' in fib: fib['used'] = False fib[band].sort() def restore_optical_band(self, optical_band_id, slots, band): for i in slots: - self.optical_bands[optical_band_id][band].append(int(i)) - self.optical_bands[optical_band_id][band].sort() + self.optical_bands[optical_band_id][band][str(i)] = 1 + #self.optical_bands[optical_band_id][band].append(int(i)) + #self.optical_bands[optical_band_id][band].sort() def del_flow(self, flow, o_b_id = None): flows = flow["flows"] @@ -250,21 +281,35 @@ class RSA(): links = flow["links"] bidir = flow["bidir"] - for l in fiber_f.keys(): + for l in links: if debug: print(l) - print(fiber_f[l]) #link = self.links_dict[l] #f = fiber_f[l] #fib = link['fibers'][f] - fib = self.get_fiber_details(l, fiber_f[l]) - if not list_in_list(slots, fib[band]): + fib = self.get_link_by_name(l)["optical_details"] + if not list_in_list(slots, str_list_to_int(fib[band].keys())): self.restore_link(fib, slots, band) if debug: print(fib[band]) if o_b_id is not None: + if debug: + print("restoring OB") self.restore_optical_band(o_b_id, slots, band) if bidir: + for l in links: + r_l = reverse_link(l) + if debug: + print(r_l) + # link = self.links_dict[l] + # f = fiber_f[l] + # fib = link['fibers'][f] + fib = self.get_link_by_name(r_l)["optical_details"] + if not list_in_list(slots, str_list_to_int(fib[band].keys())): + self.restore_link(fib, slots, band) + if debug: + print(fib[band]) + ''' for rl in fiber_b.keys(): if debug: print(rl) @@ -277,6 +322,7 @@ class RSA(): self.restore_link(rfib, slots, band) if debug: print(rfib[band]) + ''' #changed according to TFS development #if o_b_id is not None: # rev_o_band_id = self.optical_bands[o_b_id]["reverse_optical_band_id"] @@ -287,7 +333,7 @@ class RSA(): fiber_list = {} add = links[0] drop = links[-1] - print(links) + #print(links) ''' for link in self.links_dict["links"]: if link["optical_link"]["name"] == l: @@ -296,85 +342,98 @@ class RSA(): ''' for l in links: - for link in self.links_dict["links"]: - if link["optical_link"]["name"] == l: - for fib in link["optical_link"]["details"]["fibers"]: - #for f in self.links_dict[l]['fibers'].keys(): - #for fib in l["optical_link"]["details"]["fibers"]: - #fib = self.links_dict[l]['fibers'][f] - if l == add: - if 'used' in fib: - if fib["used"]: - if debug: - print("link {}, fiber {} is already in use".format(l, fib["ID"])) - continue - if l == drop: - if 'used' in fib: - if fib["used"]: - if debug: - print("link {}, fiber {} is already in use".format(l, fib["ID"])) - continue - if list_in_list(slots, fib[band]): - fiber_list[l] = fib["ID"] - self.update_link(fib, slots, band) - break + for link in self.links_dict["optical_links"]: + if link["name"] == l: + fib = link["optical_details"] + #for f in self.links_dict[l]['fibers'].keys(): + #for fib in l["optical_link"]["details"]["fibers"]: + #fib = self.links_dict[l]['fibers'][f] + if l == add: + if 'used' in fib: + if fib["used"]: + if debug: + print("link {} is already in use".format(l)) + continue + if l == drop: + if 'used' in fib: + if fib["used"]: + if debug: + print("link {} is already in use".format(l)) + continue + if list_in_list(slots, str_list_to_int(fib[band].keys())): + #fiber_list[l] = fib["ID"] + self.update_link(fib, slots, band) + break print("INFO: Path forward computation completed") return fiber_list def get_link_by_name (self, key): - result = None - for link in self.links_dict["links"]: - if link["optical_link"]["name"] == key: + for link in self.links_dict["optical_links"]: + if link["name"] == key: if debug: print(link) - result = link break - return result + return link def get_fiber_details(self, link_key, fiber_id): - for link in self.links_dict["links"]: - if link["optical_link"]["name"] == link_key: + for link in self.links_dict["optical_links"]: + if link["name"] == link_key: if debug: print(link) - for fib in link["optical_link"]["details"]["fibers"]: + for fib in link["optical_details"]: if fib["ID"] == fiber_id: return fib return None - - def get_fibers_backward(self, links, fibers, slots, band): + def get_fibers_backward(self, links, slots, band): fiber_list = {} #r_drop = reverse_link(links[0]) #r_add = reverse_link(links[-1]) - for l in fibers.keys(): - fib = self.get_fiber_details(l, fibers[l]) + for l in links: + fib = self.get_link_by_name(l)["optical_details"] ''' link = self.get_link_by_name(l) #port = self.links_dict[l]["fibers"][fibers[l]]["src_port"] for fib in link["optical_link"]["details"]["fibers"]: if fib["ID"] == fibers[l]: ''' - port = fib["src_port"] + s_port = fib["src_port"] + d_port = fib["dst_port"] + + if debug: + print(l, s_port, d_port) + r_l = reverse_link(l) r_link = self.get_link_by_name(r_l) + if debug: + print(r_l) + #for f in r_link["fibers"].keys(): - for r_fib in r_link["optical_link"]["details"]["fibers"]: - if r_fib["remote_peer_port"] == port: - if list_in_list(slots, r_fib[band]): - fiber_list[r_l] = r_fib["ID"] - self.update_link(r_fib, slots, band) + r_fib = r_link["optical_details"] + if r_fib["remote_peer_port"] == s_port and r_fib["local_peer_port"] == d_port: + if list_in_list(slots, str_list_to_int(r_fib[band].keys())): + #fiber_list[r_l] = r_fib["ID"] + self.update_link(r_fib, slots, band) print("INFO: Path backward computation completed") return fiber_list + #function invoked for lightpaths and OB def select_slots_and_ports(self, links, n_slots, c, l, s, bidir): if debug: print(self.links_dict) band, slots = slot_selection(c, l, s, n_slots, self.c_slot_number, self.l_slot_number, self.s_slot_number) + if debug: + print (band, slots) if band is None: print("No slots available in the three bands") - return None, None, None + #return None, None, None, {}, {} + return None, None, None, {}, {} if debug: print(band, slots) + self.get_fibers_forward(links, slots, band) + if bidir: + self.get_fibers_backward(links, slots, band) + ''' fibers_f = self.get_fibers_forward(links, slots, band) fibers_b = [] @@ -385,6 +444,7 @@ class RSA(): print(fibers_f) print("backward") print(fibers_b) + ''' add = links[0] drop = links[-1] inport = "0" @@ -394,18 +454,22 @@ class RSA(): t_flows = {} #if len(links) == 1: - for lx in fibers_f: - if lx == add: + for llx in links: + if llx == add: inport = "0" r_outport = "0" - if lx == drop: + if llx == drop: outport = "0" r_inport = "0" + ''' f = fibers_f[lx] - src, dst = lx.split("-") + fibx = self.get_fiber_details(lx, f) + ''' + src, dst = llx.split("-") #outport = self.links_dict[lx]['fibers'][f]["src_port"] - outport = fibx["src_port"] + lx = self.get_link_by_name(llx)["optical_details"] + outport = lx["src_port"] t_flows[src] = {} t_flows[src]["f"] = {} @@ -414,14 +478,14 @@ class RSA(): if bidir: #r_inport = self.links_dict[lx]['fibers'][f]["local_peer_port"] - r_inport = fibx["local_peer_port"] + r_inport = lx["local_peer_port"] t_flows[src]["b"] = {"in": r_inport, "out": r_outport} #inport = self.links_dict[lx]['fibers'][f]["dst_port"] - inport = fibx["dst_port"] + inport = lx["dst_port"] if bidir: #r_outport = self.links_dict[lx]['fibers'][f]["remote_peer_port"] - r_outport = fibx["remote_peer_port"] + r_outport = lx["remote_peer_port"] t_flows[dst] = {} t_flows[dst]["f"] = {} t_flows[dst]["b"] = {} @@ -436,8 +500,9 @@ class RSA(): print(t_flows) print("INFO: Flow matrix computed") - return t_flows, band, slots, fibers_f, fibers_b + return t_flows, band, slots, {}, {} + #function ivoked for fs lightpaths only def select_slots_and_ports_fs(self, links, n_slots, c, l, s, bidir, o_band_id): if debug: print(self.links_dict) @@ -447,22 +512,20 @@ class RSA(): return None, None, None, None, None if debug: print(band, slots) - fibers_f = self.get_fibers_forward(links, slots, band) - self.update_optical_band(o_band_id, slots, band) - fibers_b = [] + self.get_fibers_forward(links, slots, band) if bidir: - fibers_b = self.get_fibers_backward(links, fibers_f, slots, band) + self.get_fibers_backward(links, slots, band) + + #fibers_f = self.get_fibers_forward(links, slots, band) + self.update_optical_band(o_band_id, slots, band) + #fibers_b = [] + #if bidir: + # fibers_b = self.get_fibers_backward(links, fibers_f, slots, band) ''' rev_o_band_id = self.optical_bands[o_band_id]["reverse_optical_band_id"] self.update_optical_band(rev_o_band_id, slots, band) ''' - if debug: - print("forward") - print(fibers_f) - if bidir: - print("backward") - print(fibers_b) add = links[0] drop = links[-1] port_0 = "0" @@ -470,11 +533,10 @@ class RSA(): t_flows = {} #flows_add_side - f = fibers_f[add] src, dst = add.split("-") - fibx = self.get_fiber_details(add, f) + lx = self.get_link_by_name(add)["optical_details"] #outport = self.links_dict[add]['fibers'][f]["src_port"] - outport = fibx["src_port"] + outport = lx["src_port"] #T1 rules t_flows[src] = {} t_flows[src]["f"] = {} @@ -482,7 +544,7 @@ class RSA(): t_flows[src]["f"] = {"in": port_0, "out": outport} if bidir: #r_inport = self.links_dict[add]['fibers'][f]["local_peer_port"] - r_inport = fibx["local_peer_port"] + r_inport = lx["local_peer_port"] t_flows[src]["b"] = {"in": r_inport, "out": port_0} #R1 rules @@ -490,27 +552,26 @@ class RSA(): t_flows[dst]["f"] = {} t_flows[dst]["b"] = {} #inport = self.links_dict[add]['fibers'][f]["dst_port"] - inport = fibx["dst_port"] + inport = lx["dst_port"] opt_band_src_port = self.optical_bands[o_band_id]["src_port"] t_flows[dst]["f"] = {"in": inport, "out": opt_band_src_port} #to modify to peer ports if bidir: #r_inport = self.links_dict[add]['fibers'][f]["local_peer_port"] - r_inport = fibx["local_peer_port"] + r_inport = lx["local_peer_port"] t_flows[src]["b"] = {"in": r_inport, "out": port_0} if bidir: rev_opt_band_dst_port = self.optical_bands[o_band_id]["rev_dst_port"] #r_outport = self.links_dict[add]['fibers'][f]["remote_peer_port"] - r_outport = fibx["remote_peer_port"] + r_outport = lx["remote_peer_port"] t_flows[dst]["b"] = {"in": rev_opt_band_dst_port, "out": r_outport} #flows_drop_side # R2 rules - f = fibers_f[drop] + ly = self.get_link_by_name(drop)["optical_details"] src, dst = drop.split("-") - fiby = self.get_fiber_details(drop, f) #outport = self.links_dict[drop]['fibers'][f]["src_port"] - outport = fiby["src_port"] + outport = ly["src_port"] t_flows[src] = {} t_flows[src]["f"] = {} @@ -520,17 +581,17 @@ class RSA(): if bidir: rev_opt_band_src_port = self.optical_bands[o_band_id]["rev_src_port"] #r_inport = self.links_dict[drop]['fibers'][f]["local_peer_port"] - r_inport = fiby["local_peer_port"] + r_inport = ly["local_peer_port"] t_flows[src]["b"] = {"in": r_inport, "out": rev_opt_band_src_port} t_flows[dst] = {} t_flows[dst]["f"] = {} t_flows[dst]["b"] = {} #inport = self.links_dict[drop]['fibers'][f]["dst_port"] - inport = fiby["dst_port"] + inport = ly["dst_port"] t_flows[dst]["f"] = {"in": inport, "out": port_0} if bidir: #r_inport = self.links_dict[drop]['fibers'][f]["remote_peer_port"] - r_inport = fiby["remote_peer_port"] + r_inport = ly["remote_peer_port"] t_flows[dst]["b"] = {"in": port_0, "out": r_inport} if debug: @@ -540,7 +601,7 @@ class RSA(): print(t_flows) print("INFO: Flow matrix computed for Flex Lightpath") - return t_flows, band, slots, fibers_f, fibers_b + return t_flows, band, slots, {}, {} def rsa_computation(self, src, dst, rate, bidir): self.flow_id += 1 @@ -676,7 +737,8 @@ class RSA(): if len(c_slots) > 0 or len(l_slots) > 0 or len(s_slots) > 0: flow_list, band_range, slots, fiber_f, fiber_b = self.select_slots_and_ports(links, num_slots, c_slots, l_slots, s_slots, bidir) f0, band = freqency_converter(band_range, slots) - print(flow_list, band_range, slots, fiber_f, fiber_b) + if debug: + print(flow_list, band_range, slots, fiber_f, fiber_b) ''' flow_list_b = {} @@ -696,29 +758,34 @@ class RSA(): if flow_list is None: self.null_values(self.flow_id) return self.flow_id, [] - slots_i = [] + #slots_i = [] + #for i in slots: + # slots_i.append(int(i)) + slots_i = {} for i in slots: - slots_i.append(int(i)) + slots_i[str(i)] = 1 # return links, path, flow_list, band_range, slots, fiber_f, fiber_b, op, num_slots, f0, band # links, path, flows, bx, slots, fiber_f, fiber_b, op, n_slots, f0, band + if debug: + print(links) if len(flow_list) > 0: src_port = flow_list[path[0]]['f']['out'] dst_port = flow_list[path[-1]]['f']['in'] - print(flow_list) - if len(fiber_f.keys()) == 1: - link_x = list(fiber_f.keys())[0] + if debug: + print(flow_list) + if len(links) == 1: #fib_x = fiber_f[link_x] #rev_dst_port = self.links_dict[link_x]['fibers'][fib_x]["local_peer_port"] #rev_src_port = self.links_dict[link_x]['fibers'][fib_x]["remote_peer_port"] - fibx = self.get_fiber_details(link_x, fiber_f[link_x]) + fibx = self.get_link_by_name(links[0])["optical_details"] rev_dst_port = fibx["local_peer_port"] rev_src_port = fibx["remote_peer_port"] else: - link_in = list(fiber_f.keys())[0] - link_out = list(fiber_f.keys())[-1] - fib_inx = self.get_fiber_details(link_in, fiber_f[link_in]) - fib_outx = self.get_fiber_details(link_out, fiber_f[link_out]) + link_in = links[0] + link_out = links[-1] + fib_inx = self.get_link_by_name(link_in)["optical_details"] + fib_outx = self.get_link_by_name(link_out)["optical_details"] rev_dst_port = fib_inx["local_peer_port"] rev_src_port = fib_outx["remote_peer_port"] @@ -790,6 +857,7 @@ 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 + print("INFO: TP to TP connection") self.flow_id += 1 self.db_flows[self.flow_id] = {} self.db_flows[self.flow_id]["flow_id"] = self.flow_id @@ -797,7 +865,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 - print("INFO: TP to TP connection") + if band is None: temp_links2 = [] temp_path = [] @@ -816,7 +884,6 @@ class RSA(): temp_path.append(roadm_dst) temp_path.append(t_dst) existing_ob = self.get_optical_bands(roadm_src, roadm_dst) - if len(existing_ob) > 0: print("INFO: Evaluating existing OB {}".format(existing_ob)) @@ -879,13 +946,7 @@ 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) - # 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 + if debug: print(temp_links) diff --git a/src/opticalcontroller/__init__.py b/src/opticalcontroller/__init__.py index 38d04994f..1549d9811 100644 --- a/src/opticalcontroller/__init__.py +++ b/src/opticalcontroller/__init__.py @@ -11,3 +11,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + diff --git a/src/opticalcontroller/dijsktra.py b/src/opticalcontroller/dijsktra.py index a86d1d93d..5be78c624 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/nodes.json b/src/opticalcontroller/json_files/nodes.json index 60f017c19..51f19448e 100644 --- a/src/opticalcontroller/json_files/nodes.json +++ b/src/opticalcontroller/json_files/nodes.json @@ -22,14 +22,42 @@ "type":"OC-ROADM", "driver": "OpticalOC" }, - "T1":{ + "T1.1":{ "id":3, "ip":"10.30.2.210", "port":"50001", "type":"OC-TP", "driver": "OpticalOC" }, - "T2":{ + "T1.2":{ + "id":3, + "ip":"10.30.2.210", + "port":"50001", + "type":"OC-TP", + "driver": "OpticalOC" + }, + "T1.3":{ + "id":3, + "ip":"10.30.2.210", + "port":"50001", + "type":"OC-TP", + "driver": "OpticalOC" + }, + "T2.1":{ + "id":4, + "ip":"10.30.2.211", + "port":"50001", + "type":"OC-TP", + "driver": "OpticalOC" + }, + "T2.2":{ + "id":4, + "ip":"10.30.2.211", + "port":"50001", + "type":"OC-TP", + "driver": "OpticalOC" + }, + "T2.3":{ "id":4, "ip":"10.30.2.211", "port":"50001", diff --git a/src/opticalcontroller/json_files/tfs.json b/src/opticalcontroller/json_files/tfs.json index 31803b893..46ee3da95 100644 --- a/src/opticalcontroller/json_files/tfs.json +++ b/src/opticalcontroller/json_files/tfs.json @@ -1,16 +1,17 @@ { "links": [ { + "name": "T1.1-R1", "link_id": { "link_uuid": { - "uuid": "T1->R1" + "uuid": "T1.1->R1" } }, "link_endpoint_ids": [ { "device_id": { "device_uuid": { - "uuid": "T1" + "uuid": "T1.1" } }, "endpoint_uuid": { @@ -28,96 +29,294 @@ } } ], - "optical_link": { - "name": "T1-R1", - "details": { - "length": 0, - "source": "muxT", - "target": "srgR", - "fibers": [ - { - "ID": "M1", - "length": 0, - "src_port": "1", - "dst_port": "12", - "local_peer_port": "1", - "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 - ] + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "12", + "local_peer_port": "1", + "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 + ] + } + }, + { + "name": "T1.2-R1", + "link_id": { + "link_uuid": { + "uuid": "T1.2->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T1.2" } - ] + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "13" + } } + ], + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "13", + "local_peer_port": "1", + "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 + ] } }, { + "name": "T1.3-R1", "link_id": { "link_uuid": { - "uuid": "R1->T1" + "uuid": "T1.3->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T1.3" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "14" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "14", + "local_peer_port": "1", + "remote_peer_port": "4", + "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 + ] + } + }, + { + "name": "R1-T1.1", + "link_id": { + "link_uuid": { + "uuid": "R1->T1.1" } }, "link_endpoint_ids": [ @@ -134,7 +333,7 @@ { "device_id": { "device_uuid": { - "uuid": "T1" + "uuid": "T1.1" } }, "endpoint_uuid": { @@ -142,96 +341,190 @@ } } ], - "optical_link": { - "name": "R1-T1", - "details": { - "length": 0, - "source": "srgT", - "target": "muxT", - "fibers": [ - { - "ID": "M1", - "length": 0, - "src_port": "2", - "dst_port": "1", - "local_peer_port": "12", - "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 - ] + "optical_details": { + "length": 0, + "src_port": "2", + "dst_port": "1", + "local_peer_port": "12", + "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 + ] + } + }, + { + "name": "R1-T1.2", + "link_id": { + "link_uuid": { + "uuid": "R1->T1.2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "3" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T1.2" } - ] + }, + "endpoint_uuid": { + "uuid": "1" + } } + ], + "optical_details": { + "length": 0, + "src_port": "3", + "dst_port": "1", + "local_peer_port": "13", + "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 + ] } }, { + "name": "R1-T1.3", "link_id": { "link_uuid": { - "uuid": "R1->R2" + "uuid": "R1->T1.3" } }, "link_endpoint_ids": [ @@ -242,107 +535,201 @@ } }, "endpoint_uuid": { - "uuid": "3" + "uuid": "4" } }, { "device_id": { "device_uuid": { - "uuid": "R2" + "uuid": "T1.3" } }, "endpoint_uuid": { - "uuid": "14" + "uuid": "1" } } ], - "optical_link": { - "name": "R1-R2", - "details": { - "length": 0, - "source": "D1", - "target": "D1", - "fibers": [ - { - "ID": "D11", - "length": 0, - "src_port": "3", - "dst_port": "14", - "local_peer_port": "13", - "remote_peer_port": "4", - "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 - ] + "optical_details": { + "length": 0, + "src_port": "4", + "dst_port": "1", + "local_peer_port": "14", + "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 + ] + } + }, + { + "name": "R1-R2", + "link_id": { + "link_uuid": { + "uuid": "R1->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" } - ] + }, + "endpoint_uuid": { + "uuid": "101" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "201" + } } + ], + "optical_details": { + "length": 0, + "src_port": "101", + "dst_port": "201", + "local_peer_port": "201", + "remote_peer_port": "101", + "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": { + "name": "R2-R1", + "link_id": { "link_uuid": { "uuid": "R2->R1" } @@ -355,7 +742,7 @@ } }, "endpoint_uuid": { - "uuid": "4" + "uuid": "101" } }, { @@ -365,110 +752,308 @@ } }, "endpoint_uuid": { - "uuid": "13" + "uuid": "201" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "101", + "dst_port": "201", + "local_peer_port": "201", + "remote_peer_port": "101", + "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 + ] + } + }, + { + "name": "T2.1-R2", + "link_id": { + "link_uuid": { + "uuid": "T2.1->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T2.1" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "12" } } ], - "optical_link": { - "name": "R2-R1", - "details": { - "length": 0, - "source": "D1", - "target": "D1", - "fibers": [ - { - "ID": "D11", - "length": 0, - "src_port": "4", - "dst_port": "13", - "local_peer_port": "14", - "remote_peer_port": "3", - "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 - ] + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "12", + "local_peer_port": "1", + "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 + ] + } + }, + { + "name": "T2.2-R2", + "link_id": { + "link_uuid": { + "uuid": "T2.2->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T2.2" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" } - ] + }, + "endpoint_uuid": { + "uuid": "13" + } } + ], + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "13", + "local_peer_port": "1", + "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 + ] } }, { + "name": "T2.3-R2", "link_id": { "link_uuid": { - "uuid": "T2->R2" + "uuid": "T2.3->R2" } }, "link_endpoint_ids": [ { "device_id": { "device_uuid": { - "uuid": "T2" + "uuid": "T2.3" } }, "endpoint_uuid": { - "uuid": "6" + "uuid": "1" } }, { @@ -478,100 +1063,194 @@ } }, "endpoint_uuid": { - "uuid": "15" + "uuid": "14" } } ], - "optical_link": { - "name": "T2-R2", - "details": { - "length": 0, - "source": "srgT", - "target": "muxT", - "fibers": [ - { - "ID": "M1", - "length": 0, - "src_port": "6", - "dst_port": "15", - "local_peer_port": "6", - "remote_peer_port": "5", - "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 - ] + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "14", + "local_peer_port": "1", + "remote_peer_port": "4", + "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 + ] + } + }, + { + "name": "R2-T2.1", + "link_id": { + "link_uuid": { + "uuid": "R2->T2.1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" } - ] + }, + "endpoint_uuid": { + "uuid": "2" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T2.1" + } + }, + "endpoint_uuid": { + "uuid": "1" + } } + ], + "optical_details": { + "length": 0, + "src_port": "2", + "dst_port": "1", + "local_peer_port": "12", + "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 + ] } }, { + "name": "R2-T2.2", "link_id": { "link_uuid": { - "uuid": "R2->T2" + "uuid": "R1->T2.2" } }, "link_endpoint_ids": [ @@ -582,104 +1261,197 @@ } }, "endpoint_uuid": { - "uuid": "5" + "uuid": "3" } }, { "device_id": { "device_uuid": { - "uuid": "T2" + "uuid": "T2.2" } }, "endpoint_uuid": { - "uuid": "6" + "uuid": "1" } } ], - "optical_link": { - "name": "R2-T2", - "details": { - "length": 0, - "source": "srgT", - "target": "muxT", - "fibers": [ - { - "ID": "M1", - "length": 0, - "src_port": "5", - "dst_port": "6", - "local_peer_port": "15", - "remote_peer_port": "6", - "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 - ] + "optical_details": { + "length": 0, + "src_port": "3", + "dst_port": "1", + "local_peer_port": "13", + "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 + ] + } + }, + { + "name": "R2-T2.3", + "link_id": { + "link_uuid": { + "uuid": "R2->T2.3" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" } - ] + }, + "endpoint_uuid": { + "uuid": "4" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T2.3" + } + }, + "endpoint_uuid": { + "uuid": "1" + } } + ], + "optical_details": { + "length": 0, + "src_port": "4", + "dst_port": "1", + "local_peer_port": "14", + "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 + ] } } ] diff --git a/src/opticalcontroller/json_files/tfs_dict.json b/src/opticalcontroller/json_files/tfs_dict.json new file mode 100644 index 000000000..de7ec97fb --- /dev/null +++ b/src/opticalcontroller/json_files/tfs_dict.json @@ -0,0 +1,1458 @@ +{ + "optical_links": [ + { + "name": "T1.1-R1", + "link_id": { + "link_uuid": { + "uuid": "T1.1->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T1.1" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "12" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "12", + "local_peer_port": "1", + "remote_peer_port": "2", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "T1.2-R1", + "link_id": { + "link_uuid": { + "uuid": "T1.2->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T1.2" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "13" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "13", + "local_peer_port": "1", + "remote_peer_port": "3", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "T1.3-R1", + "link_id": { + "link_uuid": { + "uuid": "T1.3->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T1.3" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "14" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "14", + "local_peer_port": "1", + "remote_peer_port": "4", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "R1-T1.1", + "link_id": { + "link_uuid": { + "uuid": "R1->T1.1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "2" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T1.1" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "2", + "dst_port": "1", + "local_peer_port": "12", + "remote_peer_port": "1", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "R1-T1.2", + "link_id": { + "link_uuid": { + "uuid": "R1->T1.2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "3" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T1.2" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "3", + "dst_port": "1", + "local_peer_port": "13", + "remote_peer_port": "1", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "R1-T1.3", + "link_id": { + "link_uuid": { + "uuid": "R1->T1.3" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "4" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T1.3" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "4", + "dst_port": "1", + "local_peer_port": "14", + "remote_peer_port": "1", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "R1-R2", + "link_id": { + "link_uuid": { + "uuid": "R1->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "101" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "201" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "101", + "dst_port": "201", + "local_peer_port": "201", + "remote_peer_port": "101", + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "R2-R1", + "link_id": { + "link_uuid": { + "uuid": "R2->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "101" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "201" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "101", + "dst_port": "201", + "local_peer_port": "201", + "remote_peer_port": "101", + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "T2.1-R2", + "link_id": { + "link_uuid": { + "uuid": "T2.1->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T2.1" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "12" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "12", + "local_peer_port": "1", + "remote_peer_port": "2", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "T2.2-R2", + "link_id": { + "link_uuid": { + "uuid": "T2.2->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T2.2" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "13" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "13", + "local_peer_port": "1", + "remote_peer_port": "3", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "T2.3-R2", + "link_id": { + "link_uuid": { + "uuid": "T2.3->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "T2.3" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "14" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "1", + "dst_port": "14", + "local_peer_port": "1", + "remote_peer_port": "4", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "R2-T2.1", + "link_id": { + "link_uuid": { + "uuid": "R2->T2.1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "2" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T2.1" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "2", + "dst_port": "1", + "local_peer_port": "12", + "remote_peer_port": "1", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "R2-T2.2", + "link_id": { + "link_uuid": { + "uuid": "R1->T2.2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "3" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T2.2" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "3", + "dst_port": "1", + "local_peer_port": "13", + "remote_peer_port": "1", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + }, + { + "name": "R2-T2.3", + "link_id": { + "link_uuid": { + "uuid": "R2->T2.3" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "4" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "T2.3" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + } + ], + "optical_details": { + "length": 0, + "src_port": "4", + "dst_port": "1", + "local_peer_port": "14", + "remote_peer_port": "1", + "used": false, + "c_slots": { + "1": 1, + "2": 1, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 1, + "10": 1, + "11": 1, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 1, + "17": 1, + "18": 1, + "19": 1, + "20": 1 + }, + "l_slots": { + "101": 1, + "102": 1, + "103": 1, + "104": 1, + "105": 1, + "106": 1, + "107": 1, + "108": 1, + "109": 1, + "110": 1, + "111": 1, + "112": 1, + "113": 1, + "114": 1, + "115": 1, + "116": 1, + "117": 1, + "118": 1, + "119": 1, + "120": 1 + }, + "s_slots": { + "501": 1, + "502": 1, + "503": 1, + "504": 1, + "505": 1, + "506": 1, + "507": 1, + "508": 1, + "509": 1, + "510": 1, + "511": 1, + "512": 1, + "513": 1, + "514": 1, + "515": 1, + "516": 1, + "517": 1, + "518": 1, + "519": 1, + "520": 1 + } + } + } + ] +} \ No newline at end of file diff --git a/src/opticalcontroller/requirements.in b/src/opticalcontroller/requirements.in index fefe604bc..4746979fe 100644 --- a/src/opticalcontroller/requirements.in +++ b/src/opticalcontroller/requirements.in @@ -1,21 +1,22 @@ -# 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. - +aniso8601==9.0.1 +attrs==23.1.0 +blinker==1.6.2 +click==8.1.7 +colorama==0.4.6 Flask==1.1.2 flask-restplus==0.13.0 +importlib-metadata==6.8.0 +importlib-resources==6.0.1 itsdangerous==1.1.0 Jinja2==2.11.3 +jsonschema==4.19.0 +jsonschema-specifications==2023.7.1 MarkupSafe==1.1.1 numpy==1.23.0 +pkgutil-resolve-name==1.3.10 +pytz==2023.3.post1 +referencing==0.30.2 +rpds-py==0.10.3 +six==1.16.0 Werkzeug==0.16.1 +zipp==3.16.2 diff --git a/src/opticalcontroller/requirements_opt.txt b/src/opticalcontroller/requirements_opt.txt new file mode 100644 index 000000000..e4b8abe1b --- /dev/null +++ b/src/opticalcontroller/requirements_opt.txt @@ -0,0 +1,7 @@ +Flask==1.1.2 +flask-restplus==0.13.0 +itsdangerous==1.1.0 +Jinja2==2.11.3 +MarkupSafe==1.1.1 +numpy==1.23.0 +Werkzeug==0.16.1 diff --git a/src/opticalcontroller/test.py b/src/opticalcontroller/test.py new file mode 100644 index 000000000..255ee2de4 --- /dev/null +++ b/src/opticalcontroller/test.py @@ -0,0 +1,12 @@ +import json + + +def readTopologyData(): + topo_file = open("json_files/tfs_dict.json", 'r') + topo = json.load(topo_file) + # print(topo) + topo_file.close() + return topo + + +print(readTopologyData()) \ No newline at end of file diff --git a/src/opticalcontroller/tools.py b/src/opticalcontroller/tools.py index 3b3223d81..197305255 100644 --- a/src/opticalcontroller/tools.py +++ b/src/opticalcontroller/tools.py @@ -1,20 +1,8 @@ -# 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 +import json , logging +from context.client.ContextClient import ContextClient +from common.proto.context_pb2 import TopologyId def common_slots(a, b): @@ -54,20 +42,23 @@ def map_rate_to_slot(rate): return 2, 5 -def consecutives(x, val): +def consecutives(link, val): res = [] temp = [] + x1 = list(link.keys()) + x = str_list_to_int(x1) x.sort() - temp.append(x[0]) + temp.append(int(x[0])) y = 1 + #print(link, x) for i in range(1, len(x)): - if x[i] == x[i - 1] + 1: + if (int(x[i]) == int(x[i - 1]) + 1) and link[str(x[i])] == 1: y += 1 - temp.append(x[i]) + temp.append(int(x[i])) else: if y >= val: res.extend(temp) - temp = [x[i]] + temp = [int(x[i])] y = 1 if i == len(x) - 1 and y >= val: res.extend(temp) @@ -83,6 +74,13 @@ def combine(ls1, ls2): return temp +def str_list_to_int(str_list): + int_list = [] + for i in str_list: + int_list.append(int(i)) + return int_list + + def list_in_list(a, b): # convert list A to numpy array a_arr = np.array(a) @@ -135,15 +133,27 @@ def freqency_converter(b, slots): def readTopologyData(nodes, topology): + + nodes_file = open(nodes, 'r') topo_file = open(topology, 'r') nodes = json.load(nodes_file) topo = json.load(topo_file) - print(topo) + #print(topo) nodes_file.close() topo_file.close() return nodes, topo - +def readTopologyDataFromContext(topology_id:TopologyId): + + + ctx_client = ContextClient() + ctx_client.connect() + topo_details = ctx_client.GetTopologyDetails(topology_id) + topo = topo_details.optical_links + nodes = topo_details.devices + ctx_client.close() + return topo , nodes + def reverse_links(links): temp_links = links.copy() @@ -154,18 +164,20 @@ def reverse_links(links): result.append("{}-{}".format(b, a)) return result + def get_links_from_node(topology, node): result = {} for link in topology["links"]: - if "{}-".format(node) in link["optical_link"]["name"]: - result[link["optical_link"]["name"]] = link + if "{}-".format(node) in link["name"]: + result[link["name"]] = link return result + def get_links_to_node(topology, node): result = {} for link in topology["links"]: - if "-{}".format(node) in link["optical_link"]["name"]: - result[link["optical_link"]["name"]] = link + if "-{}".format(node) in link["name"]: + result[link["name"]] = link return result @@ -183,7 +195,7 @@ def slot_selection(c, l, s, n_slots, Nc, Nl, Ns): return "c_slots", c[0: slot_c] elif len(l) >= slot_l: return "l_slots", l[0: slot_l] - elif len(l) >= slot_s: + elif len(s) >= slot_s: return "s_slots", s[0: slot_s] else: return None, None diff --git a/src/opticalcontroller/variables.py b/src/opticalcontroller/variables.py index cbb65200f..28ee66208 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 @@ -24,7 +10,7 @@ Nc = 320 Ns = 720 nodes_json = 'json_files/nodes.json' -topology_json = 'json_files/tfs.json' #LAST +topology_json = 'json_files/tfs_dict.json' #LAST #topology_json = 'json_files/optical_TFSworking.json' #LAST #topology_json = 'json_files/optical_topoTFS.json' #topology_json = 'json_files/topo_2_links.json' diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py index b5623885f..94f200bbb 100644 --- a/src/service/service/ServiceServiceServicerImpl.py +++ b/src/service/service/ServiceServiceServicerImpl.py @@ -39,7 +39,7 @@ from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory from .task_scheduler.TaskScheduler import TasksScheduler from .tools.GeodesicDistance import gps_distance from .tools.OpticalTools import ( - add_lightpath, delete_lightpath, adapt_reply, get_device_name_from_uuid, get_optical_band + add_lightpath, delete_lightpath, adapt_reply, get_device_name_from_uuid, get_optical_band,refresh_opticalcontroller ) @@ -254,6 +254,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): DEFAULT_TOPOLOGY_NAME, context_id_x) topology_details = context_client.GetTopologyDetails( TopologyId(**topology_id_x)) + #refresh_opticalcontroller(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 diff --git a/src/service/service/__main__.py b/src/service/service/__main__.py index edd4d8f99..5a700b57d 100644 --- a/src/service/service/__main__.py +++ b/src/service/service/__main__.py @@ -12,7 +12,7 @@ # 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 ( @@ -44,8 +44,11 @@ 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.OPTICALCONTROLLER, ENVVAR_SUFIX_SERVICE_PORT_GRPC), + get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER, ENVVAR_SUFIX_SERVICE_HOST ), + ]) - + LOGGER.info(os.environ) signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) diff --git a/src/service/service/tools/OpticalTools.py b/src/service/service/tools/OpticalTools.py index 206524371..31bcb7bcf 100644 --- a/src/service/service/tools/OpticalTools.py +++ b/src/service/service/tools/OpticalTools.py @@ -41,7 +41,7 @@ opticalcontrollers_url = find_environment_variables([ ]) OPTICAL_IP = opticalcontrollers_url.get(VAR_NAME_OPTICAL_CONTROLLER_HOST) OPTICAL_PORT = opticalcontrollers_url.get(VAR_NAME_OPTICAL_CONTROLLER_PORT) -log.info(str(OPTICAL_IP), str(OPTICAL_PORT)) +log.info(f"OPTICAL_IP:{OPTICAL_IP} OPTICAL_PORT:{OPTICAL_PORT}") def get_uuids_from_names(devices: List[Device], device_name: str, port_name: str): device_uuid = "" @@ -77,6 +77,11 @@ def get_device_name_from_uuid(devices: List[Device], device_uuid: str): return device_name return "" +def refresh_opticalcontroller (topology_id:TopologyId): + headers = {"Content-Type": "application/json"} + urlx = "http://{}:{}/GetTopology/{}".format(OPTICAL_IP, OPTICAL_PORT,topology_id) + res = requests.get(urlx, headers=headers) + logging.info(f"Refresh opticalcontroller {res}") def add_lightpath(src, dst, bitrate, bidir, ob_band) -> str: if not testing: @@ -91,6 +96,7 @@ def add_lightpath(src, dst, bitrate, bidir, ob_band) -> str: bidir = 1 urlx = "http://{}:{}/OpticalTFS/AddFlexLightpath/{}/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, src, dst, bitrate, bidir, ob_band) r = requests.put(urlx, headers=headers) + print(f"addpathlight {r}") reply = r.text return reply else: diff --git a/src/tests/ofc24/r_t.sh b/src/tests/ofc24/r_t.sh new file mode 100644 index 000000000..f5357fc37 --- /dev/null +++ b/src/tests/ofc24/r_t.sh @@ -0,0 +1,31 @@ +#!/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 + + +docker stop -t 1 t1 +docker stop -t 1 na3 +docker stop -t 1 t2 +docker stop -t 1 na2 + +docker rm t1 +docker rm na3 + +docker rm t2 +docker rm na2 + +screen -dmS t1 -T xterm sh -c "docker run --name t1 -p 10.0.2.4:2023:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files -it asgamb1/oc23bgp.img:latest bash -c 'cp /files/platform_t1.xml demoECOC21.xml ; ./startNetconfAgent.sh'" +screen -dmS t3 -T xterm sh -c "docker run --name na3 -p 10.0.2.4:2025:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files -it asgamb1/flexscale-node.img:latest bash -c 'cp /files/platform_r1.xml init_openconfig-platform.xml ; ./startNetconfAgent.sh'" +screen -dmS t2 -T xterm sh -c "docker run --name t2 -p 10.0.2.4:2024:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files -it asgamb1/oc23bgp.img:latest bash -c 'cp /files/platform_t2.xml demoECOC21.xml ; ./startNetconfAgent.sh'" +screen -dmS t4 -T xterm sh -c "docker run --name na2 -p 10.0.2.4:2026:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files -it asgamb1/flexscale-node.img:latest bash -c 'cp /files/platform_r2.xml init_openconfig-platform.xml ; ./startNetconfAgent.sh'" \ No newline at end of file diff --git a/src/tests/ofc24/roadms.sh b/src/tests/ofc24/roadms.sh new file mode 100644 index 000000000..ac5101376 --- /dev/null +++ b/src/tests/ofc24/roadms.sh @@ -0,0 +1,26 @@ +#!/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. + + +docker stop -t 1 na3 +docker stop -t 1 na4 + +docker rm na3 +docker rm na4 + + + +screen -dmS t3 -T xterm sh -c "docker run --name na3 -p 10.0.2.4:2025:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files -it asgamb1/flexscale-node.img:latest bash -c 'cp /files/platform_r1.xml demoECOC21.xml ; ./startNetconfAgent.sh'" +screen -dmS t4 -T xterm sh -c "docker run --name na4 -p 10.0.2.4:2026:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files -it asgamb1/flexscale-node.img:latest bash -c 'cp /files/platform_r2.xml demoECOC21.xml ; ./startNetconfAgent.sh'" \ No newline at end of file diff --git a/src/tests/ofc24/tempOC/files/platform_r1.xml b/src/tests/ofc24/tempOC/files/platform_r1.xml index 625d7048a..02ea8feb4 100644 --- a/src/tests/ofc24/tempOC/files/platform_r1.xml +++ b/src/tests/ofc24/tempOC/files/platform_r1.xml @@ -116,5 +116,122 @@ </property> </properties> </component> - </components> -</config> + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> + <name>4</name> + <config> + <name>4</name> + </config> + <properties> + <property> + <name>MG_ON_PORT_TYPE</name> + <config> + <name>MG_ON_PORT_TYPE</name> + <value>MG_ON_OPTICAL_PORT_WAVEBAND</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DIRECTION</name> + <config> + <name>MG_ON_PORT_DIRECTION</name> + <value>OUTPUT</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DEGREE</name> + <config> + <name>MG_ON_PORT_DEGREE</name> + <value>D2</value> + </config> + </property> + </properties> + </component> + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> + <name>14</name> + <config> + <name>14</name> + </config> + <properties> + <property> + <name>MG_ON_PORT_TYPE</name> + <config> + <name>MG_ON_PORT_TYPE</name> + <value>MG_ON_OPTICAL_PORT_WAVEBAND</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DIRECTION</name> + <config> + <name>MG_ON_PORT_DIRECTION</name> + <value>INPUT</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DEGREE</name> + <config> + <name>MG_ON_PORT_DEGREE</name> + <value>D2</value> + </config> + </property> + </properties> + </component> + + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> + <name>101</name> + <config> + <name>101</name> + </config> + <properties> + <property> + <name>MG_ON_PORT_TYPE</name> + <config> + <name>MG_ON_PORT_TYPE</name> + <value>MG_ON_OPTICAL_PORT_WAVEBAND</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DIRECTION</name> + <config> + <name>MG_ON_PORT_DIRECTION</name> + <value>OUTPUT</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DEGREE</name> + <config> + <name>MG_ON_PORT_DEGREE</name> + <value>D2</value> + </config> + </property> + </properties> + </component> + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> + <name>111</name> + <config> + <name>111</name> + </config> + <properties> + <property> + <name>MG_ON_PORT_TYPE</name> + <config> + <name>MG_ON_PORT_TYPE</name> + <value>MG_ON_OPTICAL_PORT_WAVEBAND</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DIRECTION</name> + <config> + <name>MG_ON_PORT_DIRECTION</name> + <value>INPUT</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DEGREE</name> + <config> + <name>MG_ON_PORT_DEGREE</name> + <value>D2</value> + </config> + </property> + </properties> + </component> + </components> +</config> \ No newline at end of file diff --git a/src/tests/ofc24/tempOC/files/platform_r2.xml b/src/tests/ofc24/tempOC/files/platform_r2.xml index 65f7ee458..04d1d8370 100644 --- a/src/tests/ofc24/tempOC/files/platform_r2.xml +++ b/src/tests/ofc24/tempOC/files/platform_r2.xml @@ -1,5 +1,121 @@ <config xmlns="http://tail-f.com/ns/config/1.0"> <components xmlns="http://openconfig.net/yang/platform"> + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> + <name>2</name> + <config> + <name>2</name> + </config> + <properties> + <property> + <name>MG_ON_PORT_TYPE</name> + <config> + <name>MG_ON_PORT_TYPE</name> + <value>MG_ON_OPTICAL_PORT_WAVEBAND</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DIRECTION</name> + <config> + <name>MG_ON_PORT_DIRECTION</name> + <value>OUTPUT</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DEGREE</name> + <config> + <name>MG_ON_PORT_DEGREE</name> + <value>D1</value> + </config> + </property> + </properties> + </component> + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> + <name>12</name> + <config> + <name>12</name> + </config> + <properties> + <property> + <name>MG_ON_PORT_TYPE</name> + <config> + <name>MG_ON_PORT_TYPE</name> + <value>MG_ON_OPTICAL_PORT_WAVEBAND</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DIRECTION</name> + <config> + <name>MG_ON_PORT_DIRECTION</name> + <value>INPUT</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DEGREE</name> + <config> + <name>MG_ON_PORT_DEGREE</name> + <value>D1</value> + </config> + </property> + </properties> + </component> + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> + <name>3</name> + <config> + <name>3</name> + </config> + <properties> + <property> + <name>MG_ON_PORT_TYPE</name> + <config> + <name>MG_ON_PORT_TYPE</name> + <value>MG_ON_OPTICAL_PORT_WAVEBAND</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DIRECTION</name> + <config> + <name>MG_ON_PORT_DIRECTION</name> + <value>OUTPUT</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DEGREE</name> + <config> + <name>MG_ON_PORT_DEGREE</name> + <value>D2</value> + </config> + </property> + </properties> + </component> + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> + <name>13</name> + <config> + <name>13</name> + </config> + <properties> + <property> + <name>MG_ON_PORT_TYPE</name> + <config> + <name>MG_ON_PORT_TYPE</name> + <value>MG_ON_OPTICAL_PORT_WAVEBAND</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DIRECTION</name> + <config> + <name>MG_ON_PORT_DIRECTION</name> + <value>INPUT</value> + </config> + </property> + <property> + <name>MG_ON_PORT_DEGREE</name> + <config> + <name>MG_ON_PORT_DEGREE</name> + <value>D2</value> + </config> + </property> + </properties> + </component> <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> <name>4</name> <config> @@ -24,7 +140,7 @@ <name>MG_ON_PORT_DEGREE</name> <config> <name>MG_ON_PORT_DEGREE</name> - <value>D1</value> + <value>D2</value> </config> </property> </properties> @@ -53,15 +169,16 @@ <name>MG_ON_PORT_DEGREE</name> <config> <name>MG_ON_PORT_DEGREE</name> - <value>D1</value> + <value>D2</value> </config> </property> </properties> </component> + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> - <name>5</name> + <name>101</name> <config> - <name>5</name> + <name>101</name> </config> <properties> <property> @@ -88,9 +205,9 @@ </properties> </component> <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> - <name>15</name> + <name>111</name> <config> - <name>15</name> + <name>111</name> </config> <properties> <property> @@ -116,5 +233,5 @@ </property> </properties> </component> - </components> -</config> + </components> +</config> \ No newline at end of file diff --git a/src/tests/ofc24/copy.sh b/src/tests/ofc24/transponders.sh similarity index 100% rename from src/tests/ofc24/copy.sh rename to src/tests/ofc24/transponders.sh diff --git a/src/webui/service/__init__.py b/src/webui/service/__init__.py index 196652d3f..00908079d 100644 --- a/src/webui/service/__init__.py +++ b/src/webui/service/__init__.py @@ -84,8 +84,14 @@ def create_app(use_config=None, web_app_root=None): from webui.service.load_gen.routes import load_gen # pylint: disable=import-outside-toplevel app.register_blueprint(load_gen) + from webui.service.base_optical.route import base_optical # pylint: disable=import-outside-toplevel + app.register_blueprint(base_optical) + from webui.service.opticalconfig.routes import opticalconfig # pylint: disable=import-outside-toplevel app.register_blueprint(opticalconfig) + + from webui.service.optical_link.routes import optical_link # pylint: disable=import-outside-toplevel + app.register_blueprint(optical_link) from webui.service.service.routes import service # pylint: disable=import-outside-toplevel app.register_blueprint(service) diff --git a/src/webui/service/base_optical/__init__.py b/src/webui/service/base_optical/__init__.py new file mode 100644 index 000000000..1549d9811 --- /dev/null +++ b/src/webui/service/base_optical/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/webui/service/base_optical/route.py b/src/webui/service/base_optical/route.py new file mode 100644 index 000000000..e3f37de51 --- /dev/null +++ b/src/webui/service/base_optical/route.py @@ -0,0 +1,29 @@ +# 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 current_app, render_template, Blueprint, flash, session, redirect, url_for +from common.proto.context_pb2 import Empty, OpticalLink, LinkId, OpticalLinkList +from common.tools.context_queries.EndPoint import get_endpoint_names +from common.tools.context_queries.Link import get_link +from common.tools.context_queries.Topology import get_topology +from context.client.ContextClient import ContextClient + + +base_optical = Blueprint('base_optical', __name__, url_prefix='/base_optical') + +@base_optical.get('/') +def home(): + + return render_template("base_optical/home.html") \ No newline at end of file diff --git a/src/webui/service/main/routes.py b/src/webui/service/main/routes.py index 1fd7e006c..9f700283d 100644 --- a/src/webui/service/main/routes.py +++ b/src/webui/service/main/routes.py @@ -155,11 +155,23 @@ def topology(): 'source': link.link_endpoint_ids[0].device_id.device_uuid.uuid, 'target': link.link_endpoint_ids[1].device_id.device_uuid.uuid, }) - - return jsonify({'devices': devices, 'links': links}) + optical_links = [] + for link in response.optical_links: + if len(link.link_endpoint_ids) != 2: + str_link = grpc_message_to_json_string(link) + LOGGER.warning('Unexpected link with len(endpoints) != 2: {:s}'.format(str_link)) + continue + optical_links.append({ + 'id': link.link_id.link_uuid.uuid, + 'name': link.name, + 'source': link.link_endpoint_ids[0].device_id.device_uuid.uuid, + 'target': link.link_endpoint_ids[1].device_id.device_uuid.uuid, + }) + LOGGER.info(f"optical links {optical_links}") + return jsonify({'devices': devices, 'links': links ,'optical_links':optical_links}) except: # pylint: disable=bare-except LOGGER.exception('Error retrieving topology') - return jsonify({'devices': [], 'links': []}) + return jsonify({'devices': [], 'links': [],'optical_links':[]}) finally: context_client.close() diff --git a/src/webui/service/optical_link/__init__.py b/src/webui/service/optical_link/__init__.py new file mode 100644 index 000000000..355dcdb04 --- /dev/null +++ b/src/webui/service/optical_link/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/webui/service/optical_link/routes.py b/src/webui/service/optical_link/routes.py new file mode 100644 index 000000000..7be81410e --- /dev/null +++ b/src/webui/service/optical_link/routes.py @@ -0,0 +1,93 @@ +# 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 current_app, render_template, Blueprint, flash, session, redirect, url_for +from common.proto.context_pb2 import Empty, OpticalLink, LinkId, OpticalLinkList +from common.tools.context_queries.EndPoint import get_endpoint_names +from common.tools.context_queries.Link import get_link +from common.tools.context_queries.Topology import get_topology +from context.client.ContextClient import ContextClient + + +optical_link = Blueprint('optical_link', __name__, url_prefix='/optical_link') +context_client = ContextClient() + +@optical_link.get('/') +def home(): + if 'context_uuid' not in session or 'topology_uuid' not in session: + flash("Please select a context!", "warning") + return redirect(url_for("main.home")) + + context_uuid = session['context_uuid'] + topology_uuid = session['topology_uuid'] + + links, endpoint_ids = list(), list() + device_names, endpoints_data = dict(), dict() + + context_client.connect() + grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) + if grpc_topology is None: + flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') + else: + topo_link_uuids = {link_id.link_uuid.uuid for link_id in grpc_topology.link_ids} + grpc_links: OpticalLinkList = context_client.GetOpticalLinkList(Empty()) + for link_ in grpc_links.optical_links: + + links.append(link_) + endpoint_ids.extend(link_.link_endpoint_ids) + device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids) + context_client.close() + + return render_template('optical_link/home.html', links=links, device_names=device_names, endpoints_data=endpoints_data) + + +@optical_link.route('detail/<path:link_uuid>', methods=('GET', 'POST')) +def detail(link_uuid: str): + context_client.connect() + # pylint: disable=no-member + link_id = LinkId() + link_id.link_uuid.uuid = link_uuid + link_obj = context_client.GetOpticalLink(link_id) + + if link_obj is None: + flash('Optical Link({:s}) not found'.format(str(link_uuid)), 'danger') + link_obj = OpticalLink() + device_names, endpoints_data = dict(), dict() + else: + device_names, endpoints_data = get_endpoint_names(context_client, link_obj.link_endpoint_ids) + context_client.close() + return render_template('optical_link/detail.html',link=link_obj, device_names=device_names, endpoints_data=endpoints_data) + +@optical_link.get('<path:link_uuid>/delete') +def delete(link_uuid): + try: + + # first, check if link exists! + # request: LinkId = LinkId() + # request.link_uuid.uuid = link_uuid + # response: Link = client.GetLink(request) + # TODO: finalize implementation + + request = LinkId() + request.link_uuid.uuid = link_uuid # pylint: disable=no-member + context_client.connect() + context_client.DeleteOpticalLink(request) + context_client.close() + + flash(f'Optical Link "{link_uuid}" deleted successfully!', 'success') + except Exception as e: # pylint: disable=broad-except + flash(f'Problem deleting link "{link_uuid}": {e.details()}', 'danger') + current_app.logger.exception(e) + return redirect(url_for('optical_link.home')) diff --git a/src/webui/service/templates/base.html b/src/webui/service/templates/base.html index e081b2710..32b658746 100644 --- a/src/webui/service/templates/base.html +++ b/src/webui/service/templates/base.html @@ -84,10 +84,10 @@ {% endif %} </li> <li class="nav-item"> - {% if '/opticalconfig/' in request.path %} - <a class="nav-link active" aria-current="page" href="{{ url_for('opticalconfig.home') }}">Optical Config</a> + {% if '/base_optical/' in request.path %} + <a class="nav-link active" aria-current="page" href="{{ url_for('base_optical.home') }}">Optical Config</a> {% else %} - <a class="nav-link" href="{{ url_for('opticalconfig.home') }}">Optical Config</a> + <a class="nav-link" href="{{ url_for('base_optical.home') }}">Optical Config</a> {% endif %} </li> <li class="nav-item"> diff --git a/src/webui/service/templates/base_optical/home.html b/src/webui/service/templates/base_optical/home.html new file mode 100644 index 000000000..e6cae4c67 --- /dev/null +++ b/src/webui/service/templates/base_optical/home.html @@ -0,0 +1,40 @@ +<!-- + 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. + --> + + {% extends 'base.html' %} + + {% block content %} + <h1>My Configurations</h1> + + <div class="row"> + <div class="col"> + <a href="{{ url_for('opticalconfig.home') }}" class="btn btn-primary" style="margin-bottom: 10px;"> + + Optical Devices + </a> + </div> + <div class="col"> + <a href="{{ url_for('optical_link.home') }}" class="btn btn-primary" style="margin-bottom: 10px;"> + + Optical Links + </a> + </div> + </div> + + + + + {% endblock %} \ No newline at end of file diff --git a/src/webui/service/templates/js/topology.js b/src/webui/service/templates/js/topology.js index 1b34f2b2c..fa2cfb41b 100644 --- a/src/webui/service/templates/js/topology.js +++ b/src/webui/service/templates/js/topology.js @@ -85,6 +85,21 @@ d3.json("{{ url_for('main.topology') }}", function(data) { .attr("stroke-dasharray", function(l) { return l.name.toLowerCase().includes('mgmt') ? "5,5" : "0"; }); + optical_link = svg.append("g").attr("class", "links").style('stroke', '#aaa') + .selectAll("line") + .data(data.optical_links) + .enter() + .append("line") + .attr("opacity", 1) + .attr("stroke", function(l) { + return l.name.toLowerCase().includes('mgmt') ? '#AAAAAA' : '#555555'; + }) + .attr("stroke-width", function(l) { + return l.name.toLowerCase().includes('mgmt') ? 1 : 2; + }) + .attr("stroke-dasharray", function(l) { + return l.name.toLowerCase().includes('mgmt') ? "5,5" : "0"; + }); node = svg.append("g").attr("class", "devices").attr('r', 20).style('fill', '#69b3a2') .selectAll("circle") .data(data.devices) diff --git a/src/webui/service/templates/link/detail.html b/src/webui/service/templates/link/detail.html index 864d0cdb2..13c397334 100644 --- a/src/webui/service/templates/link/detail.html +++ b/src/webui/service/templates/link/detail.html @@ -20,7 +20,7 @@ <h1>Link {{ link.name }} ({{ link.link_id.link_uuid.uuid }})</h1> <div class="row mb-3"> <div class="col-sm-3"> - <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('link.home') }}'"> + <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('optical_link.home') }}'"> <i class="bi bi-box-arrow-in-left"></i> Back to link list </button> @@ -102,6 +102,7 @@ </table> + <!-- Modal --> <div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true"> diff --git a/src/webui/service/templates/link/home.html b/src/webui/service/templates/link/home.html index ca96a59b5..9902702fa 100644 --- a/src/webui/service/templates/link/home.html +++ b/src/webui/service/templates/link/home.html @@ -78,7 +78,7 @@ </td> <td> - <a href="{{ url_for('link.detail', link_uuid=link.link_id.link_uuid.uuid) }}"> + <a href="{{ url_for('optical_link.detail', link_uuid=link.link_id.link_uuid.uuid) }}"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16"> <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/> <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/> diff --git a/src/webui/service/templates/optical_link/detail.html b/src/webui/service/templates/optical_link/detail.html new file mode 100644 index 000000000..537c437a8 --- /dev/null +++ b/src/webui/service/templates/optical_link/detail.html @@ -0,0 +1,126 @@ +<!-- + 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. + --> + +{% extends 'base.html' %} + +{% block content %} +<h1>Link {{ link.name }} ({{ link.link_id.link_uuid.uuid }})</h1> +<div class="row mb-3"> + <div class="col-sm-3"> + <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('optical_link.home') }}'"> + <i class="bi bi-box-arrow-in-left"></i> + Back to link list + </button> + </div> + <div class="col-sm-3"> + <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete link</button> --> + <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal"> + <i class="bi bi-x-square"></i> + Delete link + </button> + </div> +</div> + +<br> +<div class="row mb-3"> + <div class="col-sm-4"> + <b>UUID: </b>{{ link.link_id.link_uuid.uuid }}<br> + <b>Name: </b>{{ link.name }}<br> + </div> + <div class="col-sm-8"> + <table class="table table-striped table-hover"> + <thead> + <tr> + <th scope="col">Endpoint UUID</th> + <th scope="col">Name</th> + <th scope="col">Device</th> + <th scope="col">Endpoint Type</th> + </tr> + </thead> + <tbody> + {% for endpoint in link.link_endpoint_ids %} + <tr> + <td> + {{ endpoint.endpoint_uuid.uuid }} + </td> + <td> + {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, (endpoint.endpoint_uuid.uuid, ''))[0] }} + </td> + <td> + <a href="{{ url_for('device.detail', device_uuid=endpoint.device_id.device_uuid.uuid) }}"> + {{ device_names.get(endpoint.device_id.device_uuid.uuid, endpoint.device_id.device_uuid.uuid) }} + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16"> + <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/> + <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/> + </svg> + </a> + </td> + <td> + {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, ('', '-'))[1] }} + </td> + </tr> + {% endfor %} + </tbody> + </table> + </div> +</div> + + + +<b>Optical Link Detail:</b> +<table class="table table-striped table-hover"> + <thead> + <tr> + <th scope="col">Key</th> + <th scope="col">Value</th> + </tr> + </thead> + <tbody> + {% for field_descriptor, field_value in link.optical_details.ListFields() %} + <tr> + <td> + {{ field_descriptor.name }} + </td> + <td> + {{ field_value }} + </td> + </tr> + {% endfor %} + </tbody> +</table> +<!-- Modal --> +<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" + aria-labelledby="staticBackdropLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title" id="staticBackdropLabel">Delete link?</h5> + <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> + </div> + <div class="modal-body"> + Are you sure you want to delete the link "{{ link.link_id.link_uuid.uuid }}"? + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button> + <a type="button" class="btn btn-danger" + href="{{ url_for('link.delete', link_uuid=link.link_id.link_uuid.uuid) }}"><i + class="bi bi-exclamation-diamond"></i>Yes</a> + </div> + </div> + </div> +</div> + +{% endblock %} diff --git a/src/webui/service/templates/optical_link/home.html b/src/webui/service/templates/optical_link/home.html new file mode 100644 index 000000000..e5aca5695 --- /dev/null +++ b/src/webui/service/templates/optical_link/home.html @@ -0,0 +1,98 @@ +<!-- + 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. + --> + + {% extends 'base.html' %} + + {% block content %} + <h1>Optical Links</h1> + + <div class="row"> + <div class="col"> + <!-- <a href="#" class="btn btn-primary" style="margin-bottom: 10px;"> + <i class="bi bi-plus"></i> + Add New Link + </a> --> + </div> + <div class="col"> + {{ links | length }} links found in context <i>{{ session['context_uuid'] }}</i> + </div> + <!-- <div class="col"> + <form> + <div class="input-group"> + <input type="text" aria-label="Search" placeholder="Search..." class="form-control"/> + <button type="submit" class="btn btn-primary">Search</button> + </div> + </form> + </div> --> + </div> + + <table class="table table-striped table-hover"> + <thead> + <tr> + <th scope="col">UUID</th> + <th scope="col">Name</th> + <th scope="col">Endpoints</th> + <th scope="col"></th> + </tr> + </thead> + <tbody> + {% if links %} + {% for link in links %} + <tr> + <td> + {{ link.link_id.link_uuid.uuid }} + </td> + <td> + {{ link.name }} + </td> + + <td> + <ul> + {% for endpoint in link.link_endpoint_ids %} + <li> + {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, (endpoint.endpoint_uuid.uuid, ''))[0] }} / + Device: + <a href="{{ url_for('device.detail', device_uuid=endpoint.device_id.device_uuid.uuid) }}"> + {{ device_names.get(endpoint.device_id.device_uuid.uuid, endpoint.device_id.device_uuid.uuid) }} + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16"> + <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/> + <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/> + </svg> + </a> + </li> + {% endfor %} + </ul> + </td> + + <td> + <a href="{{ url_for('optical_link.detail', link_uuid=link.link_id.link_uuid.uuid) }}"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16"> + <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/> + <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/> + </svg> + </a> + </td> + </tr> + {% endfor %} + {% else %} + <tr> + <td colspan="7">No links found</td> + </tr> + {% endif %} + </tbody> + </table> + + {% endblock %} \ No newline at end of file diff --git a/src/webui/service/templates/opticalconfig/home.html b/src/webui/service/templates/opticalconfig/home.html index c1253a7b5..349c25e36 100644 --- a/src/webui/service/templates/opticalconfig/home.html +++ b/src/webui/service/templates/opticalconfig/home.html @@ -1,18 +1,18 @@ <!-- - 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. ---> + 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. + --> {% extends 'base.html' %} diff --git a/test.py b/test.py index d27e15d38..f8e77b70b 100644 --- a/test.py +++ b/test.py @@ -1,10 +1,63 @@ from ncclient import manager from ncclient.xml_ import * import lxml.etree as ET +import re +from typing import Optional, Union +from uuid import UUID, uuid4, uuid5 +import logging + +NAMESPACE_TFS = UUID('200e3a1f-2223-534f-a100-758e29c37f40') + +print (uuid5(NAMESPACE_TFS, '1')) +def extract_roadm_ports (xml_data:str): + pattern = r'\bMG_ON_OPTICAL_PORT_WAVEBAND\b' + xml_bytes = xml_data.encode("utf-8") + root = ET.fromstring(xml_bytes) + with open('xml.log', 'w') as f: + print(xml_bytes, file=f) + + + namespace = {'oc': 'http://openconfig.net/yang/platform'} + ports = [] + components = root.findall('.//oc:component',namespace) + print(f"component {components}") + + + for component in components: + + properties = component.find(".//oc:properties",namespace) + + if (properties is not None): + for property in properties : + value = property.find(".//oc:value",namespace) + + if (re.search(pattern,value.text)): + name_element= component.find(".//oc:name",namespace) + print (f"name {name_element.text}") + + + +def extract_ports_based_on_type (xml_data:str): + pattern = r':\s*PORT\b' + + xml_bytes = xml_data.encode("utf-8") + root = ET.fromstring(xml_bytes) + + namespace = {'oc': 'http://openconfig.net/yang/platform', 'typex': 'http://openconfig.net/yang/platform-types'} + ports = [] + components = root.findall(".//oc:state[oc:type]",namespace) + for component in components: + type_ele = component.find(".//oc:type",namespace) + match = re.search(pattern, type_ele.text) + if match is not None : + name= component.find(".//oc:name",namespace) + print(name.text) + print("/////////////") + device = { - 'host': '10.0.2.10', # IP address or hostname of the remote machine - 'port': 2023, # SSH port (default: 22) + 'host': '10.0.2.4', # IP address or hostname of the remote machine + 'port': 2025, # SSH port (default: 22) 'username': 'admin', # SSH username 'password': 'admin', # SSH password 'device_params': {'name': 'default'}, @@ -12,6 +65,8 @@ device = { "allow_agent":False ,"look_for_keys":False } + + def extract_value (xml_data): xml_bytes = xml_data.encode("utf-8") root = ET.fromstring(xml_bytes) @@ -28,14 +83,15 @@ def extract_value (xml_data): else: print(" element not found.") - -with manager.connect(**device) as m: - # Perform operations on the remote machine using the 'm' object - # For example, you can retrieve the running configuration: - #result =m.edit_config(target='running',config=edit_config) - running_config = m.get_config('running').data_xml - - - - extract_value(running_config) +def main () : + with manager.connect(**device) as m: + # Perform operations on the remote machine using the 'm' object + # For example, you can retrieve the running configuration: + #result =m.edit_config(target='running',config=edit_config) + running_config = m.get_config('running').data_xml + + #extract_roadm_ports(running_config) + x,y= [1,3] + print (x) + -- GitLab