diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 095e542dfa8c5eca947a2931e6a9348aef70d838..1415782872cbc7726a9f7a3c182cabe4803ab6f9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -31,11 +31,11 @@ include: - local: '/src/dbscanserving/.gitlab-ci.yml' - local: '/src/opticalattackmitigator/.gitlab-ci.yml' - local: '/src/opticalattackdetector/.gitlab-ci.yml' - # - local: '/src/opticalattackmanager/.gitlab-ci.yml' + #- local: '/src/opticalattackmanager/.gitlab-ci.yml' - local: '/src/ztp/.gitlab-ci.yml' - local: '/src/policy/.gitlab-ci.yml' - local: '/src/forecaster/.gitlab-ci.yml' - - local: '/src/webui/.gitlab-ci.yml' + #- local: '/src/webui/.gitlab-ci.yml' #- local: '/src/l3_distributedattackdetector/.gitlab-ci.yml' #- local: '/src/l3_centralizedattackdetector/.gitlab-ci.yml' #- local: '/src/l3_attackmitigator/.gitlab-ci.yml' diff --git a/deploy/tfs.sh b/deploy/tfs.sh index 3a01606ce32369d0f0968282569eaf4ed59d778c..19c0d75a095bc5dc239d1d95237378bcf2fbb8da 100755 --- a/deploy/tfs.sh +++ b/deploy/tfs.sh @@ -364,7 +364,7 @@ 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=300s deployment/${COMPONENT_OBJNAME}service + --for='condition=available' --timeout=90s deployment/${COMPONENT_OBJNAME}service printf "\n" done diff --git a/manifests/opticalcontrollerservice.yaml b/manifests/opticalcontrollerservice.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4b677ee4f7287b0790aaa0b19f034db03978fac0 --- /dev/null +++ b/manifests/opticalcontrollerservice.yaml @@ -0,0 +1,72 @@ +# 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. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: opticalcontrollerservice +spec: + selector: + matchLabels: + app: opticalcontrollerservice + replicas: 1 + template: + metadata: + labels: + app: opticalcontrollerservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: localhost:32000/tfs/opticalcontroller:dev + imagePullPolicy: Never + ports: + - containerPort: 10060 + - containerPort: 9192 + env: + - name: LOG_LEVEL + value: "INFO" + #readinessProbe: + # exec: + # command: ["/bin/grpc_health_probe", "-addr=:10060"] + #livenessProbe: + # exec: + # command: ["/bin/grpc_health_probe", "-addr=:10060"] + resources: + requests: + cpu: 500m + memory: 128Mi + limits: + cpu: 1000m + memory: 1024Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: opticalcontrollerservice + labels: + app: opticalcontrollerservice +spec: + type: ClusterIP + selector: + app: opticalcontrollerservice + ports: + - name: grpc + protocol: TCP + port: 10060 + targetPort: 10060 + - name: metrics + protocol: TCP + port: 9192 + targetPort: 9192 diff --git a/my_deploy.sh b/my_deploy.sh index 0c5ba03c5b9f63038a622f44ab2dfaaf1e7e6ada..7dd5e5c3ee13cbce2b701b5b4e703823dfb2c28f 100755 --- a/my_deploy.sh +++ b/my_deploy.sh @@ -25,9 +25,12 @@ export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_gene # Uncomment to activate Monitoring #export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" -# Uncomment to activate bgpls_speaker +# Uncomment to activate BGP-LS Speaker #export TFS_COMPONENTS="${TFS_COMPONENTS} bgpls_speaker" +# Uncomment to activate Optical Controller +#export TFS_COMPONENTS="${TFS_COMPONENTS} opticalcontroller" + # Uncomment to activate ZTP #export TFS_COMPONENTS="${TFS_COMPONENTS} ztp" diff --git a/ofc24 b/ofc24 new file mode 120000 index 0000000000000000000000000000000000000000..baae92c8e249f4abfbbcf9739c9162087fefbacd --- /dev/null +++ b/ofc24 @@ -0,0 +1 @@ +src/tests/ofc24/ \ No newline at end of file diff --git a/proto/context.proto b/proto/context.proto index 1f8b0ce194b3ca04c162b7feb0548cdc4d9bc965..472d55975a925d7760d57ff93f2ac24fd6437c54 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -74,6 +74,16 @@ service ContextService { rpc SetConnection (Connection ) returns ( ConnectionId ) {} rpc RemoveConnection (ConnectionId ) returns ( Empty ) {} rpc GetConnectionEvents(Empty ) returns (stream ConnectionEvent ) {} + + + // ------------------------------ Experimental ----------------------------- + rpc GetOpticalConfig (Empty ) returns (OpticalConfigList ) {} + rpc SetOpticalConfig (OpticalConfig ) returns (OpticalConfigId ) {} + rpc SelectOpticalConfig(OpticalConfigId) returns (OpticalConfig ) {} + + rpc SetOpticalLink (OpticalLink ) returns (Empty ) {} + rpc GetOpticalLink (OpticalLinkId ) returns (OpticalLink ) {} + rpc GetFiber (FiberId ) returns (Fiber ) {} } // ----- Generic ------------------------------------------------------------------------------------------------------- @@ -203,6 +213,7 @@ enum DeviceDriverEnum { DEVICEDRIVER_GNMI_OPENCONFIG = 8; DEVICEDRIVER_FLEXSCALE = 9; DEVICEDRIVER_IETF_ACTN = 10; + DEVICEDRIVER_OC = 11; } enum DeviceOperationalStatusEnum { @@ -288,6 +299,7 @@ enum ServiceTypeEnum { SERVICETYPE_TAPI_CONNECTIVITY_SERVICE = 3; SERVICETYPE_TE = 4; SERVICETYPE_E2E = 5; + SERVICETYPE_OPTICAL_CONNECTIVITY = 6; } enum ServiceStatusEnum { @@ -613,3 +625,53 @@ message AuthenticationResult { ContextId context_id = 1; bool authenticated = 2; } + +// ---------------- Experimental ------------------------ +message OpticalConfigId { + string opticalconfig_uuid = 1; +} +message OpticalConfig { + OpticalConfigId opticalconfig_id = 1; + string config = 2; +} + +message OpticalConfigList { + repeated OpticalConfig opticalconfigs = 1; +} + +// ---- Optical Link ---- + +message OpticalLinkId { + Uuid optical_link_uuid = 1; +} + +message FiberId { + Uuid fiber_uuid = 1; +} + +message Fiber { + string ID = 10; + string src_port = 1; + string dst_port = 2; + string local_peer_port = 3; + string remote_peer_port = 4; + repeated int32 c_slots = 5; + repeated int32 l_slots = 6; + repeated int32 s_slots = 7; + float length = 8; + bool used = 9; + FiberId fiber_uuid = 11; + +} +message OpticalLinkDetails { + float length = 1; + string source = 2; + string target = 3; + repeated Fiber fibers = 4; +} + +message OpticalLink { + string name = 1; + OpticalLinkDetails details = 2; + OpticalLinkId optical_link_uuid = 3; +} diff --git a/proto/openconfig_device.proto b/proto/openconfig_device.proto new file mode 100644 index 0000000000000000000000000000000000000000..913ac247eaab89efb7d6de9f64b2730378937738 --- /dev/null +++ b/proto/openconfig_device.proto @@ -0,0 +1,23 @@ +// Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; +package openconfig_device; + +import "context.proto"; + +service OpenConfigService { + rpc AddOpenConfigDevice (context.OpticalConfig) returns (context.OpticalConfigId) {} + rpc ConfigureOpticalDevice(context.OpticalConfig) returns (context.Empty ) {} +} diff --git a/scripts/run_tests_locally-optical-attack-detector.sh b/scripts/run_tests_locally-optical-attack-detector.sh new file mode 100755 index 0000000000000000000000000000000000000000..e34c62b5665677c3040900abee6f95f0fb20233c --- /dev/null +++ b/scripts/run_tests_locally-optical-attack-detector.sh @@ -0,0 +1,102 @@ +#!/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. + + +PROJECTDIR=`pwd` +RCFILE=$PROJECTDIR/coverage/.coveragerc +COVERAGEFILE=$PROJECTDIR/coverage/.coverage + +# Destroy old coverage file and configure the correct folder on the .coveragerc file +rm -f $COVERAGEFILE +cat $PROJECTDIR/coverage/.coveragerc.template | sed s+~/tfs-ctrl+$PROJECTDIR+g > $RCFILE + +echo +echo "Pre-test clean-up:" +echo "------------------" +docker rm -f redis opticalattackdetector dbscanserving +docker network rm tfs_br + +echo +echo "Pull Docker images:" +echo "-------------------" +docker pull redis:7.0-alpine + +echo +echo "Build optical attack detector:" +echo "------------------------------" +docker build -t "opticalattackdetector:latest" -f ./src/opticalattackdetector/Dockerfile . +docker images --filter="dangling=true" --quiet | xargs -r docker rmi + +echo +echo "Build dbscan serving:" +echo "---------------------" +docker build -t "dbscanserving:latest" -f ./src/dbscanserving/Dockerfile . +docker images --filter="dangling=true" --quiet | xargs -r docker rmi + +echo +echo "Create test environment:" +echo "------------------------" +export REDIS_PASSWORD=$(uuidgen) +docker network create -d bridge --subnet=172.254.254.0/24 --gateway=172.254.254.1 --ip-range=172.254.254.0/24 tfs_br + +docker run --name redis -d --network=tfs_br -p 16379:6379 --rm \ + --env REDIS_PASSWORD=${REDIS_PASSWORD} \ + redis:7.0-alpine redis-server --requirepass ${REDIS_PASSWORD} + +docker run --name dbscanserving -d --network=tfs_br -p 10008:10008 --rm \ + --env LOG_LEVEL=DEBUG \ + dbscanserving:latest "python -m dbscanserving.service" + +echo +echo "Waiting for initialization..." +echo "-----------------------------" +while ! docker logs redis 2>&1 | grep -q 'Ready to accept connections'; do sleep 1; done +docker logs redis +#while ! docker logs dbscanserving 2>&1 | grep -q 'Server is ready'; do sleep 1; done +docker logs dbscanserving +#sleep 10 +docker ps -a + +echo +echo "Run unitary tests and analyze code coverage:" +echo "--------------------------------------------" +export REDIS_ADDRESS=$(docker inspect redis --format "{{.NetworkSettings.Networks.tfs_br.IPAddress}}") +export DBSCANSERVING_ADDRESS=$(docker inspect dbscanserving --format "{{.NetworkSettings.Networks.tfs_br.IPAddress}}") +docker run --name opticalattackdetector -d --network=tfs_br -p 10006:10006 --rm \ + --env REDIS_PASSWORD=${REDIS_PASSWORD} \ + --env DBSCANSERVINGSERVICE_SERVICE_HOST=${DBSCANSERVING_ADDRESS} \ + --env CACHINGSERVICE_SERVICE_HOST=${REDIS_ADDRESS} \ + opticalattackdetector:latest + +sleep 5 +docker ps -a +docker logs opticalattackdetector +docker exec -i opticalattackdetector bash -c "coverage run -m pytest --log-level=DEBUG --verbose opticalattackdetector/tests/test_unitary.py" +docker logs redis +docker logs dbscanserving +docker logs opticalattackdetector + +echo +echo "Coverage report:" +echo "----------------" +docker exec -i opticalattackdetector bash -c "coverage report --include='opticalattackdetector/*' --sort cover --show-missing --skip-covered" + +echo +echo "Post-test clean-up:" +echo "-------------------" +docker rm -f redis opticalattackdetector dbscanserving +docker network rm tfs_br + +echo "Done!" diff --git a/scripts/show_logs_opticalcontroller.sh b/scripts/show_logs_opticalcontroller.sh new file mode 100755 index 0000000000000000000000000000000000000000..17af5483c59e4d97a5534b388d006f5be00030e5 --- /dev/null +++ b/scripts/show_logs_opticalcontroller.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +######################################################################################################################## +# Define your deployment settings here +######################################################################################################################## + +# If not already set, set the name of the Kubernetes namespace to deploy to. +export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"} + +######################################################################################################################## +# Automated steps start here +######################################################################################################################## + +kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/opticalcontrollerservice -c server diff --git a/src/bgpls_speaker/.gitlab-ci.yml b/src/bgpls_speaker/.gitlab-ci.yml index 68b04f8e7d12812c3d19a269a00d5337874d7762..5020256266cf4f84b280985844f24dabad35c39c 100644 --- a/src/bgpls_speaker/.gitlab-ci.yml +++ b/src/bgpls_speaker/.gitlab-ci.yml @@ -38,45 +38,45 @@ build bgpls_speaker: - manifests/${IMAGE_NAME}service.yaml - .gitlab-ci.yml -# Apply unit test to the component -unit_test bgpls_speaker: - variables: - IMAGE_NAME: 'bgpls_speaker' # name of the microservice - IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) - stage: unit_test - needs: - - build bgpls_speaker - before_script: - - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - - if docker network list | grep teraflowbridge; then echo "teraflowbridge is already created"; else docker network create --driver=bridge teraflowbridge; fi - - if docker container ls | grep $IMAGE_NAME; then docker rm -f $IMAGE_NAME; else echo "$IMAGE_NAME image is not in the system"; fi - script: - - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" - - docker run --name $IMAGE_NAME -d -p 20030:20030 -v "$PWD/src/$IMAGE_NAME/tests:/opt/results" --network=teraflowbridge $CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG - - sleep 5 - - docker ps -a - - docker logs $IMAGE_NAME - - docker exec -i $IMAGE_NAME bash -c "coverage run -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary.py --junitxml=/opt/results/${IMAGE_NAME}_report.xml" - - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing" - coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' - after_script: - - docker rm -f $IMAGE_NAME - - docker network rm teraflowbridge - rules: - - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' - - changes: - - src/common/**/*.py - - proto/*.proto - - src/$IMAGE_NAME/**/*.{py,in,yml} - - src/$IMAGE_NAME/Dockerfile - - src/$IMAGE_NAME/tests/*.py - - manifests/${IMAGE_NAME}service.yaml - - .gitlab-ci.yml - artifacts: - when: always - reports: - junit: src/$IMAGE_NAME/tests/${IMAGE_NAME}_report.xml +## Apply unit test to the component +#unit_test bgpls_speaker: +# variables: +# IMAGE_NAME: 'bgpls_speaker' # name of the microservice +# IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) +# stage: unit_test +# needs: +# - build bgpls_speaker +# before_script: +# - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY +# - if docker network list | grep teraflowbridge; then echo "teraflowbridge is already created"; else docker network create --driver=bridge teraflowbridge; fi +# - if docker container ls | grep $IMAGE_NAME; then docker rm -f $IMAGE_NAME; else echo "$IMAGE_NAME image is not in the system"; fi +# script: +# - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" +# - docker run --name $IMAGE_NAME -d -p 20030:20030 -v "$PWD/src/$IMAGE_NAME/tests:/opt/results" --network=teraflowbridge $CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG +# - sleep 5 +# - docker ps -a +# - docker logs $IMAGE_NAME +# - docker exec -i $IMAGE_NAME bash -c "coverage run -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary.py --junitxml=/opt/results/${IMAGE_NAME}_report.xml" +# - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing" +# coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' +# after_script: +# - docker rm -f $IMAGE_NAME +# - docker network rm teraflowbridge +# rules: +# - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' +# - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' +# - changes: +# - src/common/**/*.py +# - proto/*.proto +# - src/$IMAGE_NAME/**/*.{py,in,yml} +# - src/$IMAGE_NAME/Dockerfile +# - src/$IMAGE_NAME/tests/*.py +# - manifests/${IMAGE_NAME}service.yaml +# - .gitlab-ci.yml +# artifacts: +# when: always +# reports: +# junit: src/$IMAGE_NAME/tests/${IMAGE_NAME}_report.xml ## Deployment of the service in Kubernetes Cluster #deploy bgpls_speaker: diff --git a/src/bgpls_speaker/service/BgplsServiceServicerImpl.py b/src/bgpls_speaker/service/BgplsServiceServicerImpl.py index 79862ee3b1204af105c5bd75c233f80ff3a9cf00..6fa9a8b8049e782b60ee700990a742e702d8942d 100644 --- a/src/bgpls_speaker/service/BgplsServiceServicerImpl.py +++ b/src/bgpls_speaker/service/BgplsServiceServicerImpl.py @@ -14,7 +14,7 @@ import grpc, json, logging from typing import List, Tuple, Union -from bgpls_speaker.service.tools.DiscoveredDBManager import DiscoveredDBManager, GetContextDevices +from bgpls_speaker.service.tools.DiscoveredDBManager import DiscoveredDBManager, GetContextDevices, getEndpointFromIpInterface from bgpls_speaker.service.tools.GrpcServer import GrpcServer from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method from common.proto.context_pb2 import DeviceId, Empty, EndPointId, Link, LinkId, Uuid @@ -25,19 +25,6 @@ from common.proto.bgpls_pb2 import ( ) from common.proto.bgpls_pb2_grpc import BgplsServiceServicer -def json_to_list(json_str : str) -> List[Union[str, Tuple[str, str]]]: - try: - data = json.loads(json_str) - except: # pylint: disable=bare-except - return [('item', str(json_str))] - - if isinstance(data, dict): - return [('kv', (key, value)) for key, value in data.items()] - elif isinstance(data, list): - return [('item', ', '.join(data))] - else: - return [('item', str(data))] - LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Service', 'RPC') @@ -121,12 +108,14 @@ class BgplsServiceServicerImpl(BgplsServiceServicer): """ When a node is added to context via bgpls module this function checks if there are other nodes in the topology connected by links discovered via bgpls. Then, if the link exist adds it to the context. - TODO: get endpoints from pce module """ node_name=request.nodeName node_igp=self.discoveredDB.GetIgpIdFromNodeName(node_name) - LOGGER.debug("(NotifyAddNodeToContext) Find links to nodes ") - nodes_conected=self.discoveredDB.FindConnectedNodes(node_igp) + LOGGER.debug("(NotifyAddNodeToContext) Find links to nodes %s:%s",node_name,node_igp) + # Get nodes connected and links were the igpID appears + nodes_conected, links_local, links_remote=self.discoveredDB.FindConnectedNodes(node_igp) + o=[LOGGER.debug("(NotifyAddNodeToContext) Links local: %s %s",link_local.local_id, link_local.remote_id) for link_local in links_local] + o=[LOGGER.debug("(NotifyAddNodeToContext) Links remote: %s %s",links_remote.local_id,links_remote.remote_id) for links_remote in links_remote] # Check if nodes are in context context_client=ContextClient() context_client.connect() @@ -138,55 +127,52 @@ class BgplsServiceServicerImpl(BgplsServiceServicer): LOGGER.debug("(NotifyAddNodeToContext) nodes_conected_in_context: %s", nodes_conected_in_context) # TODO: next to function for remote_node in nodes_conected_in_context: - - # TODO: get endpoints connected to remote ip (pce¿) - end_point1="eth-1/0/20" - end_point2="eth-1/0/20" - end_point_uuid1=Uuid(uuid=end_point1) - end_point_uuid2=Uuid(uuid=end_point2) - - link_name_src_dest=node_name+"/"+end_point1+"=="+remote_node+"/"+end_point2 + LOGGER.info("(NotifyAddNodeToContext) creating link to...: %s", remote_node) + remote_igp=self.discoveredDB.GetIgpIdFromNodeName(remote_node) + # Get source device from name device_uuid_src=DeviceId(device_uuid=Uuid(uuid=node_name)) device_src=context_client.GetDevice(device_uuid_src) - link_name_dest_src=remote_node+"/"+end_point2+"=="+node_name+"/"+end_point1 + # Get destination device from name device_uuid_dest=DeviceId(device_uuid=Uuid(uuid=remote_node)) device_dest=context_client.GetDevice(device_uuid_dest) - - self.getEndpointFromIpInterface(device_src,link.local_ipv4_id) - self.getEndpointFromIpInterface(device_dest,link.remote_ipv4_id) - # LOGGER.debug("(NotifyAddNodeToContext) Source: %s Destination: %s", device_src,device_dest) - - end_point_id1=EndPointId(endpoint_uuid=end_point_uuid1,device_id=device_uuid_src) - end_point_id2=EndPointId(endpoint_uuid=end_point_uuid2,device_id=device_uuid_dest) - - end_point_ids_src_dest=[end_point_id1,end_point_id2] - end_point_ids_dest_src=[end_point_id2,end_point_id1] - - link_id_src=context_client.SetLink(Link(link_id=LinkId(link_uuid=Uuid(uuid=link_name_src_dest)), - link_endpoint_ids=end_point_ids_src_dest)) - link_id_dst=context_client.SetLink(Link(link_id=LinkId(link_uuid=Uuid(uuid=link_name_dest_src)), - link_endpoint_ids=end_point_ids_dest_src)) + # Here I assume one link will always have same link in other direction + # First direction for link + # Get endpoints associated to link between devices + for link_local in links_local: + LOGGER.debug("(NotifyAddNodeToContext) local: %s %s", link_local.local_id,link_local.remote_id) + LOGGER.debug("(NotifyAddNodeToContext) matches: %s %s", node_igp,remote_igp) + if link_local.local_id == node_igp and link_local.remote_id == remote_igp: + LOGGER.debug("(NotifyAddNodeToContext) local_ipv4_id: %s", link_local.local_ipv4_id) + end_point1,ip_1=getEndpointFromIpInterface(device_src,link_local.local_ipv4_id) + LOGGER.debug("(NotifyAddNodeToContext) end_point1: %s", end_point1) + + LOGGER.debug("(NotifyAddNodeToContext) remote_ipv4_id: %s", link_local.remote_ipv4_id) + end_point2,ip_2=getEndpointFromIpInterface(device_dest,link_local.remote_ipv4_id) + LOGGER.debug("(NotifyAddNodeToContext) end_point2: %s", end_point2) + # LOGGER.debug("(NotifyAddNodeToContext) Source: %s Destination: %s", end_point1,end_point2) + + link_name_src_dest=node_name+"/"+end_point1+"=="+remote_node+"/"+end_point2 + + end_point_uuid1=Uuid(uuid=end_point1) + end_point_uuid2=Uuid(uuid=end_point2) + + end_point_id1=EndPointId(endpoint_uuid=end_point_uuid1,device_id=device_uuid_src) + + link_name_dest_src=remote_node+"/"+end_point2+"=="+node_name+"/"+end_point1 + + end_point_id2=EndPointId(endpoint_uuid=end_point_uuid2,device_id=device_uuid_dest) + + end_point_ids_src_dest=[end_point_id1,end_point_id2] + end_point_ids_dest_src=[end_point_id2,end_point_id1] + + link_id_src=context_client.SetLink(Link(link_id=LinkId(link_uuid=Uuid(uuid=link_name_src_dest)), + link_endpoint_ids=end_point_ids_src_dest)) + + link_id_dst=context_client.SetLink(Link(link_id=LinkId(link_uuid=Uuid(uuid=link_name_dest_src)), + link_endpoint_ids=end_point_ids_dest_src)) LOGGER.debug("(NotifyAddNodeToContext) Link set id src--->dst: %s", link_id_src) context_client.close() return Empty() - - def getEndpointFromIpInterface(self,device,ipv4): - """ - Get TFS endpoint from interface IPv4. - """ - for config in device.device_config.config_rules: - if config.WhichOneof('config_rule') == 'custom': - for item_type, item in json_to_list(config.custom.resource_value): - if item_type == 'kv': - # LOGGER.debug("(getEndpointFromIpInterface) item: %s",item) - endpoint=item - LOGGER.debug("(getEndpointFromIpInterface) config: %s",config.custom.resource_key) - if "/interface" in config.custom.resource_key: - interface=config.custom.resource_key.split("/interface")[1].strip("[]") - LOGGER.debug("(getEndpointFromIpInterface) interface: %s",interface) - if ipv4 in config.custom.resource_value: - LOGGER.debug("(getEndpointFromIpInterface) value: %s",config.custom.resource_value) - return endpoint \ No newline at end of file diff --git a/src/bgpls_speaker/service/java/netphony-topology/src/main/java/eu/teraflow/tid/bgp4Peer/grpc/grpcClient.java b/src/bgpls_speaker/service/java/netphony-topology/src/main/java/eu/teraflow/tid/bgp4Peer/grpc/grpcClient.java index fb1d2354368099c76e69aafab03407295ca2faa2..6e74dff00a565edd4197734483f3ca036f939c27 100644 --- a/src/bgpls_speaker/service/java/netphony-topology/src/main/java/eu/teraflow/tid/bgp4Peer/grpc/grpcClient.java +++ b/src/bgpls_speaker/service/java/netphony-topology/src/main/java/eu/teraflow/tid/bgp4Peer/grpc/grpcClient.java @@ -97,16 +97,16 @@ public class grpcClient { strIgpL=link.getLocalNodeIGPId().toString(); } String ipv4R; - if(link.getiPv4RouterIDNeighborNodeLATLV()==null) + if(link.getiPv4RouterIDLocalNodeLATLV()==null) ipv4R="-"; else { - ipv4R=link.getiPv4RouterIDNeighborNodeLATLV(); + ipv4R=link.getiPv4RouterIDLocalNodeLATLV(); } String ipv4L; - if(link.getiPv4RouterIDLocalNodeLATLV()==null) + if(link.getiPv4RouterIDNeighborNodeLATLV()==null) ipv4L="-"; else { - ipv4L=link.getiPv4RouterIDLocalNodeLATLV(); + ipv4L=link.getiPv4RouterIDNeighborNodeLATLV(); } // Build link for grpc message. need non null values in some cases diff --git a/src/bgpls_speaker/service/tools/DiscoveredDBManager.py b/src/bgpls_speaker/service/tools/DiscoveredDBManager.py index ecd46347f729cd569999abd910e53825b550f69d..6ca318305a1b625e5de100b958ee0f2f50df8ddb 100644 --- a/src/bgpls_speaker/service/tools/DiscoveredDBManager.py +++ b/src/bgpls_speaker/service/tools/DiscoveredDBManager.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import List +from typing import List, Tuple, Union from bgpls_speaker.service.tools.Tools import UpdateRequest,NodeInfo,LinkInfo from common.proto.bgpls_pb2 import NodeDescriptors from common.proto.context_pb2 import ContextId, ContextList,Topology,TopologyId,Device,DeviceDriverEnum,ContextId,Empty, TopologyList @@ -20,9 +20,22 @@ from common.Constants import DEFAULT_CONTEXT_NAME from common.tools.object_factory.Context import json_context_id from context.client.ContextClient import ContextClient -import logging +import logging,json LOGGER = logging.getLogger(__name__) +def json_to_list(json_str : str) -> List[Union[str, Tuple[str, str]]]: + try: + data = json.loads(json_str) + except: # pylint: disable=bare-except + return [('item', str(json_str))] + + if isinstance(data, dict): + return [('kv', (key, value)) for key, value in data.items()] + elif isinstance(data, list): + return [('item', ', '.join(data))] + else: + return [('item', str(data))] + class DiscoveredDBManager: def __init__(self): self.discoveredDB=[] @@ -37,15 +50,16 @@ class DiscoveredDBManager: # Check if node info message if(self.checkIfNodeInUpdate(update_request)): # Check if node exists - to_add=True + node_count=len(update_request.nodes) for node in update_request.nodes: if(self.CheckIfNodeNameInDb(node) or CheckIfNodeInContext(node.node_name)): # Replace info from node if exists LOGGER.debug("(AddToDB) Node already in DB!!!") - to_add=False + update_request.nodes.remove(node) + node_count=node_count-1 else: LOGGER.debug("(AddToDB) Node NOT in DB!!!") - if(to_add): + if(node_count>0): self.discoveredDB.append(update_request) else: # is a link @@ -127,7 +141,9 @@ class DiscoveredDBManager: Return the IGP ID given a node name if exists in the discoveredDB. """ for update in self.discoveredDB: + LOGGER.debug("(GetIgpIdFromNodeName)checking update: %s",update.toString()) for node in update.nodes: + LOGGER.debug("(GetIgpIdFromNodeName)checking nodes: %s",node.node_name) if(node.node_name==name): return node.igp_id return None @@ -165,6 +181,8 @@ class DiscoveredDBManager: # find links where the node appears links_to_node=[] nodes_conected=[] + link_local=[] + link_remote=[] for update in self.discoveredDB: for link in update.links: LOGGER.debug("(FindConnectedNodes) link in up:%s %s", @@ -173,14 +191,16 @@ class DiscoveredDBManager: if(link.local_id == new_node): links_to_node.append(link) nodes_conected.append(link.remote.node_name) + link_local.append(link) if(link.remote_id == new_node): links_to_node.append(link) nodes_conected.append(link.local.node_name) + link_remote.append(link) if(nodes_conected): LOGGER.debug("(FindConnectedNodes) links to local node:%s",new_node) LOGGER.debug("(FindConnectedNodes) %s", nodes_conected) - return nodes_conected + return nodes_conected, link_local, link_remote LOGGER.debug("(FindConnectedNodes) NO LINKS TO OTHER NODES") return None @@ -263,3 +283,36 @@ def CheckIfNodeInContext(node_name) -> bool: return True LOGGER.info("(CheckIfNodeInContext) Node NOT in context") return False + +def getEndpointFromIpInterface(device,ipv4): + """ + Get TFS endpoint uuid drom given device having the IPv4 interface. + """ + for config in device.device_config.config_rules: + if config.WhichOneof('config_rule') == 'custom': + # for item_type, item in json_to_list(config.custom.resource_value): + # if item_type == 'kv': + # # LOGGER.debug("(getEndpointFromIpInterface) item: %s",item) + # endpoint_item=item + # LOGGER.debug("(getEndpointFromIpInterface) config: %s",config.custom.resource_key) + if "/interface" in config.custom.resource_key: + iface=config.custom.resource_key.split("/interface")[1].strip("[]") + LOGGER.debug("(getEndpointFromIpInterface) interface: %s",iface) + if ipv4 in config.custom.resource_value: + LOGGER.debug("(getEndpointFromIpInterface) value: %s",config.custom.resource_value) + resource_dict=json.loads(config.custom.resource_value) + interface = resource_dict['name'] + resource_ip=resource_dict['address_ip'] + # Search for endpoint uuid assigned to interface + for config in device.device_config.config_rules: + if config.WhichOneof('config_rule') == 'custom': + if "/endpoints/endpoint" in config.custom.resource_key: + key=config.custom.resource_key.split("/endpoints/endpoint")[1].strip("[]") + LOGGER.debug("(getEndpointFromIpInterface) key: %s",key) + if interface in key: + LOGGER.debug("(getEndpointFromIpInterface) value: %s",config.custom.resource_value) + endpoint=config.custom.resource_key.split("/endpoints/endpoint")[1].strip("[]") + resource_dict_endpoint=json.loads(config.custom.resource_value) + return resource_dict_endpoint['uuid'],resource_ip + + return None,ipv4 \ No newline at end of file diff --git a/src/bgpls_speaker/service/tools/Tools.py b/src/bgpls_speaker/service/tools/Tools.py index adf7dcb44d777c2a06e32f69493c2e8d5a4972f5..4d47110b1f161caa11459c687e61e79b1c140ca7 100644 --- a/src/bgpls_speaker/service/tools/Tools.py +++ b/src/bgpls_speaker/service/tools/Tools.py @@ -47,12 +47,13 @@ class UpdateRequest: ) def toString(self): # Debug purposes - out = "" + out = " " out+=self.address_family_id out+=self.next_hop out+=self.as_path_segment for node in self.nodes: + out+="name" out+=node.node_name out+=node.igp_id out+=str(node.bgpls_id) @@ -84,7 +85,15 @@ class NodeInfo: self.bgpls_id = bgpls_id.strip("/") self.as_id = as_id self.learnt_from=learnt_from - + def toString(self): + # Debug purposes + out = "name" + out+=self.node_name + out+=self.igp_id + out+=str(self.bgpls_id) + out+=str(self.as_id) + out+=self.learnt_from + @classmethod def from_proto(cls, proto_node): return cls( diff --git a/src/common/Constants.py b/src/common/Constants.py index c7ba01f69978fd3c601dcfe30180015d524b1100..a1913a951aeaa968a594fc3bafcb49581459a0e0 100644 --- a/src/common/Constants.py +++ b/src/common/Constants.py @@ -59,6 +59,7 @@ class ServiceNameEnum(Enum): TE = 'te' FORECASTER = 'forecaster' E2EORCHESTRATOR = 'e2eorchestrator' + OPTICALCONTROLLER = 'opticalcontroller' BGPLS = 'bgpls-speaker' # Used for test and debugging only @@ -87,6 +88,7 @@ DEFAULT_SERVICE_GRPC_PORTS = { ServiceNameEnum.TE .value : 10030, ServiceNameEnum.FORECASTER .value : 10040, ServiceNameEnum.E2EORCHESTRATOR .value : 10050, + ServiceNameEnum.OPTICALCONTROLLER .value : 10060, ServiceNameEnum.BGPLS .value : 20030, # Used for test and debugging only diff --git a/src/common/tools/descriptor/Tools.py b/src/common/tools/descriptor/Tools.py index b4a76ff4f00d0f6886895cca0ab6f27f7aa8aa43..e95fc756052bf792f0009518b19991b8e87bac68 100644 --- a/src/common/tools/descriptor/Tools.py +++ b/src/common/tools/descriptor/Tools.py @@ -15,6 +15,7 @@ import copy, json from typing import Dict, List, Optional, Tuple, Union from common.DeviceTypes import DeviceTypeEnum +from common.proto.context_pb2 import DeviceDriverEnum def get_descriptors_add_contexts(contexts : List[Dict]) -> List[Dict]: contexts_add = copy.deepcopy(contexts) @@ -95,7 +96,8 @@ def split_devices_by_rules(devices : List[Dict]) -> Tuple[List[Dict], List[Dict] if len(connect_rules) > 0: device_add = copy.deepcopy(device) - device_add['device_endpoints'] = [] + if (device['device_drivers'][0] != DeviceDriverEnum.DEVICEDRIVER_OC): + device_add['device_endpoints'] = [] device_add['device_config'] = {'config_rules': connect_rules} devices_add.append(device_add) diff --git a/src/context/client/ContextClient.py b/src/context/client/ContextClient.py index 13d9dc0035b45845bf11367e02c8830b5151c1d6..48a635cccd19f5985721a6a737fb8a2e5bd260b2 100644 --- a/src/context/client/ContextClient.py +++ b/src/context/client/ContextClient.py @@ -26,7 +26,9 @@ from common.proto.context_pb2 import ( Link, LinkEvent, LinkId, LinkIdList, LinkList, Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, - Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList) + Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, + OpticalConfig, OpticalConfigId, OpticalConfigList +) from common.proto.context_pb2_grpc import ContextServiceStub from common.proto.context_policy_pb2_grpc import ContextPolicyServiceStub from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule @@ -436,3 +438,26 @@ class ContextClient: response = self.policy_stub.RemovePolicyRule(request) LOGGER.debug('RemovePolicyRule result: {:s}'.format(grpc_message_to_json_string(response))) return response + + #//////////////// Experimental ////////////////// + + @RETRY_DECORATOR + def SetOpticalConfig(self, request : OpticalConfig) -> OpticalConfigId: + LOGGER.debug('SetOpticalConfig request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.SetOpticalConfig(request) + LOGGER.debug('SetOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + @RETRY_DECORATOR + def GetOpticalConfig(self, request : Empty) -> OpticalConfigList: + LOGGER.debug('GetOpticalConfig request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.GetOpticalConfig(request) + LOGGER.debug('GetOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + @RETRY_DECORATOR + def SelectOpticalConfig(self,request : OpticalConfigId) -> OpticalConfigList: + LOGGER.debug('SelectOpticalConfig request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.SelectOpticalConfig(request) + LOGGER.debug('SelectOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response))) + return response diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py index 5aad7f9c9ff3a6fd063b1f364256e760f47e1c33..a102fa17629bd866d96883230a542a6e7a4d92ff 100644 --- a/src/context/service/ContextServiceServicerImpl.py +++ b/src/context/service/ContextServiceServicerImpl.py @@ -23,7 +23,9 @@ from common.proto.context_pb2 import ( Link, LinkEvent, LinkId, LinkIdList, LinkList, Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, - Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList) + Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, + OpticalConfigList, OpticalConfigId, OpticalConfig +) from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule from common.proto.context_pb2_grpc import ContextServiceServicer from common.proto.context_policy_pb2_grpc import ContextPolicyServiceServicer @@ -43,6 +45,7 @@ from .database.Slice import ( slice_delete, slice_get, slice_list_ids, slice_list_objs, slice_select, slice_set, slice_unset) from .database.Topology import ( topology_delete, topology_get, topology_get_details, topology_list_ids, topology_list_objs, topology_set) +from .database.OpticalConfig import set_opticalconfig, select_opticalconfig, get_opticalconfig LOGGER = logging.getLogger(__name__) @@ -296,3 +299,22 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def RemovePolicyRule(self, request : PolicyRuleId, context: grpc.ServicerContext) -> Empty: return policyrule_delete(self.db_engine, self.messagebroker, request) + + # ---------------------------- Experimental ------------------- + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def GetOpticalConfig(self, request : Empty, context : grpc.ServicerContext) -> OpticalConfigList: + result = get_opticalconfig(self.db_engine) + return OpticalConfigList(OpticalConfigs=result) + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def SetOpticalConfig(self, request : OpticalConfig, context : grpc.ServicerContext) -> OpticalConfigId: + result = set_opticalconfig(self.db_engine, request) + return OpticalConfigId(**result) + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def SelectOpticalConfig(self, request : OpticalConfigId, context : grpc.ServicerContext) -> OpticalConfig: + result = select_opticalconfig(self.db_engine, request) + optical_config_id = OpticalConfigId() + optical_config_id.CopyFrom(result.OpticalConfig_id) + return OpticalConfig(config=result.config, OpticalConfig_id=optical_config_id) diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py index 3aff20ade14532dcb7fbf8ec1033c084aaeead3c..7f58ddeb55c65a17f0deb286b69a7343b1ae234b 100644 --- a/src/context/service/database/Device.py +++ b/src/context/service/database/Device.py @@ -21,7 +21,9 @@ from typing import Dict, List, Optional, Set, Tuple from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException from common.message_broker.MessageBroker import MessageBroker from common.proto.context_pb2 import ( - Device, DeviceFilter, DeviceId, DeviceIdList, DeviceList, Empty, EventTypeEnum, TopologyId) + Device, DeviceDriverEnum, DeviceFilter, DeviceId, DeviceIdList, DeviceList, + Empty, EventTypeEnum, TopologyId +) from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.object_factory.Device import json_device_id from context.service.database.uuids.Topology import topology_get_uuid @@ -103,10 +105,12 @@ 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) + endpoints_data : List[Dict] = list() for i, endpoint in enumerate(request.device_endpoints): endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid - if len(endpoint_device_uuid) == 0: endpoint_device_uuid = device_uuid + if len(endpoint_device_uuid) == 0 or is_oc_driver : endpoint_device_uuid = device_uuid if endpoint_device_uuid not in {raw_device_uuid, device_uuid}: raise InvalidArgumentException( 'request.device_endpoints[{:d}].device_id.device_uuid.uuid'.format(i), endpoint_device_uuid, @@ -302,4 +306,4 @@ def device_select(db_engine : Engine, request : DeviceFilter) -> DeviceList: obj_list : List[DeviceModel] = query.filter(DeviceModel.device_uuid.in_(device_uuids)).all() return [obj.dump(**dump_params) for obj in obj_list] devices = run_transaction(sessionmaker(bind=db_engine), callback) - return DeviceList(devices=devices) \ No newline at end of file + return DeviceList(devices=devices) diff --git a/src/context/service/database/OpticalConfig.py b/src/context/service/database/OpticalConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..9e7552bc111e40245bb649d2eb1ffa910c6f8588 --- /dev/null +++ b/src/context/service/database/OpticalConfig.py @@ -0,0 +1,88 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json, logging +from sqlalchemy.dialects.postgresql import insert +from sqlalchemy.engine import Engine +from sqlalchemy.orm import Session, sessionmaker +from sqlalchemy_cockroachdb import run_transaction +from common.proto.context_pb2 import OpticalConfig, OpticalConfigId +from .models.OpticalConfigModel import OpticalConfigModel + +LOGGER = logging.getLogger(__name__) + +def get_opticalconfig(db_engine : Engine): + def callback(session:Session): + optical_configs = list() + results = session.query(OpticalConfigModel).all() + for obj in results: + optical_config = OpticalConfig() + optical_config.config = json.dump(obj.config) + optical_config.opticalconfig_id.opticalconfig_uuid = obj.opticalconfig_uuid + optical_configs.append(optical_config) + return optical_configs + obj = run_transaction(sessionmaker(bind=db_engine), callback) + return obj + +def set_opticalconfig(db_engine : Engine, request : OpticalConfig): + opticalconfig_id = OpticalConfigId() + opticalconfig_id.opticalconfig_uuid = request.opticalconfig_id.opticalconfig_uuid + my_config_data = [] + if request.config: + channels = [] + transceivers = [] + config = json.loads(request.config) + if 'channels' in config and len(config['channels']) > 0: + channels = [channel['name']['index'] for channel in config['channels']] + if 'transceivers' in config and len(config['transceivers']['transceiver']) > 0: + transceivers = [transceiver for transceiver in config['transceivers']['transceiver']] + + my_config_data = [ + { + "opticalconfig_uuid": request.opticalconfig_id.opticalconfig_uuid, + "channels" : channels, + "transcievers" : transceivers, + "interfaces" : json.dumps(config["interfaces"]["interface"]), + "channel_namespace" : config["channel_namespace"], + "endpoints" : [json.dumps(endpoint) for endpoint in config["endpoints"]], + "frequency" : config["frequency"] if "frequency" in config else 0, + "operational_mode" : config["operational_mode"] if "operational_mode" in config else 0, + "output_power" : config["output_power"] if "output_power" in config else '', + } + ] + + def callback(session:Session)->bool: + stmt = insert(OpticalConfigModel).values(my_config_data) + stmt = stmt.on_conflict_do_update( + index_elements=[OpticalConfigModel.opticalconfig_uuid], + set_=dict( + channel_namespace=stmt.excluded.channel_namespace + ) + ) + stmt = stmt.returning(OpticalConfigModel.opticalconfig_uuid) + id = session.execute(stmt).fetchone() + opticalconfig_id = run_transaction(sessionmaker(bind=db_engine), callback) + return {'opticalconfig_uuid': opticalconfig_id} + +def select_opticalconfig(db_engine:Engine,request:OpticalConfigId): + def callback(session : Session) -> OpticalConfig: + result = OpticalConfig() + stmt = session.query(OpticalConfigModel) + stmt = stmt.filter_by(opticalconfig_uuid=request.opticalconfig_uuid) + obj = stmt.first() + if obj is not None: + result.config = json.dumps(obj.dump()) + result.opticalconfig_id.opticalconfig_uuid = obj.opticalconfig_uuid + return result + return run_transaction(sessionmaker(bind=db_engine, expire_on_commit=False), callback) diff --git a/src/context/service/database/Service.py b/src/context/service/database/Service.py index fc196ddded291aa82c8f9df932c15611d13121e4..337bf592f785db97d5924aa7da17772c35eac1b2 100644 --- a/src/context/service/database/Service.py +++ b/src/context/service/database/Service.py @@ -20,7 +20,9 @@ from sqlalchemy.orm import Session, selectinload, sessionmaker from sqlalchemy_cockroachdb import run_transaction from typing import Dict, List, Optional, Set from common.proto.context_pb2 import ( - ContextId, Empty, EventTypeEnum, Service, ServiceFilter, ServiceId, ServiceIdList, ServiceList) + ContextId, Empty, EventTypeEnum, Service, ServiceFilter, ServiceId, ServiceIdList, + ServiceList, ServiceTypeEnum +) from common.message_broker.MessageBroker import MessageBroker from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException from common.tools.object_factory.Context import json_context_id @@ -84,6 +86,9 @@ def service_set(db_engine : Engine, messagebroker : MessageBroker, request : Ser context_uuid,service_uuid = service_get_uuid(request.service_id, service_name=service_name, allow_random=True) service_type = grpc_to_enum__service_type(request.service_type) + if service_type is None and request.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY: + service_type = "OPTICAL_CONNECTIVITY" + service_status = grpc_to_enum__service_status(request.service_status.service_status) now = datetime.datetime.utcnow() diff --git a/src/context/service/database/models/OpticalConfigModel.py b/src/context/service/database/models/OpticalConfigModel.py new file mode 100644 index 0000000000000000000000000000000000000000..10cf197f9a8a728b8fd02bdcdaf255677551bf17 --- /dev/null +++ b/src/context/service/database/models/OpticalConfigModel.py @@ -0,0 +1,42 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +from sqlalchemy import Column, String, Integer +from sqlalchemy.dialects.postgresql import ARRAY +from ._Base import _Base + +class OpticalConfigModel(_Base): + __tablename__ = 'optical_config' + opticalconfig_uuid = Column(String, primary_key=True) + channels = Column(ARRAY(String), nullable=True) + transcievers = Column(ARRAY(String), nullable=True) + interfaces = Column(String, nullable=True) + channel_namespace = Column(String, nullable=True) + endpoints = Column(ARRAY(String), nullable=True) + frequency = Column(Integer, nullable=True) + operational_mode = Column(Integer, nullable=True) + output_power = Column(String, nullable=True) + + def dump(self): + return { + "channels" : [{'name': {'index': channel}} for channel in self.channels], + "transceivers" : {"transceiver": [transciever for transciever in self.transcievers]}, + "interfaces" : {"interface": json.loads(self.interfaces)}, + "channel_namespace" : self.channel_namespace, + "endpoints" : [json.loads(endpoint) for endpoint in self.endpoints], + "frequency" : self.frequency, + "output_power" : self.output_power, + "operational_mode" : self.operational_mode, + } diff --git a/src/context/service/database/models/enums/DeviceDriver.py b/src/context/service/database/models/enums/DeviceDriver.py index 8e15bf058599eeed0629fc1249af0d052183db28..2ccdda2725a7f7bb13ba296d4eca25f88b1e73d1 100644 --- a/src/context/service/database/models/enums/DeviceDriver.py +++ b/src/context/service/database/models/enums/DeviceDriver.py @@ -33,6 +33,7 @@ class ORM_DeviceDriverEnum(enum.Enum): GNMI_OPENCONFIG = DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG FLEXSCALE = DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE IETF_ACTN = DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN + OC = DeviceDriverEnum.DEVICEDRIVER_OC grpc_to_enum__device_driver = functools.partial( grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum) diff --git a/src/context/service/database/models/enums/ServiceType.py b/src/context/service/database/models/enums/ServiceType.py index ce198f8c1f795f25da547e2d5974059062489709..01ed68c1708dc617a46edc31e94fc07d79e278e1 100644 --- a/src/context/service/database/models/enums/ServiceType.py +++ b/src/context/service/database/models/enums/ServiceType.py @@ -28,6 +28,7 @@ class ORM_ServiceTypeEnum(enum.Enum): TAPI_CONNECTIVITY_SERVICE = ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE TE = ServiceTypeEnum.SERVICETYPE_TE E2E = ServiceTypeEnum.SERVICETYPE_E2E + OPTICAL_CONNECTIVITY = ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY grpc_to_enum__service_type = functools.partial( grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum) diff --git a/src/context/service/database/models/enums/_GrpcToEnum.py b/src/context/service/database/models/enums/_GrpcToEnum.py index 0cde8ac5eebdb724d749b63663f30afd02435884..cc98a5f61bf360c0bcc86bc366da5f6ba4411741 100644 --- a/src/context/service/database/models/enums/_GrpcToEnum.py +++ b/src/context/service/database/models/enums/_GrpcToEnum.py @@ -14,16 +14,21 @@ import re from enum import Enum -from typing import Optional +from typing import Any, Optional # Enumeration classes are redundant with gRPC classes, but gRPC does not provide a programmatical method to retrieve # the values it expects from strings containing the desired value symbol or its integer value, so a kind of mapping is # required. Besides, ORM Models expect Enum classes in EnumeratedFields; we create specific and conveniently defined # Enum classes to serve both purposes. -def grpc_to_enum(grpc_enum_class, orm_enum_class : Enum, grpc_enum_value, grpc_enum_prefix : Optional[str] = None): +def grpc_to_enum( + grpc_enum_class, orm_enum_class : Enum, grpc_enum_value, grpc_enum_prefix : Optional[str] = None, + fail_if_not_found : bool = False +) -> Optional[Any]: enum_name = grpc_enum_class.Name(grpc_enum_value) + _orig_enum_name = enum_name + _orig_grpc_enum_prefix = grpc_enum_prefix if grpc_enum_prefix is None: grpc_enum_prefix = orm_enum_class.__name__.upper() #grpc_enum_prefix = re.sub(r'^ORM_(.+)$', r'\1', grpc_enum_prefix) @@ -35,4 +40,7 @@ def grpc_to_enum(grpc_enum_class, orm_enum_class : Enum, grpc_enum_value, grpc_e enum_name = enum_name.replace(grpc_enum_prefix, '') orm_enum_value = orm_enum_class._member_map_.get(enum_name) + if orm_enum_value is None and fail_if_not_found: + MSG = 'Unable to map gRPC Enum Value ({:s} / {:s}) to ORM Enum Value; grpc_enum_prefix={:s}' + raise Exception(MSG.format(str(grpc_enum_value), str(_orig_enum_name), str(_orig_grpc_enum_prefix))) return orm_enum_value diff --git a/src/device/Config.py b/src/device/Config.py index 1549d9811aa5d1c193a44ad45d0d7773236c0612..2e831a4054522db5206ad424483367a20be324b9 100644 --- a/src/device/Config.py +++ b/src/device/Config.py @@ -12,3 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. + +import os + +TRUE_VALUES = {'T', 'TRUE', 'YES', '1'} +DEVICE_EMULATED_ONLY = os.environ.get('DEVICE_EMULATED_ONLY') +LOAD_ALL_DEVICE_DRIVERS = (DEVICE_EMULATED_ONLY is None) or (DEVICE_EMULATED_ONLY.upper() not in TRUE_VALUES) diff --git a/src/device/client/DeviceClient.py b/src/device/client/DeviceClient.py index 32fa685b953232808acba273e7d30514922c04eb..3fde3df778e32df20c863ff110a1eb572f38d177 100644 --- a/src/device/client/DeviceClient.py +++ b/src/device/client/DeviceClient.py @@ -15,7 +15,7 @@ import grpc, logging from common.Constants import ServiceNameEnum from common.Settings import get_service_host, get_service_port_grpc -from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty, MyConfig, MyConfigId +from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty,OpticalConfig,OpticalConfigId from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceStub from common.tools.client.RetryDecorator import retry, delay_exponential @@ -82,8 +82,7 @@ class DeviceClient: response = self.stub.MonitorDeviceKpi(request) LOGGER.debug('MonitorDeviceKpi result: {:s}'.format(grpc_message_to_json_string(response))) return response - - def ConfigureOpticalDevice(self, request : MyConfig) -> MyConfigId: + def ConfigureOpticalDevice(self, request : OpticalConfig) -> OpticalConfigId: LOGGER.debug('ConfigureOpticalDevice request: {:s}'.format(grpc_message_to_json_string(request))) response = self.openconfig_stub.ConfigureOpticalDevice(request) LOGGER.debug('ConfigureOpticalDevice result: {:s}'.format(grpc_message_to_json_string(response))) diff --git a/src/device/service/DeviceService.py b/src/device/service/DeviceService.py index c7868e44579fb27b6eecc6806f64e3bb531d7cd4..0e1ce79f955607cceed2bb791e44ae547b5772f5 100644 --- a/src/device/service/DeviceService.py +++ b/src/device/service/DeviceService.py @@ -12,15 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os from common.Constants import ServiceNameEnum from common.Settings import get_service_port_grpc from common.proto.device_pb2_grpc import add_DeviceServiceServicer_to_server +from common.proto.openconfig_device_pb2_grpc import add_OpenConfigServiceServicer_to_server from common.tools.service.GenericGrpcService import GenericGrpcService +from device.Config import LOAD_ALL_DEVICE_DRIVERS from .driver_api.DriverInstanceCache import DriverInstanceCache from .DeviceServiceServicerImpl import DeviceServiceServicerImpl from .monitoring.MonitoringLoops import MonitoringLoops from .OpenConfigServicer import OpenConfigServicer -from common.proto.openconfig_device_pb2_grpc import add_OpenConfigServiceServicer_to_server # Custom gRPC settings # Multiple clients might keep connections alive waiting for RPC methods to be executed. @@ -33,12 +35,14 @@ class DeviceService(GenericGrpcService): super().__init__(port, max_workers=GRPC_MAX_WORKERS, cls_name=cls_name) self.monitoring_loops = MonitoringLoops() self.device_servicer = DeviceServiceServicerImpl(driver_instance_cache, self.monitoring_loops) - self.openconfig_device_servicer=OpenConfigServicer(driver_instance_cache,self.monitoring_loops) + if LOAD_ALL_DEVICE_DRIVERS: + self.openconfig_device_servicer = OpenConfigServicer(driver_instance_cache,self.monitoring_loops) def install_servicers(self): self.monitoring_loops.start() add_DeviceServiceServicer_to_server(self.device_servicer, self.server) - add_OpenConfigServiceServicer_to_server(self.openconfig_device_servicer,self.server) + if LOAD_ALL_DEVICE_DRIVERS: + add_OpenConfigServiceServicer_to_server(self.openconfig_device_servicer,self.server) def stop(self): super().stop() diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py index 7592e5b58f45d7745a045643f4669e4d957134f3..5e5d7540c0ffbc860ba912cbbcacc637b7d790c5 100644 --- a/src/device/service/DeviceServiceServicerImpl.py +++ b/src/device/service/DeviceServiceServicerImpl.py @@ -20,7 +20,8 @@ from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException from common.proto.context_pb2 import ( - Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link, MyConfig, MyConfigId + Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link, + OpticalConfig, OpticalConfigId ) from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer @@ -30,7 +31,6 @@ from context.client.ContextClient import ContextClient from .driver_api._Driver import _Driver from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver from .monitoring.MonitoringLoops import MonitoringLoops -from .drivers.oc_driver.OCDriver import OCDriver from .ErrorMessages import ERROR_MISSING_DRIVER, ERROR_MISSING_KPI from .Tools import ( check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules, @@ -60,9 +60,9 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): device_uuid = request.device_id.device_uuid.uuid connection_config_rules = check_connect_rules(request.device_config) - if (request.device_drivers[0]!= 9) : + if request.device_drivers[0] != DeviceDriverEnum.DEVICEDRIVER_OC: check_no_endpoints(request.device_endpoints) - + t1 = time.time() context_client = ContextClient() @@ -143,12 +143,12 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED # temporary line - if (request.device_drivers[0]== 9 and len(request.device_endpoints)>0): - - for endpoint in request.device_endpoints: - #endpoint.endpoint_id.device_id.CopyFrom(device.device_id) - pass + if request.device_drivers[0] == DeviceDriverEnum.DEVICEDRIVER_OC and len(request.device_endpoints) > 0: + #for endpoint in request.device_endpoints: + # #endpoint.endpoint_id.device_id.CopyFrom(device.device_id) + # pass device.device_endpoints.extend(request.device_endpoints) + device_id = context_client.SetDevice(device) t10 = time.time() diff --git a/src/device/service/OpenConfigServicer.py b/src/device/service/OpenConfigServicer.py index 5be11cb31ec69825a2b6009159e5202b54936009..1060449f185330faa0a71ff062ad2bbd0086b2e4 100644 --- a/src/device/service/OpenConfigServicer.py +++ b/src/device/service/OpenConfigServicer.py @@ -12,18 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import grpc, logging, os, time -from typing import Dict -from prometheus_client import Histogram -from common.Constants import ServiceNameEnum -from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name -from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method -from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException +import grpc, logging, json +from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method +from common.method_wrappers.ServiceExceptions import NotFoundException from common.proto.context_pb2 import ( - Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link, MyConfig, MyConfigId, - MyConfig, MyConfigList + Device, DeviceId, DeviceOperationalStatusEnum, Empty, OpticalConfig, OpticalConfig ) -from common.proto.device_pb2 import MonitoringSettings from common.proto.device_pb2_grpc import DeviceServiceServicer from common.tools.context_queries.Device import get_device from common.tools.mutex_queues.MutexQueues import MutexQueues @@ -31,13 +25,8 @@ from context.client.ContextClient import ContextClient from .driver_api._Driver import _Driver from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver from .monitoring.MonitoringLoops import MonitoringLoops -from .drivers.oc_driver.OCDriver import OCDriver -from .ErrorMessages import ERROR_MISSING_DRIVER, ERROR_MISSING_KPI from .Tools import extract_resources -from .Tools import ( - check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules, - get_device_controller_uuid, populate_config_rules, populate_endpoint_monitoring_resources, populate_endpoints, - populate_initial_config_rules, subscribe_kpi, unsubscribe_kpi, update_endpoints) +from .Tools import check_no_endpoints LOGGER = logging.getLogger(__name__) @@ -54,14 +43,10 @@ class OpenConfigServicer(DeviceServiceServicer): self.monitoring_loops = monitoring_loops self.mutex_queues = MutexQueues() LOGGER.debug('Servicer Created') - + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) - def AddOpenConfigDevice(self, request : MyConfig, context : grpc.ServicerContext) -> DeviceId: - + def AddOpenConfigDevice(self, request : OpticalConfig, context : grpc.ServicerContext) -> DeviceId: device_uuid = request.device_id.device_uuid.uuid - device_type=request.device_type - ocdriver=OCDriver() - connection_config_rules = check_connect_rules(request.device_config) check_no_endpoints(request.device_endpoints) context_client = ContextClient() @@ -74,61 +59,37 @@ class OpenConfigServicer(DeviceServiceServicer): device.device_type = request.device_type device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED device.device_drivers.extend(request.device_drivers) # pylint: disable=no-member - device.device_config.CopyFrom(request.device_config) # pylint: disable=no-member + device.device_config.CopyFrom(request.device_config) + device.device_endpoints.extend(request.device_endpoints) + # pylint: disable=no-member device_id = context_client.SetDevice(device) device = get_device(context_client, device_id.device_uuid.uuid, rw_copy=True) # update device_uuid to honor UUID provided by Context device_uuid = device.device_id.device_uuid.uuid - LOGGER.debug('device type %s',device) - t2 = time.time() - self.mutex_queues.wait_my_turn(device_uuid) - t3 = time.time() - #temp fix to solve the error - #todo check what to pass here - resources_to_get = [] try: - #driver : _Driver = get_driver(self.driver_instance_cache, device) - results_getconfig=ocdriver.GetConfig(resource_keys=resources_to_get,device_uuid=device_uuid) - #results_getconfig = driver.GetConfig(resources_to_get,device_uuid) + device_id = context_client.SetDevice(device) except Exception as error : LOGGER.debug("error %s",error) @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) - def ConfigureOpticalDevice (self, request : MyConfig, context:grpc.ServicerContext) -> Empty: - LOGGER.info('Setting from ConfigureOpticalDevice with Flows %s',request) - #device_id = request.myconfig_id - #device_uuid = device_id.myconfig_uuid - device_uuid = request.myconfig_id.myconfig_uuid - LOGGER.info("device uuid {}".format(device_uuid)) + def ConfigureOpticalDevice (self, request : OpticalConfig, context : grpc.ServicerContext) -> Empty: + device_uuid = request.opticalconfig_id.opticalconfig_uuid resources=[] - result=None - config = eval(request.config) - filter_fields= ["frequency", "target-output-power", "interface", "operational-mode"] + config =json.loads(request.config) try: context_client = ContextClient() - device = get_device( context_client, device_uuid, rw_copy=True, include_endpoints=True, include_components=False, include_config_rules=False) - if device is None: - LOGGER.info("device is none") raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice') resources,conditions=extract_resources(config=config,device=device) driver : _Driver = get_driver(self.driver_instance_cache, device) - LOGGER.info("resource %s conditions %s",resources,conditions) - result = driver.SetConfig(resources=resources,conditions=conditions) - #todo - #add a control with the NETCONF get + #TODO: add a control with the NETCONF get #driver.GetConfig(resource_keys=filter_fields) - except Exception as e: LOGGER.info("error in configuring %s",e) - - - LOGGER.info("result %s",result) return Empty() - \ No newline at end of file diff --git a/src/device/service/Tools.py b/src/device/service/Tools.py index 8ccb77afa712d77a66f4d971340f93231bbaf0a6..f3700e10488228387145a2c4c8574a899675aade 100644 --- a/src/device/service/Tools.py +++ b/src/device/service/Tools.py @@ -12,30 +12,26 @@ # See the License for the specific language governing permissions and # limitations under the License. -from uuid import UUID, uuid4, uuid5 import json, logging from typing import Any, Dict, List, Optional, Tuple, Union from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME -from common.method_wrappers.ServiceExceptions import InvalidArgumentException -from common.proto.context_pb2 import ConfigActionEnum, ConfigRule_ACL, Device, DeviceConfig, Link, Location +from common.DeviceTypes import DeviceTypeEnum +from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException +from common.proto.context_pb2 import ConfigActionEnum, ConfigRule_ACL, Device, DeviceConfig, EndPoint, Link, Location from common.proto.device_pb2 import MonitoringSettings from common.proto.kpi_sample_types_pb2 import KpiSampleType from common.tools.grpc.ConfigRules import update_config_rule_custom from common.tools.grpc.Tools import grpc_message_to_json +from common.type_checkers.Checkers import chk_length, chk_type from .driver_api._Driver import _Driver, RESOURCE_ENDPOINTS from .monitoring.MonitoringLoops import MonitoringLoops from .ErrorMessages import ( ERROR_BAD_RESOURCE, ERROR_DELETE, ERROR_GET, ERROR_GET_INIT, ERROR_MISSING_KPI, ERROR_SAMPLETYPE, ERROR_SET, ERROR_SUBSCRIBE, ERROR_UNSUBSCRIBE, ERROR_UNSUP_RESOURCE ) -from .drivers.oc_driver.OCDriver import OCDriver -from common.method_wrappers.ServiceExceptions import NotFoundException -from common.type_checkers.Checkers import chk_length, chk_type -from common.proto.context_pb2 import EndPoint LOGGER = logging.getLogger(__name__) - def get_endpoint_matching(device : Device, endpoint_uuid_or_name : str) -> EndPoint: for endpoint in device.device_endpoints: choices = {endpoint.endpoint_id.endpoint_uuid.uuid, endpoint.name} @@ -456,76 +452,73 @@ def update_endpoints(src_device : Device, dst_device : Device) -> None: if len(src_topology_uuid) > 0: dst_topology_id.topology_uuid.uuid = src_topology_uuid if len(src_context_uuid) > 0: dst_topology_id.context_id.context_uuid.uuid = src_context_uuid -def oc_default_endpoints( - device : Device, driver : _Driver, monitoring_loops : MonitoringLoops, - new_sub_devices : Dict[str, Device], new_sub_links : Dict[str, Link] -) -> List[str]: - - pass -#def get_enpoint_name (device:Device,endpoint_id:str): -# str(UUID(str_uuid_or_name)) - -def get_edit_target (device:Device,is_opticalband:bool)-> str: - if (is_opticalband): return "optical-band" - else : - if device.device_type =='optical-roadm': return 'media-channel' - else : return 'optical-channel' - -def extract_resources (config : dict, device : Device)-> list: - conditions={} - resources=[] - resources.append({"resource_key":"channel_namespace","value":config["channel_namespace"] if "channel_namespace" in config else None}) - resources.append({"resource_key":'add_transceiver',"value":config['add_transceiver'] if 'add_transceiver' in config else None}) - resources.append({"resource_key":"interface","value":config["update_interface"] if 'update_interface' in config else None}) - is_opticalband=config['is_opticalband'] if 'is_opticalband' in config else False - conditions["is_opticalband"]=is_opticalband - conditions["edit_type"]=get_edit_target(device=device,is_opticalband=is_opticalband) - if ('flow' in config): +def get_edit_target(device : Device, is_opticalband : bool) -> str: + if is_opticalband: return 'optical-band' + if device.device_type == DeviceTypeEnum.OPTICAL_ROADM: return 'media-channel' + return 'optical-channel' + +def is_key_existed(key : str, keys_dic = dict, key_name_to_use = None) -> dict: + dic = {} + dic['resource_key'] = key + if key_name_to_use is not None: + dic['resource_key'] = key_name_to_use + if key in keys_dic: + dic['value'] = keys_dic[key] + else: + dic['value'] = None + return dic + +def extract_resources(config : dict, device : Device) -> list: + conditions = {} + resources = [] + resources.append(is_key_existed('channel_namespace', config)) + resources.append(is_key_existed('add_transceiver', config)) + is_opticalband = config.get('is_opticalband', False) + conditions['is_opticalband'] = is_opticalband + conditions['edit_type'] = get_edit_target(device, is_opticalband) + if 'flow' in config: #for tuple_value in config['flow'][device.name]: source_vals = [] dest_vals = [] for tuple_value in config['flow']: - source_port=None - destination_port=None - #resources.append({"resource_key":"source_port","value":source_port}) - #resources.append({"resource_key":"destination_port","value":destination_port}) - source_port_uuid,destination_port_uuid=tuple_value - if (source_port_uuid !='0'): + source_port = None + destination_port = None + source_port_uuid, destination_port_uuid = tuple_value + if source_port_uuid != '0': src_endpoint_obj = get_endpoint_matching(device, source_port_uuid) source_port = src_endpoint_obj.name source_vals.append(source_port) - if (destination_port_uuid !='0'): + if destination_port_uuid != '0': dst_endpoint_obj = get_endpoint_matching(device, destination_port_uuid) destination_port = dst_endpoint_obj.name dest_vals.append(destination_port) - resources.append({"resource_key":"source_port","value":source_vals}) - resources.append({"resource_key":"destination_port","value":dest_vals}) - if ('new_config' in config): - lower_frequency=None - upper_frequency=None - resources.append({"resource_key":"target-output-power","value":config["new_config"]["target-output-power"] if "target-output-power" in config["new_config"] else None }) - #resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config else config["new_config"]["freqency"]}) - resources.append({"resource_key":"frequency","value":config["new_config"]["frequency"] if "frequency" in config["new_config"] else None}) - resources.append({"resource_key":"operational-mode","value":config["new_config"]["operational-mode"] if "operational-mode" in config["new_config"] else None}) - resources.append({"resource_key":"line-port","value":config["new_config"]["line-port"] if "line-port" in config["new_config"] else None}) - - resources.append({"resource_key":"name","value":config['new_config']['band_type'] if 'band_type' in config['new_config'] else None}) - resources.append({"resource_key":"optical-band-parent","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None }) - resources.append({"resource_key":"channel_name","value":config["new_config"]["name"] if "name" in config["new_config"] else None}) - - if not is_opticalband : - if 'frequency' in config['new_config'] and 'band' in config['new_config'] and conditions["edit_type"] == 'media-channel': - lower_frequency= int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2)) - upper_frequency= int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2)) - - #lower_frequency= (config['new_config']['frequency']- config['new_config']['band'])/2 - #upper_frequency=(config['new_config']['frequency']+ config['new_config']['band'])/2 - resources.append({"resource_key":"index","value":config["new_config"]["flow_id"] if "flow_id" in config["new_config"] else None}) - else : - lower_frequency=config['new_config']['low-freq'] if "low-freq" in config['new_config'] else None - upper_frequency=config['new_config']['up-freq'] if 'up-freq' in config['new_config'] else None - resources.append({"resource_key":"index","value":config["new_config"]["ob_id"] if "ob_id" in config["new_config"] else None}) - - resources.append({"resource_key":"lower-frequency","value":lower_frequency}) - resources.append({"resource_key":"upper-frequency","value":upper_frequency}) - return [resources,conditions] + resources.append({'resource_key': 'source_port', 'value': source_vals}) + resources.append({'resource_key': 'destination_port', 'value': dest_vals }) + + if 'new_config' in config: + lower_frequency = None + upper_frequency = None + resources.append(is_key_existed('target-output-power', keys_dic=config['new_config'])) + resources.append(is_key_existed('frequency', keys_dic=config['new_config'])) + resources.append(is_key_existed('operational-mode', keys_dic=config['new_config'])) + resources.append(is_key_existed('line-port', keys_dic=config['new_config'])) + resources.append(is_key_existed('band_type', keys_dic=config['new_config'], key_name_to_use='name')) + resources.append(is_key_existed('ob_id', keys_dic=config['new_config'], key_name_to_use='optical-band-parent')) + resources.append(is_key_existed('name', keys_dic=config['new_config'], key_name_to_use='channel_name')) + if not is_opticalband: + if 'frequency' in config['new_config'] and 'band' in config['new_config'] and conditions['edit_type'] == 'media-channel': + lower_frequency = int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2)) + upper_frequency = int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2)) + #lower_frequency = (config['new_config']['frequency'] - config['new_config']['band'])/2 + #upper_frequency = (config['new_config']['frequency'] + config['new_config']['band'])/2 + resources.append(is_key_existed('flow_id', keys_dic=config['new_config'], key_name_to_use='index')) + #resources.append({'resource_key':'index','value':config['new_config']['flow_id'] if 'flow_id' in config['new_config'] else None}) + else: + lower_frequency = config['new_config']['low-freq'] if 'low-freq' in config['new_config'] else None + upper_frequency = config['new_config']['up-freq' ] if 'up-freq' in config['new_config'] else None + resources.append(is_key_existed('ob_id', keys_dic=config['new_config'], key_name_to_use='index')) + #resources.append({'resource_key':'index','value':config['new_config']['ob_id'] if 'ob_id' in config['new_config'] else None}) + resources.append({'resource_key': 'lower-frequency', 'value': lower_frequency}) + resources.append({'resource_key': 'upper-frequency', 'value': upper_frequency}) + + return [resources, conditions] diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py index 09c4d33b70ffce893ce9ea08b2e67e0a12d350ef..beb3db38e153445e48d61e3ad4ac5d514297a91d 100644 --- a/src/device/service/drivers/__init__.py +++ b/src/device/service/drivers/__init__.py @@ -15,12 +15,9 @@ import os from common.DeviceTypes import DeviceTypeEnum from common.proto.context_pb2 import DeviceDriverEnum +from device.Config import LOAD_ALL_DEVICE_DRIVERS from ..driver_api.FilterFields import FilterFieldEnum -TRUE_VALUES = {'T', 'TRUE', 'YES', '1'} -DEVICE_EMULATED_ONLY = os.environ.get('DEVICE_EMULATED_ONLY') -LOAD_ALL_DEVICE_DRIVERS = (DEVICE_EMULATED_ONLY is None) or (DEVICE_EMULATED_ONLY.upper() not in TRUE_VALUES) - DRIVERS = [] from .emulated.EmulatedDriver import EmulatedDriver # pylint: disable=wrong-import-position @@ -172,11 +169,9 @@ if LOAD_ALL_DEVICE_DRIVERS: from .oc_driver.OCDriver import OCDriver # pylint: disable=wrong-import-position DRIVERS.append( (OCDriver, [ - { # Real Packet Router, specifying OpenConfig Driver => use OpenConfigDriver FilterFieldEnum.DEVICE_TYPE: [ - DeviceTypeEnum.NETCONFIG_AGENT, DeviceTypeEnum.OPTICAL_ROADM, DeviceTypeEnum.OPTICAL_TRANSPONDER ], diff --git a/src/device/service/drivers/oc_driver/OCDriver.py b/src/device/service/drivers/oc_driver/OCDriver.py index 512ec49baa66ed7a5cb4062c2ddf34bff81f9cde..16f00cfb4c7b80d807882ab5b4c95b36b28db8f6 100644 --- a/src/device/service/drivers/oc_driver/OCDriver.py +++ b/src/device/service/drivers/oc_driver/OCDriver.py @@ -35,9 +35,9 @@ from .templates.VPN.physical import create_optical_channel,add_transceiver,crea from .RetryDecorator import retry from context.client.ContextClient import ContextClient from common.proto.context_pb2 import ( - MyConfig, + OpticalConfig, ConfigActionEnum, Device, DeviceDriverEnum, DeviceId, DeviceList, DeviceOperationalStatusEnum, Empty - ,MyConfigId,Uuid) + ,OpticalConfigId,Uuid) from .templates.Tools import extractor from .Tools import generate_uuid_from_numbers DEBUG_MODE = False @@ -135,8 +135,7 @@ class NetconfSessionHandler: response= self.__manager.edit_config( config, target=target, default_operation=default_operation, test_option=test_option, error_option=error_option, format=format) - logging.info("response message %s",response) - + @RETRY_DECORATOR def locked(self, target): @@ -154,17 +153,12 @@ def edit_config( commit_per_rule=False, target='running', default_operation='merge', test_option=None, error_option=None, format='xml' ): - str_method = 'DeleteConfig' if delete else 'SetConfig' + #str_method = 'DeleteConfig' if delete else 'SetConfig' results = [] str_config_messages=[] - #try: - # if add_proccess: - # str_config_messages = add_transceiver(resources[0]['value']) - # elif update_interface: - # str_config_messages = interface_template(resources[0]["value"]) - # else: + if (conditions['edit_type']=='optical-channel'): #transponder str_config_messages = create_optical_channel(resources) @@ -174,14 +168,8 @@ def edit_config( else : #roadm media-channel str_config_messages=create_media_channel(resources) - logging.info("config message %s",str_config_messages) - # if (add_proccess or update_interface): - - # netconf_handler.edit_config( # configure the device - # config=str_config_messages, target=target, default_operation=default_operation, - # test_option=test_option, error_option=error_option, format=format) - # if commit_per_rule: - # netconf_handler.commit() + + for str_config_message in str_config_messages: # configuration of the received templates @@ -195,23 +183,7 @@ def edit_config( #results[i] = True results.append(True) - # except Exception as e: # pylint: disable=broad-except - # str_operation = 'preparing' if target == 'candidate' else ('deleting' if delete else 'setting') - # msg = '[{:s}] Exception {:s} {:s}: {:s}' - # logger.info("error %s",e) - # logger.exception(msg.format(e)) - # #results[i] = e # if validation fails, store the exception - # results.append(e) - - # if not commit_per_rule: - # try: - # netconf_handler.commit() - # except Exception as e: # pylint: disable=broad-except - # msg = '[{:s}] Exception committing: {:s}' - # str_operation = 'preparing' if target == 'candidate' else ('deleting' if delete else 'setting') - # logger.exception(msg.format(str_method, str_operation, str(resources))) - # results = [e for _ in resources] # if commit fails, set exception in each resource - # return results + class OCDriver(_Driver): def __init__(self, address : str, port : int,device_uuid=None, **settings) -> None: @@ -232,7 +204,7 @@ class OCDriver(_Driver): self._temp_address=f"{address}{port}" self.__out_samples = queue.Queue() self.__netconf_handler = NetconfSessionHandler(self.address, self.port, **(self.settings)) - self.__logger.info("settings are %s",settings) + self.__device_uuid=device_uuid self.Connect() @@ -267,15 +239,15 @@ class OCDriver(_Driver): @metered_subclass_method(METRICS_POOL) def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: - self.__logger.info("device_uuid %s",self.__device_uuid) + chk_type('resources', resource_keys, list) results = [] - myConfig= MyConfig() + opticalConfig= OpticalConfig() j=0 with self.__lock: - self.__logger.info(" resources_key %s",resource_keys) + context_client.connect() config={} channels_lst=[] @@ -301,12 +273,10 @@ class OCDriver(_Driver): value_dic["interfaces"]=interfaces value_dic["channel_namespace"]=channel_namespace value_dic["endpoints"]=endpoints - self.__logger.info("config from get config %s",str(value_dic)) - myConfig.config=str(value_dic) - - myconfig_id=MyConfigId() - myConfig.myconfig_id.myconfig_uuid=self.__device_uuid if self.__device_uuid is not None else "" - config_id=context_client.SetMyConfig(myConfig) + + opticalConfig.config=json.dumps(value_dic) + opticalConfig.opticalconfig_id.opticalconfig_uuid=self.__device_uuid if self.__device_uuid is not None else "" + config_id=context_client.SetOpticalConfig(opticalConfig) context_client.close() diff --git a/src/device/service/drivers/oc_driver/templates/Tools.py b/src/device/service/drivers/oc_driver/templates/Tools.py index 4370495c912dafbc2c5165e00fc79ec885536a4d..909bdd83bf4c189da0a778268ce40119cca7c452 100644 --- a/src/device/service/drivers/oc_driver/templates/Tools.py +++ b/src/device/service/drivers/oc_driver/templates/Tools.py @@ -92,7 +92,6 @@ def extract_channels_based_on_channelnamespace (xml_data:str,channel_namespace:s xml_bytes = xml_data.encode("utf-8") root = ET.fromstring(xml_bytes) channels=[] - logging.info("channel namespace %s opticalband %s",channel_namespace ,is_opticalband) # Find the component names whose children include the "optical-channel" element if (not is_opticalband): @@ -122,7 +121,6 @@ def extract_channels_based_on_channelnamespace (xml_data:str,channel_namespace:s # Retrieve port-name for dest - logging.info("extract channels %s",channels) return channels def extract_channels_based_on_type (xml_data:str): xml_bytes = xml_data.encode("utf-8") @@ -230,10 +228,10 @@ def has_opticalbands(xml_data:str): return has_opticalbands def extractor(data_xml:str,resource_keys:list,dic:dict): - logging.info('data xml %s',data_xml) + endpoints=[] is_opticalband=has_opticalbands(xml_data=data_xml) - logging.info("from extractor opticalband %s",is_opticalband) + channel_namespace=extract_channel_xmlns(data_xml=data_xml,is_opticalband=is_opticalband) # channel_names=extract_channels_based_on_type(xml_data=data_xml) # if len(channel_names)==0 : diff --git a/src/device/service/drivers/oc_driver/templates/VPN/physical.py b/src/device/service/drivers/oc_driver/templates/VPN/physical.py index ba0de7ea6fded64b457ffa348f80ca294c89cfdf..355858d2da891d96777d111f481c070fe3036d44 100644 --- a/src/device/service/drivers/oc_driver/templates/VPN/physical.py +++ b/src/device/service/drivers/oc_driver/templates/VPN/physical.py @@ -21,7 +21,7 @@ def seperate_port_config(resources:list,unwanted_keys:list[str])->list[list,dict ports={} index=None for item in resources : - logging.info("Andrea223344 item={}".format(item['resource_key'])) + if (item['value'] is not None and (item['resource_key'] not in unwanted_keys)): config.append({'resource_key':item['resource_key'], 'value':item['value']} ) #if (item['resource_key'] == 'destination_port' or item['resource_key'] == 'source_port') and item['value'] is not None: @@ -30,25 +30,24 @@ def seperate_port_config(resources:list,unwanted_keys:list[str])->list[list,dict ports[item['resource_key']]=item['value'] if (item['resource_key']=='index' and item['value'] is not None) : index=item['value'] - logging.info("from create_templates config %s ports %s index %s",config,ports,index) + return [config,ports,index] def create_optical_channel(resources): - logging.debug("TRANSPONDERconfiguration, resources={}".format(resources)) + unwanted_keys=['destination_port','source_port','channel_namespace','optical-band-parent','index', 'name'] results =[] data={"name":i["value"] for i in resources if i["resource_key"]=="channel_name"} data["channel_namespace"]=next((i["value"] for i in resources if i["resource_key"] == "channel_namespace"), None) config,ports,index=seperate_port_config(resources,unwanted_keys=unwanted_keys) - logging.info("from physical %s",resources) - + port_val = "" if 'destination_port' in ports and ports['destination_port'][0] is not None: port_val = ports['destination_port'][0] else: port_val = ports['source_port'][0] - logging.info("transponder port={}".format(port_val)) + doc, tag, text = Doc().tagtext() #with tag('config'): @@ -69,7 +68,7 @@ def create_optical_channel(resources): ) results.append(result) - logging.info("xml %s",results) + return results def add_transceiver (transceiver_name:str): @@ -184,7 +183,7 @@ def create_media_channel (resources): with tag('config'): #with tag('index'):text(index) for resource in config: - logging.info("Andrea223344 resources_key= {}".format(resource['resource_key'])) + if resource['resource_key'] == "index": with tag('index'):text(str(int(index)+i)) else: diff --git a/src/monitoring/tests/test_unitary.py b/src/monitoring/tests/test_unitary.py index f2c2215970545e1f6583598bdc5ef88299ba76d2..9aa6acea46a8350553a0c1aed3db8f9e444c4877 100644 --- a/src/monitoring/tests/test_unitary.py +++ b/src/monitoring/tests/test_unitary.py @@ -38,7 +38,6 @@ from common.tools.service.GenericGrpcService import GenericGrpcService from common.tools.timestamp.Converters import timestamp_utcnow_to_float #, timestamp_string_to_float from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient -from device.service.DeviceService import DeviceService from device.service.driver_api.DriverFactory import DriverFactory from device.service.driver_api.DriverInstanceCache import DriverInstanceCache from monitoring.client.MonitoringClient import MonitoringClient @@ -54,7 +53,8 @@ from monitoring.tests.Messages import create_kpi_request, create_kpi_request_d, from monitoring.tests.Objects import DEVICE_DEV1, DEVICE_DEV1_CONNECT_RULES, DEVICE_DEV1_UUID, ENDPOINT_END1_UUID os.environ['DEVICE_EMULATED_ONLY'] = 'TRUE' -from device.service.drivers import DRIVERS # pylint: disable=wrong-import-position,ungrouped-imports +from device.service.DeviceService import DeviceService # pylint: disable=wrong-import-position,ungrouped-imports +from device.service.drivers import DRIVERS # pylint: disable=wrong-import-position,ungrouped-imports ########################### diff --git a/src/opticalattackdetector/.gitlab-ci.yml b/src/opticalattackdetector/.gitlab-ci.yml index 9c064f118ed435ff1c2f7cad92c2f717b87969d8..d329cd265389a0e4680727e4ec62a4f970431531 100644 --- a/src/opticalattackdetector/.gitlab-ci.yml +++ b/src/opticalattackdetector/.gitlab-ci.yml @@ -55,6 +55,7 @@ unit_test opticalattackdetector: - export REDIS_PASSWORD=$(uuidgen) - docker pull "redis:7.0-alpine" - docker run --name redis -d --network=teraflowbridge -p 16379:6379 -e REDIS_PASSWORD=${REDIS_PASSWORD} --rm redis:7.0-alpine redis-server --requirepass ${REDIS_PASSWORD} + - while ! docker logs redis 2>&1 | grep -q 'Ready to accept connections'; do sleep 1; done - docker logs redis - REDIS_ADDRESS=$(docker inspect redis --format "{{.NetworkSettings.Networks.teraflowbridge.IPAddress}}") - docker pull "$CI_REGISTRY_IMAGE/dbscanserving:$IMAGE_TAG" diff --git a/src/opticalcontroller/OpticalController.py b/src/opticalcontroller/OpticalController.py index e8e0e2164a81f6ea621decba92350b04cdcba814..c2805695a75933c73d4ad367176bee8b504d4460 100644 --- a/src/opticalcontroller/OpticalController.py +++ b/src/opticalcontroller/OpticalController.py @@ -198,7 +198,7 @@ class GetBands(Resource): return "Error", 404 -@optical.route('/GetOpticalBand/<string:ob_id>') +@optical.route('/GetOpticalBand/<int:ob_id>') @optical.response(200, 'Success') @optical.response(404, 'Error, not found') class GetBand(Resource): @@ -238,9 +238,8 @@ if __name__ == '__main__': nodes_dict, links_dict = readTopologyData(nodes_json, topology_json) - topologies,links= getTopology() - print ("topologies{} and devices {}".format(topologies,links)) + #topologies, links = getTopology() + #print("topologies{} and devices {}".format(topologies,links)) rsa = RSA(nodes_dict, links_dict) - LOGGER.info(rsa.init_link_slots(testing)) - app.run(host='0.0.0.0', port=5022,debug=True) + app.run(host='0.0.0.0', port=10060, debug=True) diff --git a/src/opticalcontroller/RSA.py b/src/opticalcontroller/RSA.py index acf080d7f9c223766409551051b7cacae1610db1..9b12b1ac8d9302c2bb622b2d4b81924b5453036c 100644 --- a/src/opticalcontroller/RSA.py +++ b/src/opticalcontroller/RSA.py @@ -322,11 +322,14 @@ class RSA(): 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: if debug: print(link) - return link + result = link + break + return result def get_fiber_details(self, link_key, fiber_id): for link in self.links_dict["links"]: @@ -787,6 +790,13 @@ 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 + 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 print("INFO: TP to TP connection") if band is None: temp_links2 = [] @@ -806,13 +816,7 @@ class RSA(): temp_path.append(roadm_dst) temp_path.append(t_dst) existing_ob = self.get_optical_bands(roadm_src, roadm_dst) - 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 len(existing_ob) > 0: print("INFO: Evaluating existing OB {}".format(existing_ob)) @@ -875,13 +879,13 @@ 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 + # 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/json_files/tfs.json b/src/opticalcontroller/json_files/tfs.json index a108ed13ee5fe85c974e41e8ff6fe5ed5dd7d2ed..31803b893b5639e957be33465599573baa475ca2 100644 --- a/src/opticalcontroller/json_files/tfs.json +++ b/src/opticalcontroller/json_files/tfs.json @@ -39,159 +39,9 @@ "ID": "M1", "length": 0, "src_port": "1", - "dst_port": "2001", + "dst_port": "12", "local_peer_port": "1", - "remote_peer_port": "1001", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M2", - "length": 0, - "src_port": "2", - "dst_port": "2002", - "local_peer_port": "2", - "remote_peer_port": "1002", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M3", - "length": 0, - "src_port": "3", - "dst_port": "2003", - "local_peer_port": "3", - "remote_peer_port": "1003", + "remote_peer_port": "2", "used": false, "c_slots": [ 1, @@ -302,9 +152,9 @@ { "ID": "M1", "length": 0, - "src_port": "1001", + "src_port": "2", "dst_port": "1", - "local_peer_port": "2001", + "local_peer_port": "12", "remote_peer_port": "1", "used": false, "c_slots": [ @@ -373,15 +223,53 @@ 519, 520 ] - }, + } + ] + } + } + }, + { + "link_id": { + "link_uuid": { + "uuid": "R1->R2" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "3" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "14" + } + } + ], + "optical_link": { + "name": "R1-R2", + "details": { + "length": 0, + "source": "D1", + "target": "D1", + "fibers": [ { - "ID": "M2", + "ID": "D11", "length": 0, - "src_port": "1002", - "dst_port": "2", - "local_peer_port": "2002", - "remote_peer_port": "2", - "used": false, + "src_port": "3", + "dst_port": "14", + "local_peer_port": "13", + "remote_peer_port": "4", "c_slots": [ 1, 2, @@ -448,15 +336,53 @@ 519, 520 ] - }, + } + ] + } + } + }, + { + "link_id": { + "link_uuid": { + "uuid": "R2->R1" + } + }, + "link_endpoint_ids": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "endpoint_uuid": { + "uuid": "4" + } + }, + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "endpoint_uuid": { + "uuid": "13" + } + } + ], + "optical_link": { + "name": "R2-R1", + "details": { + "length": 0, + "source": "D1", + "target": "D1", + "fibers": [ { - "ID": "M3", + "ID": "D11", "length": 0, - "src_port": "1003", - "dst_port": "3", - "local_peer_port": "2003", + "src_port": "4", + "dst_port": "13", + "local_peer_port": "14", "remote_peer_port": "3", - "used": false, "c_slots": [ 1, 2, @@ -531,18 +457,18 @@ { "link_id": { "link_uuid": { - "uuid": "R1->R2" + "uuid": "T2->R2" } }, "link_endpoint_ids": [ { "device_id": { "device_uuid": { - "uuid": "R1" + "uuid": "T2" } }, "endpoint_uuid": { - "uuid": "13" + "uuid": "6" } }, { @@ -552,24 +478,25 @@ } }, "endpoint_uuid": { - "uuid": "24" + "uuid": "15" } } ], "optical_link": { - "name": "R1-R2", + "name": "T2-R2", "details": { "length": 0, - "source": "D1", - "target": "D1", + "source": "srgT", + "target": "muxT", "fibers": [ { - "ID": "D11", + "ID": "M1", "length": 0, - "src_port": "13", - "dst_port": "24", - "local_peer_port": "23", - "remote_peer_port": "14", + "src_port": "6", + "dst_port": "15", + "local_peer_port": "6", + "remote_peer_port": "5", + "used": false, "c_slots": [ 1, 2, @@ -644,7 +571,7 @@ { "link_id": { "link_uuid": { - "uuid": "R2->R1" + "uuid": "R2->T2" } }, "link_endpoint_ids": [ @@ -655,561 +582,34 @@ } }, "endpoint_uuid": { - "uuid": "14" + "uuid": "5" } }, { "device_id": { "device_uuid": { - "uuid": "R1" + "uuid": "T2" } }, "endpoint_uuid": { - "uuid": "23" + "uuid": "6" } } ], "optical_link": { - "name": "R2-R1", + "name": "R2-T2", "details": { "length": 0, - "source": "D1", - "target": "D1", + "source": "srgT", + "target": "muxT", "fibers": [ { - "ID": "D11", + "ID": "M1", "length": 0, - "src_port": "14", - "dst_port": "23", - "local_peer_port": "24", - "remote_peer_port": "13", - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - } - ] - } - } - }, - { - "link_id": { - "link_uuid": { - "uuid": "T2->R2" - } - }, - "link_endpoint_ids": [ - { - "device_id": { - "device_uuid": { - "uuid": "T2" - } - }, - "endpoint_uuid": { - "uuid": "1" - } - }, - { - "device_id": { - "device_uuid": { - "uuid": "R2" - } - }, - "endpoint_uuid": { - "uuid": "1001" - } - } - ], - "optical_link": { - "name": "T2-R2", - "details": { - "length": 0, - "source": "srgT", - "target": "muxT", - "fibers": [ - { - "ID": "M1", - "length": 0, - "src_port": "1", - "dst_port": "1001", - "local_peer_port": "1", - "remote_peer_port": "2001", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M2", - "length": 0, - "src_port": "2", - "dst_port": "1002", - "local_peer_port": "2", - "remote_peer_port": "2002", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M3", - "length": 0, - "src_port": "3", - "dst_port": "1003", - "local_peer_port": "3", - "remote_peer_port": "2003", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - } - ] - } - } - }, - { - "link_id": { - "link_uuid": { - "uuid": "R2->T2" - } - }, - "link_endpoint_ids": [ - { - "device_id": { - "device_uuid": { - "uuid": "R2" - } - }, - "endpoint_uuid": { - "uuid": "5" - } - }, - { - "device_id": { - "device_uuid": { - "uuid": "T2" - } - }, - "endpoint_uuid": { - "uuid": "6" - } - } - ], - "optical_link": { - "name": "R2-T2", - "details": { - "length": 0, - "source": "srgT", - "target": "muxT", - "fibers": [ - { - "ID": "M1", - "length": 0, - "src_port": "1001", - "dst_port": "1", - "local_peer_port": "2001", - "remote_peer_port": "1", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M2", - "length": 0, - "src_port": "1002", - "dst_port": "2", - "local_peer_port": "2002", - "remote_peer_port": "2", - "used": false, - "c_slots": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20 - ], - "l_slots": [ - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120 - ], - "s_slots": [ - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520 - ] - }, - { - "ID": "M3", - "length": 0, - "src_port": "1003", - "dst_port": "3", - "local_peer_port": "2003", - "remote_peer_port": "3", + "src_port": "5", + "dst_port": "6", + "local_peer_port": "15", + "remote_peer_port": "6", "used": false, "c_slots": [ 1, diff --git a/src/pathcomp/frontend/Dockerfile b/src/pathcomp/frontend/Dockerfile index b54a49cabab79112e65b28a7e5e28d5a17056d67..c2b9a7a7c7892a3dbce4ed1295b1530e292751c6 100644 --- a/src/pathcomp/frontend/Dockerfile +++ b/src/pathcomp/frontend/Dockerfile @@ -68,8 +68,9 @@ COPY src/context/__init__.py context/__init__.py COPY src/context/client/. context/client/ COPY src/device/__init__.py device/__init__.py COPY src/device/client/. device/client/ -COPY src/forecaster/__init__.py forecaster/__init__.py -COPY src/forecaster/client/. forecaster/client/ +# Requires entire Forecaster component for the tests +# TODO: Improve testing framework +COPY src/forecaster/. forecaster/ COPY src/monitoring/__init__.py monitoring/__init__.py COPY src/monitoring/client/. monitoring/client/ COPY src/service/__init__.py service/__init__.py diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py index b06295deee528656ae30ed33e4dacc7d7d04a178..f65d5b59a0d9a81c44f4d04683eb87e7773efa4a 100644 --- a/src/service/service/ServiceServiceServicerImpl.py +++ b/src/service/service/ServiceServiceServicerImpl.py @@ -255,6 +255,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): DEFAULT_TOPOLOGY_NAME, context_id_x) topology_details = context_client.GetTopologyDetails( TopologyId(**topology_id_x)) + # devices = get_devices_in_topology(context_client, TopologyId(**topology_id_x), ContextId(**context_id_x)) devices = topology_details.devices context_uuid_x = topology_details.topology_id.context_id.context_uuid.uuid topology_uuid_x = topology_details.topology_id.topology_uuid.uuid @@ -289,7 +290,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): parent_ob = reply_json["parent_opt_band"] LOGGER.debug('Parent optical-band={}'.format(parent_ob)) optical_band_txt = get_optical_band(parent_ob) - LOGGER.debug('optical-band details={}'.format(optical_band_txt)) + LOGGER.info('optical-band details={}'.format(optical_band_txt)) else: LOGGER.debug('expected optical band not found') else: @@ -302,22 +303,20 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): optical_reply = adapt_reply( devices, _service, reply_json, context_uuid_x, topology_uuid_x, optical_band_txt ) - LOGGER.debug('optical_reply={:s}'.format( + LOGGER.info('optical_reply={:s}'.format( grpc_message_to_json_string(optical_reply))) tasks_scheduler.compose_from_pathcompreply( optical_reply, is_delete=False) - - if num_disjoint_paths is None or num_disjoint_paths in {0, 1}: + else: + if num_disjoint_paths is None or num_disjoint_paths in {0, 1} : pathcomp_request.shortest_path.Clear() # pylint: disable=no-member else: pathcomp_request.k_disjoint_path.num_disjoint = num_disjoint_paths # pylint: disable=no-member - LOGGER.debug('pathcomp_request={:s}'.format(grpc_message_to_json_string(pathcomp_request))) pathcomp = PathCompClient() pathcomp_reply = pathcomp.Compute(pathcomp_request) pathcomp.close() - LOGGER.debug('pathcomp_reply={:s}'.format(grpc_message_to_json_string(pathcomp_reply))) # Feed TaskScheduler with this path computation reply. TaskScheduler identifies inter-dependencies among # the services and connections retrieved and produces a schedule of tasks (an ordered list of tasks to be @@ -348,7 +347,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY: devs = [] - + context_id_x = json_context_id(DEFAULT_CONTEXT_NAME) topology_id_x = json_topology_id( DEFAULT_TOPOLOGY_NAME, context_id_x) @@ -359,16 +358,15 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): devs.append(endpoint_id.device_id.device_uuid.uuid) src = get_device_name_from_uuid(devices, devs[0]) dst = get_device_name_from_uuid(devices, devs[1]) - + bitrate = int( float(service.service_constraints[0].custom.constraint_value)) if len(service.service_config.config_rules) > 0: c_rules_dict = json.loads( service.service_config.config_rules[0].custom.resource_value) - flow_id = c_rules_dict["flow_id"] - - reply = delete_lightpath(flow_id, src, dst, bitrate) - + if ("flow_id" in c_rules_dict): + flow_id = c_rules_dict["flow_id"] + reply = delete_lightpath(flow_id, src, dst, bitrate) # Normal service # Feed TaskScheduler with this service and the sub-services and sub-connections related to this service. diff --git a/src/service/service/__main__.py b/src/service/service/__main__.py index f2b6e38d6181a0c56b4f1dfca3116717d1400ced..edd4d8f9973e20d0df6e2d99ba8164d5d68f068d 100644 --- a/src/service/service/__main__.py +++ b/src/service/service/__main__.py @@ -17,7 +17,8 @@ from prometheus_client import start_http_server from common.Constants import ServiceNameEnum from common.Settings import ( ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name, get_log_level, get_metrics_port, - wait_for_environment_variables) + wait_for_environment_variables +) from .ServiceService import ServiceService from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory from .service_handlers import SERVICE_HANDLERS diff --git a/src/service/service/service_handler_api/FilterFields.py b/src/service/service/service_handler_api/FilterFields.py index e771e24f17b2ea97c61158b65cb62c87ee9f37c5..633f41b63c71727d9ead0ee57b79002dc3a6cd97 100644 --- a/src/service/service/service_handler_api/FilterFields.py +++ b/src/service/service/service_handler_api/FilterFields.py @@ -26,6 +26,7 @@ SERVICE_TYPE_VALUES = { ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE, ServiceTypeEnum.SERVICETYPE_TE, ServiceTypeEnum.SERVICETYPE_E2E, + ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY } DEVICE_DRIVER_VALUES = { @@ -40,6 +41,7 @@ DEVICE_DRIVER_VALUES = { DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE, DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN, + DeviceDriverEnum.DEVICEDRIVER_OC } # Map allowed filter fields to allowed values per Filter field. If no restriction (free text) None is specified diff --git a/src/service/service/service_handlers/oc/OCServiceHandler.py b/src/service/service/service_handlers/oc/OCServiceHandler.py index 8ae42639315287cada0ca288cd5593240819cfc5..6359f2a09e53cab1002acd55d477aeb2d9b393b0 100644 --- a/src/service/service/service_handlers/oc/OCServiceHandler.py +++ b/src/service/service/service_handlers/oc/OCServiceHandler.py @@ -15,14 +15,14 @@ import json, logging from typing import Any, List, Optional, Tuple, Union from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method -from common.proto.context_pb2 import ConfigRule, DeviceId, EndPointId, Service +from common.proto.context_pb2 import ConfigRule, DeviceId, Service from common.tools.object_factory.Device import json_device_id from common.type_checkers.Checkers import chk_type from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching from service.service.service_handler_api._ServiceHandler import _ServiceHandler from service.service.service_handler_api.SettingsHandler import SettingsHandler from service.service.task_scheduler.TaskExecutor import TaskExecutor -#from .ConfigRules import setup_config_rules, teardown_config_rules +from .ConfigRules import setup_config_rules, teardown_config_rules from .OCTools import convert_endpoints_to_flows, handle_flows_names LOGGER = logging.getLogger(__name__) @@ -53,30 +53,32 @@ class OCServiceHandler(_ServiceHandler): else: settings = self.__settings_handler.get('/settings') - LOGGER.debug("settings={}".format(settings)) - # settings = self.__settings_handler.get('/settings') + + # settings = self.__settings_handler.get('/settings') #flow is the new variable that stores input-output relationship flows = convert_endpoints_to_flows(endpoints) #handled_flows=handle_flows_names(flows=flows,task_executor=self.__task_executor) - LOGGER.debug("dict of flows= {}".format(flows)) + #LOGGER.info("Handled Flows %s",handled_flows) results = [] #new cycle for setting optical devices - for device_uuid, dev_flows in flows.items(): + for device_uuid in flows.keys(): try: + dev_flows = flows[device_uuid] device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) - LOGGER.debug("device_obj={}".format(device_obj)) + + if (settings): - LOGGER.debug("settings={}".format(settings)) + self.__task_executor.configure_optical_device(device_obj, settings, dev_flows, is_opticalband) results.append(True) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to configure Device({:s})'.format(str(device_uuid))) results.append(e) - + return results @metered_subclass_method(METRICS_POOL) @@ -86,14 +88,29 @@ class OCServiceHandler(_ServiceHandler): chk_type('endpoints', endpoints, list) if len(endpoints) == 0: return [] - # TODO: to be checked and elaborated + service_uuid = self.__service.service_id.service_uuid.uuid + settings = self.__settings_handler.get('/settings') results = [] for endpoint in endpoints: try: device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) + device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) - self.__task_executor.configure_device(device_obj) + endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) + endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) + endpoint_name = endpoint_obj.name + + json_config_rules = teardown_config_rules( + service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name, + settings, endpoint_settings) + + if len(json_config_rules) > 0: + del device_obj.device_config.config_rules[:] + for json_config_rule in json_config_rules: + device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) + self.__task_executor.configure_device(device_obj) + results.append(True) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to DeleteEndpoint({:s})'.format(str(endpoint))) diff --git a/src/service/service/service_handlers/oc/OCTools.py b/src/service/service/service_handlers/oc/OCTools.py index f40cb65bef2af5b69628c4167218bed59c92e317..2b202a8a9ce2183342fc23f3563cc16d81abcd5d 100644 --- a/src/service/service/service_handlers/oc/OCTools.py +++ b/src/service/service/service_handlers/oc/OCTools.py @@ -17,6 +17,7 @@ from typing import Dict, Any, List, Optional, Tuple import logging from common.proto.context_pb2 import ConfigRule, DeviceId, Service from common.tools.object_factory.Device import json_device_id + log = logging.getLogger(__name__) #def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]])->Dict[str: List[Tuple[str, str]]]: @@ -26,6 +27,7 @@ def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]]) #entries = Dict[str: List[Tuple[str, str]]] entries = {} #tuple is in, out + #end = len(endpoints) if isinstance(endpoints,list) else 0 end = len(endpoints) i = 0 bidir = 0 diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py index 6d24da4c0be05e1687536a836219bbfa15052504..b9715aae637bb8845077bfc2b8b9b9d1bb030645 100644 --- a/src/service/service/task_scheduler/TaskExecutor.py +++ b/src/service/service/task_scheduler/TaskExecutor.py @@ -12,12 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging #, json +import json, logging from enum import Enum from typing import TYPE_CHECKING, Any, Dict, Optional, Union from common.method_wrappers.ServiceExceptions import NotFoundException from common.proto.context_pb2 import ( - Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId, MyConfig, MyConfigId + Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId, + OpticalConfig, OpticalConfigId ) from common.tools.context_queries.Connection import get_connection_by_id from common.tools.context_queries.Device import get_device @@ -27,7 +28,8 @@ from common.tools.object_factory.Device import json_device_id from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient from service.service.service_handler_api.Exceptions import ( - UnsatisfiedFilterException, UnsupportedFilterFieldException, UnsupportedFilterFieldValueException) + UnsatisfiedFilterException, UnsupportedFilterFieldException, UnsupportedFilterFieldValueException +) from service.service.service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory, get_service_handler_class from service.service.tools.ObjectKeys import get_connection_key, get_device_key, get_service_key @@ -110,7 +112,7 @@ class TaskExecutor: return device def configure_device(self, device : Device) -> None: - self._context_client.SelectMyConfig() + self._context_client.SelectOpticalConfig() device_key = get_device_key(device.device_id) self._device_client.ConfigureDevice(device) self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device) @@ -118,28 +120,25 @@ class TaskExecutor: # New function Andrea for Optical Devices def configure_optical_device(self, device : Device, settings : str, flows : list, is_opticalband : bool): device_key = get_device_key(device.device_id) - myid = MyConfigId() - myid.myconfig_uuid = device.device_id.device_uuid.uuid - myConfig = MyConfig() - + myid = OpticalConfigId() + myid.opticalconfig_uuid = device.device_id.device_uuid.uuid + opticalconfig = OpticalConfig() setting = settings.value if settings else "" - + new_config = {} try: - result = self._context_client.SelectMyConfig(myid) - new_config = eval(result.config) - LOGGER.info("result %s",result) + result = self._context_client.SelectOpticalConfig(myid) + new_config = json.loads(result.config) if result is not None : - new_config["new_config"]=setting - new_config["is_opticalband"]=is_opticalband - new_config["flow"]=flows + new_config["new_config"] = setting + new_config["is_opticalband"] = is_opticalband + new_config["flow"] = flows result.config = str(new_config) - myConfig.CopyFrom(result) - self._device_client.ConfigureOpticalDevice(myConfig) - + opticalconfig.CopyFrom(result) + self._device_client.ConfigureOpticalDevice(opticalconfig) self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device) except Exception as e: - LOGGER.debug("error in config my config %s",e) + LOGGER.info("error in config my config %s",e) def get_device_controller(self, device : Device) -> Optional[Device]: #json_controller = None diff --git a/src/service/service/tools/OpticalTools.py b/src/service/service/tools/OpticalTools.py index 227be2765fbd6bbc779e53505b833fc8bf08873f..20652437194b9ef498f5b83bbe996863ba49c911 100644 --- a/src/service/service/tools/OpticalTools.py +++ b/src/service/service/tools/OpticalTools.py @@ -17,35 +17,41 @@ import json import requests import uuid from common.Constants import * -from typing import Dict, List +from typing import List from common.proto.context_pb2 import( - Device, DeviceId, Service, Connection, EndPointId, TopologyId, ContextId, Uuid, ConfigRule, ConfigActionEnum, ConfigRule_Custom) + Device, DeviceId, Service, Connection, EndPointId, TopologyId, ContextId, Uuid, + ConfigRule, ConfigActionEnum, ConfigRule_Custom +) from common.proto.pathcomp_pb2 import PathCompReply -from typing import Dict, List, Optional, Tuple - -from context.service.database.uuids.EndPoint import endpoint_get_uuid - - +from common.Settings import ( + ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, find_environment_variables, get_env_var_name +) from service.service.tools.replies import reply_uni_txt, optical_band_uni_txt, reply_bid_txt, optical_band_bid_txt log = logging.getLogger(__name__) -testing = True - +testing = False -def get_uuids_from_names(devices: List[Device], device_name: str, port_name: str): +VAR_NAME_OPTICAL_CONTROLLER_HOST = get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER, ENVVAR_SUFIX_SERVICE_HOST) +VAR_NAME_OPTICAL_CONTROLLER_PORT = get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER, ENVVAR_SUFIX_SERVICE_PORT_GRPC) + +opticalcontrollers_url = find_environment_variables([ + VAR_NAME_OPTICAL_CONTROLLER_HOST, + VAR_NAME_OPTICAL_CONTROLLER_PORT, +]) +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)) +def get_uuids_from_names(devices: List[Device], device_name: str, port_name: str): device_uuid = "" port_uuid = "" for device in devices: if device.name == device_name: - device_uuid = device.device_id.device_uuid.uuid - for ep in device.device_endpoints: if ep.name == port_name: port_uuid = ep.endpoint_id.endpoint_uuid.uuid - return device_uuid, port_uuid return "", "" @@ -134,6 +140,7 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b #add optical band connection first rules_ob= [] ob_id = 0 + connection_ob=None if optical_band_txt != "": ob_json = json.loads(optical_band_txt) ob = ob_json @@ -176,7 +183,7 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob)) connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) else: - log.INFO("no map device port for device {} port {}".format(devxb, in_end_point_f)) + log.info("no map device port for device {} port {}".format(devxb, in_end_point_f)) if out_end_point_f != "0": d_ob, p_ob = get_uuids_from_names(devices, devxb, out_end_point_f) @@ -184,21 +191,21 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob)) connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) else: - log.INFO("no map device port for device {} port {}".format(devxb, out_end_point_f)) + log.info("no map device port for device {} port {}".format(devxb, out_end_point_f)) if in_end_point_b != "0": d_ob, p_ob = get_uuids_from_names(devices, devxb, in_end_point_b) if d_ob != "" and p_ob != "": end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob)) connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) else: - log.INFO("no map device port for device {} port {}".format(devxb, in_end_point_b)) + log.info("no map device port for device {} port {}".format(devxb, in_end_point_b)) if out_end_point_b != "0": d_ob, p_ob = get_uuids_from_names(devices, devxb, out_end_point_b) if d_ob != "" and p_ob != "": end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob)) connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) else: - log.INFO("no map device port for device {} port {}".format(devxb, out_end_point_b)) + log.info("no map device port for device {} port {}".format(devxb, out_end_point_b)) log.debug("optical-band connection {}".format(connection_ob)) r = reply_json bidir_f = r["bidir"] @@ -223,39 +230,39 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p)) connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) else: - log.INFO("no map device port for device {} port {}".format(devx, in_end_point_f)) + log.info("no map device port for device {} port {}".format(devx, in_end_point_f)) if out_end_point_f != "0": d, p = get_uuids_from_names(devices, devx, out_end_point_f) if d != "" and p != "": end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p)) connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) else: - log.INFO("no map device port for device {} port {}".format(devx, out_end_point_f)) + log.info("no map device port for device {} port {}".format(devx, out_end_point_f)) if in_end_point_b != "0": d, p = get_uuids_from_names(devices, devx, in_end_point_b) if d != "" and p != "": end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p)) connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) else: - log.INFO("no map device port for device {} port {}".format(devx, in_end_point_b)) + log.info("no map device port for device {} port {}".format(devx, in_end_point_b)) if out_end_point_b != "0": d, p = get_uuids_from_names(devices, devx, out_end_point_b) if d != "" and p != "": end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p)) connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) else: - log.INFO("no map device port for device {} port {}".format(devx, out_end_point_b)) + log.info("no map device port for device {} port {}".format(devx, out_end_point_b)) #check that list of endpoints is not empty - if len(connection_ob.path_hops_endpoint_ids) == 0: + if connection_ob is not None and len(connection_ob.path_hops_endpoint_ids) == 0: log.debug("deleting empty optical-band connection") opt_reply.connections.remove(connection_ob) #inizialize custom optical parameters - band = r["band"] - op_mode = r["op-mode"] - frequency = r["freq"] - flow_id = r["flow_id"] - r_type = r["band_type"] + band = r["band"] if "band" in r else None + op_mode = r["op-mode"] if "op-mode" in r else None + frequency = r["freq"] if "freq" in r else None + flow_id = r["flow_id"] if "flow_id" in r else None + r_type = r["band_type"] if "band_type" in r else None if r_type == "l_slots": band_type = "L_BAND" elif r_type == "s_slots": @@ -263,14 +270,14 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b else: band_type = "C_BAND" - if ob_id is not 0: + if ob_id != 0: val = {"frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "ob_id": ob_id, "band_type": band_type,} else: val = {"frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "band_type": band_type,} custom_rule = ConfigRule_Custom(resource_key="/settings", resource_value=json.dumps(val)) rule = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=custom_rule) service.service_config.config_rules.add().CopyFrom(rule) - log.debug("optical-band rules {}".format(rules_ob)) + if len(rules_ob) > 0: for rulex in rules_ob: rule_ob = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=rulex) diff --git a/src/slice/.gitlab-ci.yml b/src/slice/.gitlab-ci.yml index 39edd20b325c60c40dafddd4dd220b2615042f60..28db8751a4b9f2fa267adcd76fd3ae9bd45c959c 100644 --- a/src/slice/.gitlab-ci.yml +++ b/src/slice/.gitlab-ci.yml @@ -38,47 +38,46 @@ build slice: - manifests/${IMAGE_NAME}service.yaml - .gitlab-ci.yml -# Apply unit test to the component -unit_test slice: - variables: - IMAGE_NAME: 'slice' # name of the microservice - IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) - stage: unit_test - needs: - - build slice - - unit_test service - before_script: - - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - - if docker network list | grep teraflowbridge; then echo "teraflowbridge is already created"; else docker network create -d bridge teraflowbridge; fi - - if docker container ls | grep $IMAGE_NAME; then docker rm -f $IMAGE_NAME; else echo "$IMAGE_NAME image is not in the system"; fi - script: - - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" - - docker run --name $IMAGE_NAME -d -p 4040:4040 -v "$PWD/src/$IMAGE_NAME/tests:/opt/results" --network=teraflowbridge $CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG - - sleep 5 - - docker ps -a - - docker logs $IMAGE_NAME - - docker exec -i $IMAGE_NAME bash -c "coverage run -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary.py --junitxml=/opt/results/${IMAGE_NAME}_report.xml" - - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing" - coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' - after_script: - - docker rm -f $IMAGE_NAME - - docker network rm teraflowbridge - rules: - - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' - - changes: - - src/common/**/*.py - - proto/*.proto - - src/$IMAGE_NAME/**/*.{py,in,yml} - - src/$IMAGE_NAME/Dockerfile - - src/$IMAGE_NAME/tests/*.py - - src/$IMAGE_NAME/tests/Dockerfile - - manifests/${IMAGE_NAME}service.yaml - - .gitlab-ci.yml - artifacts: - when: always - reports: - junit: src/$IMAGE_NAME/tests/${IMAGE_NAME}_report.xml +## Apply unit test to the component +#unit_test slice: +# variables: +# IMAGE_NAME: 'slice' # name of the microservice +# IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) +# stage: unit_test +# needs: +# - build slice +# before_script: +# - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY +# - if docker network list | grep teraflowbridge; then echo "teraflowbridge is already created"; else docker network create -d bridge teraflowbridge; fi +# - if docker container ls | grep $IMAGE_NAME; then docker rm -f $IMAGE_NAME; else echo "$IMAGE_NAME image is not in the system"; fi +# script: +# - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" +# - docker run --name $IMAGE_NAME -d -p 4040:4040 -v "$PWD/src/$IMAGE_NAME/tests:/opt/results" --network=teraflowbridge $CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG +# - sleep 5 +# - docker ps -a +# - docker logs $IMAGE_NAME +# - docker exec -i $IMAGE_NAME bash -c "coverage run -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary.py --junitxml=/opt/results/${IMAGE_NAME}_report.xml" +# - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing" +# coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' +# after_script: +# - docker rm -f $IMAGE_NAME +# - docker network rm teraflowbridge +# rules: +# - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' +# - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' +# - changes: +# - src/common/**/*.py +# - proto/*.proto +# - src/$IMAGE_NAME/**/*.{py,in,yml} +# - src/$IMAGE_NAME/Dockerfile +# - src/$IMAGE_NAME/tests/*.py +# - src/$IMAGE_NAME/tests/Dockerfile +# - manifests/${IMAGE_NAME}service.yaml +# - .gitlab-ci.yml +# artifacts: +# when: always +# reports: +# junit: src/$IMAGE_NAME/tests/${IMAGE_NAME}_report.xml ## Deployment of the service in Kubernetes Cluster #deploy slice: diff --git a/src/slice/service/slice_grouper/MetricsExporter.py b/src/slice/service/slice_grouper/MetricsExporter.py index 3708641eef64e100fae18e875a4fbc4896357057..b884373aabe8827949108a72bcf0e00b1b8e3c83 100644 --- a/src/slice/service/slice_grouper/MetricsExporter.py +++ b/src/slice/service/slice_grouper/MetricsExporter.py @@ -29,8 +29,8 @@ MSG_REST_FAILED = '[rest_request] Query({:s}) failed, retry={:d}/{:d}...' MSG_ERROR_MAX_RETRIES = 'Maximum number of retries achieved: {:d}' METRICSDB_HOSTNAME = os.environ.get('METRICSDB_HOSTNAME') -METRICSDB_ILP_PORT = int(os.environ.get('METRICSDB_ILP_PORT')) -METRICSDB_REST_PORT = int(os.environ.get('METRICSDB_REST_PORT')) +METRICSDB_ILP_PORT = int(os.environ.get('METRICSDB_ILP_PORT', 0)) +METRICSDB_REST_PORT = int(os.environ.get('METRICSDB_REST_PORT', 0)) METRICSDB_TABLE_SLICE_GROUPS = os.environ.get('METRICSDB_TABLE_SLICE_GROUPS') COLORS = { diff --git a/src/slice/tests/test_unitary.py b/src/slice/tests/test_unitary.py index a61ccbcd603cc69025b98051d5480570bd4018ff..17bc6ab02936b2d9fd511694da62e79ac5406686 100644 --- a/src/slice/tests/test_unitary.py +++ b/src/slice/tests/test_unitary.py @@ -12,34 +12,34 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging, os, pytest -from common.Constants import ServiceNameEnum -from common.Settings import ( - ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name, get_service_port_grpc) -from slice.client.SliceClient import SliceClient -from slice.service.SliceService import SliceService +#import logging, os, pytest +#from common.Constants import ServiceNameEnum +#from common.Settings import ( +# ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name, get_service_port_grpc) +#from slice.client.SliceClient import SliceClient +#from slice.service.SliceService import SliceService -LOCAL_HOST = '127.0.0.1' -MOCKSERVICE_PORT = 10000 -SLICE_SERVICE_PORT = MOCKSERVICE_PORT + get_service_port_grpc(ServiceNameEnum.SLICE) # avoid privileged ports -os.environ[get_env_var_name(ServiceNameEnum.SLICE, ENVVAR_SUFIX_SERVICE_HOST )] = str(LOCAL_HOST) -os.environ[get_env_var_name(ServiceNameEnum.SLICE, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(SLICE_SERVICE_PORT) +#LOCAL_HOST = '127.0.0.1' +#MOCKSERVICE_PORT = 10000 +#SLICE_SERVICE_PORT = MOCKSERVICE_PORT + get_service_port_grpc(ServiceNameEnum.SLICE) # avoid privileged ports +#os.environ[get_env_var_name(ServiceNameEnum.SLICE, ENVVAR_SUFIX_SERVICE_HOST )] = str(LOCAL_HOST) +#os.environ[get_env_var_name(ServiceNameEnum.SLICE, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(SLICE_SERVICE_PORT) -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) +#LOGGER = logging.getLogger(__name__) +#LOGGER.setLevel(logging.DEBUG) -@pytest.fixture(scope='session') -def slice_service(): - _service = SliceService() - _service.start() - yield _service - _service.stop() +#@pytest.fixture(scope='session') +#def slice_service(): +# _service = SliceService() +# _service.start() +# yield _service +# _service.stop() -@pytest.fixture(scope='session') -def slice_client(slice_service : SliceService): # pylint: disable=redefined-outer-name - _client = SliceClient() - yield _client - _client.close() +#@pytest.fixture(scope='session') +#def slice_client(slice_service : SliceService): # pylint: disable=redefined-outer-name +# _client = SliceClient() +# yield _client +# _client.close() #def test_add_device_wrong_attributes(slice_client : SliceClient): # # should fail with slice uuid is empty diff --git a/src/tests/ofc24/1.context.json b/src/tests/ofc24/1.context.json new file mode 100755 index 0000000000000000000000000000000000000000..36b3c44fd61fdec9d208a82a11d5a16c3671d004 --- /dev/null +++ b/src/tests/ofc24/1.context.json @@ -0,0 +1,19 @@ +{ + "contexts": [ + { + "context_id": {"context_uuid": {"uuid": "admin"}}, + "topology_ids": [], + "service_ids": [] + } + ], + "topologies": [ + { + "topology_id": { + "context_id": {"context_uuid": {"uuid": "admin"}}, + "topology_uuid": {"uuid": "admin"} + }, + "device_ids": [], + "link_ids": [] + } + ] +} diff --git a/src/tests/ofc24/2.device1.json b/src/tests/ofc24/2.device1.json new file mode 100755 index 0000000000000000000000000000000000000000..3e31f31eb84630415f96b6af1e6ae5d34bdb1c89 --- /dev/null +++ b/src/tests/ofc24/2.device1.json @@ -0,0 +1,91 @@ +{ + "devices": [ + { + "device_id": { + "device_uuid": { + "uuid": "T1" + } + }, + "device_type": "optical-transponder", + "device_drivers": [ + 11 + ], + "device_endpoints": [ + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "T1" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "1" + } + } + } + ], + "device_operational_status": 1, + "device_config": { + "config_rules": [ + { + "action": 1, + "custom": { + "resource_key": "_connect/address", + "resource_value": "10.0.2.15" + } + }, + { + "action": 1, + "custom": { + "resource_key": "_connect/port", + "resource_value": "2023" + } + }, + { + "action": 1, + "custom": { + "resource_key": "_connect/settings", + "resource_value": { + "username": "admin", + "password": "admin", + "force_running": false, + "hostkey_verify": false, + "look_for_keys": false, + "allow_agent": false, + "commit_per_rule": false, + "device_params": { + "name": "default" + }, + "manager_params": { + "timeout": 120 + }, + "endpoints": [ + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "1" + } + ] + } + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/tests/ofc24/3.device2.json b/src/tests/ofc24/3.device2.json new file mode 100755 index 0000000000000000000000000000000000000000..812affa7b8540b67f83d6f3c9bb9b5442c44fd0d --- /dev/null +++ b/src/tests/ofc24/3.device2.json @@ -0,0 +1,91 @@ +{ + "devices": [ + { + "device_id": { + "device_uuid": { + "uuid": "T2" + } + }, + "device_type": "optical-transponder", + "device_drivers": [ + 11 + ], + "device_endpoints": [ + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "T2" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "6" + } + } + } + ], + "device_operational_status": 1, + "device_config": { + "config_rules": [ + { + "action": 1, + "custom": { + "resource_key": "_connect/address", + "resource_value": "10.0.2.15" + } + }, + { + "action": 1, + "custom": { + "resource_key": "_connect/port", + "resource_value": "2024" + } + }, + { + "action": 1, + "custom": { + "resource_key": "_connect/settings", + "resource_value": { + "username": "admin", + "password": "admin", + "force_running": false, + "hostkey_verify": false, + "look_for_keys": false, + "allow_agent": false, + "commit_per_rule": false, + "device_params": { + "name": "default" + }, + "manager_params": { + "timeout": 120 + }, + "endpoints": [ + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "6" + } + ] + } + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/tests/ofc24/4.device3_R1.json b/src/tests/ofc24/4.device3_R1.json new file mode 100755 index 0000000000000000000000000000000000000000..3a57ba79cd2ff8aa6d4b666ac382932ade2f20e0 --- /dev/null +++ b/src/tests/ofc24/4.device3_R1.json @@ -0,0 +1,188 @@ +{ + "devices": [ + { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "device_type": "optical-roadm", + "device_drivers": [ + 11 + ], + "device_endpoints": [ + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "2" + } + } + }, + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "3" + } + } + }, + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "12" + } + } + }, + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "R1" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "13" + } + } + } + ], + "device_operational_status": 1, + "device_config": { + "config_rules": [ + { + "action": 1, + "custom": { + "resource_key": "_connect/address", + "resource_value": "10.0.2.15" + } + }, + { + "action": 1, + "custom": { + "resource_key": "_connect/port", + "resource_value": "2025" + } + }, + { + "action": 1, + "custom": { + "resource_key": "_connect/settings", + "resource_value": { + "username": "admin", + "password": "admin", + "force_running": false, + "hostkey_verify": false, + "look_for_keys": false, + "allow_agent": false, + "commit_per_rule": false, + "device_params": { + "name": "default" + }, + "manager_params": { + "timeout": 120 + }, + "endpoints": [ + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "2" + }, + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "3" + }, + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "12" + }, + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "13" + } + + ] + } + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/tests/ofc24/5.device4_R2.json b/src/tests/ofc24/5.device4_R2.json new file mode 100755 index 0000000000000000000000000000000000000000..9b1968d095c3e2c28c058b22f7295d7d1cbda380 --- /dev/null +++ b/src/tests/ofc24/5.device4_R2.json @@ -0,0 +1,189 @@ +{ + "devices": [ + { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "device_type": "optical-roadm", + "device_drivers": [ + 11 + ], + "device_endpoints": [ + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "4" + } + } + }, + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "5" + } + } + }, + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "14" + } + } + }, + { + "endpoint_id": { + "device_id": { + "device_uuid": { + "uuid": "R2" + } + }, + "topology_id": { + "context_id": { + "context_uuid": { + "uuid": "admin" + } + }, + "topology_uuid": { + "uuid": "admin" + } + }, + "endpoint_uuid": { + "uuid": "15" + } + } + } + + ], + "device_operational_status": 1, + "device_config": { + "config_rules": [ + { + "action": 1, + "custom": { + "resource_key": "_connect/address", + "resource_value": "10.0.2.15" + } + }, + { + "action": 1, + "custom": { + "resource_key": "_connect/port", + "resource_value": "2026" + } + }, + { + "action": 1, + "custom": { + "resource_key": "_connect/settings", + "resource_value": { + "username": "admin", + "password": "admin", + "force_running": false, + "hostkey_verify": false, + "look_for_keys": false, + "allow_agent": false, + "commit_per_rule": false, + "device_params": { + "name": "default" + }, + "manager_params": { + "timeout": 120 + }, + "endpoints": [ + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "4" + }, + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "5" + }, + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "14" + }, + { + "sample_types": [ + 101, + 102, + 201, + 202 + ], + "type": "optical", + "uuid": "15" + } + + ] + } + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/tests/ofc24/6.links.json b/src/tests/ofc24/6.links.json new file mode 100755 index 0000000000000000000000000000000000000000..eb2d004fc8e5484c5ae9eaafa6ec86efb49eb729 --- /dev/null +++ b/src/tests/ofc24/6.links.json @@ -0,0 +1,28 @@ +{ "links": [ + {"link_id": {"link_uuid": {"uuid": "T1->R1"}}, "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}}, + {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "12"}} + ]}, + {"link_id": {"link_uuid": {"uuid": "R1->T1"}}, "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2"}}, + {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}} + ]}, + {"link_id": {"link_uuid": {"uuid": "R1->R2"}}, "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "3"}}, + {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "14"}} + ]}, + {"link_id": {"link_uuid": {"uuid": "R2->R1"}}, "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "4"}}, + {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "13"}} + ]}, + {"link_id": {"link_uuid": {"uuid": "T2->R2"}}, "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}}, + {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "15"}} + ]}, + {"link_id": {"link_uuid": {"uuid": "R2->T2"}}, "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "5"}}, + {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}} + ]} +] + +} diff --git a/src/tests/ofc24/7.service-bidir.json b/src/tests/ofc24/7.service-bidir.json new file mode 100755 index 0000000000000000000000000000000000000000..05547a19d2d375d2a8202266b1a1a5ffcfe46eb6 --- /dev/null +++ b/src/tests/ofc24/7.service-bidir.json @@ -0,0 +1,22 @@ +{ + "services": [ + { + "service_id": { + "context_id": {"context_uuid": {"uuid": "admin"}}, + "service_uuid": {"uuid": "optical-connection"} + }, + "service_type": 6, + "service_status": {"service_status": 1}, + "service_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}}, + {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}} + ], + "service_constraints": [ + {"custom": {"constraint_type": "bandwidth[gbps]", "constraint_value": "100.0"}}, + {"custom": {"constraint_type": "bidirectionality", "constraint_value": "1"}}, + {"custom": {"constraint_type": "optical-band-width[GHz]", "constraint_value": "200"}} + ], + "service_config": {"config_rules": []} + } + ] +} diff --git a/src/tests/ofc24/7.service-unidir.json b/src/tests/ofc24/7.service-unidir.json new file mode 100755 index 0000000000000000000000000000000000000000..d9b4e88479c17aaf03f65d08b8d4b0ca22121e74 --- /dev/null +++ b/src/tests/ofc24/7.service-unidir.json @@ -0,0 +1,22 @@ +{ + "services": [ + { + "service_id": { + "context_id": {"context_uuid": {"uuid": "admin"}}, + "service_uuid": {"uuid": "optical-connection"} + }, + "service_type": 6, + "service_status": {"service_status": 1}, + "service_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}}, + {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}} + ], + "service_constraints": [ + {"custom": {"constraint_type": "bandwidth[gbps]", "constraint_value": "100.0"}}, + {"custom": {"constraint_type": "bidirectionality", "constraint_value": "0"}}, + {"custom": {"constraint_type": "optical-band-width[GHz]", "constraint_value": "200"}} + ], + "service_config": {"config_rules": []} + } + ] +} diff --git a/src/tests/ofc24/README.md b/src/tests/ofc24/README.md new file mode 100644 index 0000000000000000000000000000000000000000..93e95fc642273bf852c829d6fae14cddf8ccba96 --- /dev/null +++ b/src/tests/ofc24/README.md @@ -0,0 +1,21 @@ +# OFC'24 - Test scenario + +## Start Topology +Topology is composed of 2 transponders managed through OpenConfig and 2 Multi-granular ROAMDS +Strat the topology executing the following command: +```bash +sudo ./start_topo.sh +``` + +## Populate the TFS context and topology +Pushing the JSON files following the file indexes, i.e, 1, 2, 3, ... +The last JSON file with ID 7 is the service. +To check the service is onboarded successfully go into the TFS WebUI and check the `Service` tab. + +## Check configuration in devices +Check if the devices are configured properly. +To check that, run, for each device (X={1, 2, 3, 4}): +```bash +screen -r tX +``` +To release the terminal, press `Ctrl + A + D` diff --git a/src/tests/ofc24/plat_r1.xml b/src/tests/ofc24/plat_r1.xml new file mode 100755 index 0000000000000000000000000000000000000000..47e135c2e3752de21dbe2f17550026e9622f4de1 --- /dev/null +++ b/src/tests/ofc24/plat_r1.xml @@ -0,0 +1,120 @@ +<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> + </components> +</config> \ No newline at end of file diff --git a/src/tests/ofc24/plat_r2.xml b/src/tests/ofc24/plat_r2.xml new file mode 100755 index 0000000000000000000000000000000000000000..dfaaf05ad7134a950ec11f411037b9a058b7d719 --- /dev/null +++ b/src/tests/ofc24/plat_r2.xml @@ -0,0 +1,120 @@ +<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>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>D1</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>D1</value> + </config> + </property> + </properties> + </component> + <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create"> + <name>5</name> + <config> + <name>5</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>15</name> + <config> + <name>15</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/startExtraNetConfigAgent.sh b/src/tests/ofc24/startExtraNetConfigAgent.sh new file mode 100755 index 0000000000000000000000000000000000000000..d9428585ef1040bb0440bf6db100b7f2bc71c970 --- /dev/null +++ b/src/tests/ofc24/startExtraNetConfigAgent.sh @@ -0,0 +1,34 @@ +#!/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_CONTAINER=$1 +DOCKER_PORT=$2 + +if [ -n "$DOCKER_CONTAINER" ] && [ -n "$DOCKER_PORT" ];then + sudo docker stop "$DOCKER_CONTAINER" -t 1 + sudo docker rm "$DOCKER_CONTAINER" + + echo "Creating TPs" + screen -dmS t1 -T xterm sh -c "docker run -p 10.0.2.15:"$DOCKER_PORT":2022 -v ~/tfs-ctrl/tempOC/files:/files --name $DOCKER_CONTAINER -it asgamb1/oc23bgp.img:latest" + sleep 2 + if [ "$( docker container inspect -f '{{.State.Running}}' "$DOCKER_CONTAINER")" = "true" ]; then + docker exec "$DOCKER_CONTAINER" cp /files/demoECOC21_4.xml demoECOC21.xml + docker exec "$DOCKER_CONTAINER" /confd/examples.confd/OC23/startNetconfAgent.sh + else + echo "your container is not running yet" + fi +else + echo "Please define the docker container name and port" +fi diff --git a/src/tests/ofc24/start_topo.sh b/src/tests/ofc24/start_topo.sh new file mode 100755 index 0000000000000000000000000000000000000000..c924064763c14e4da45344cd21f4d9c81c9640a9 --- /dev/null +++ b/src/tests/ofc24/start_topo.sh @@ -0,0 +1,63 @@ +#!/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. + +IMAGE_NAME="asgamb1/oc23bgp.img:latest" +DOCKER_CONTAINER=$1 +DOCKER_PORT="2022" + +sudo docker stop na1 -t 1 +sudo docker stop na2 -t 1 +sudo docker stop na3 -t 1 +sudo docker stop na4 -t 1 + +sudo docker rm na2 +sudo docker rm na1 +sudo docker rm na3 +sudo docker rm na4 + +echo "Creating Transponder Agents" + +# if ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1 ; then +# echo "asgamb1/oc23bgp.img:latest not existed ! " +# screen -dmS t3 -T xterm sh -c "docker run -p 10.0.2.15:2025:2022 -v ~/tempOC/files:/files --name na -it $IMAGE_NAME bash" +# echo 'start downloading asgamb1/oc23bgp.img:latest , it may take few minutes ! .... ' +# while [ "$(docker image inspect asgamb1/oc23bgp.img:latest 2>/dev/null)" == "[]" ]; do +# sleep 1 +# done + +#fi + + + +screen -dmS t1 -T xterm sh -c "docker run -p 127.0.0.1:2023:2022 -v ~/tempOC/files:/files --name $DOCKER_CONTAINER -it asgamb1/oc23bgp.img:latest bash" +sleep 2 +if [ "$( docker container inspect -f '{{.State.Running}}' "$DOCKER_CONTAINER")" = "true" ]; then + docker exec "$DOCKER_CONTAINER" cp /files/demoECOC21_4.xml demoECOC21.xml + docker exec "$DOCKER_CONTAINER" /confd/examples.confd/OC23/startNetconfAgent.sh +else + echo "your container is not running yet" +fi + +echo " It may take a while , Hang on ..." +source "./startExtraNetConfigAgent.sh" "na1" "2023" +sleep 3 + +source "./startExtraNetConfigAgent.sh" "na2" "2024" +sleep 3 + +bash -c "cp /tempOC/files/plat_r1.xml /confd/examples.confd/OC23/init_openconfig-platform.xml; ./startNetconfAgent.sh" +bash -c "cp /tempOC/files/plat_r2.xml /confd/examples.confd/OC23/init_openconfig-platform.xml; ./startNetconfAgent.sh" +screen -dmS t3 -T xterm sh -c 'docker run -p 10.0.2.15:2025:2022 -v ~/tfs-ctrl/tempOC/files:/files --name na3 -it asgamb1/flexscale-node.img:latest ./startNetconfAgent.sh' +screen -dmS t4 -T xterm sh -c 'docker run -p 10.0.2.15:2026:2022 -v ~/tfs-ctrl/tempOC/files:/files --name na4 -it asgamb1/flexscale-node.img:latest ./startNetconfAgent.sh' diff --git a/src/tests/ofc24/t1.xml b/src/tests/ofc24/t1.xml new file mode 100755 index 0000000000000000000000000000000000000000..712615df8dd821ff8e79df9785d6d29324a25b7d --- /dev/null +++ b/src/tests/ofc24/t1.xml @@ -0,0 +1,298 @@ +<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <components xmlns="http://openconfig.net/yang/platform"> + <component> + <name>device</name> + <config> + <name>device</name> + </config> + <state> + <name>MellanoxSwitch</name> + <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> + <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:OPERATING_SYSTEM</type> + </state> + </component> + <component> + <name>channel-1</name> + <config> + <name>channel-1</name> + </config> + <state> + <name>channel-1</name> + <type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type> + </state> + <optical-channel xmlns="http://openconfig.net/yang/terminal-device"> + <config> + <frequency>191600000</frequency> + <target-output-power>100</target-output-power> + <operational-mode>0</operational-mode> + <line-port>transceiver-1</line-port> + </config> + <state> + <frequency>191600000</frequency> + <target-output-power>0</target-output-power> + <operational-mode>0</operational-mode> + <line-port>transceiver-1</line-port> + <group-id>1</group-id> + <output-power> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + <interval>0</interval> + </output-power> + <input-power> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + <interval>0</interval> + </input-power> + <laser-bias-current> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + <interval>0</interval> + </laser-bias-current> + <chromatic-dispersion> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + </chromatic-dispersion> + <polarization-mode-dispersion> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + </polarization-mode-dispersion> + <second-order-polarization-mode-dispersion> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + </second-order-polarization-mode-dispersion> + <polarization-dependent-loss> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + <interval>0</interval> + </polarization-dependent-loss> + </state> + </optical-channel> + </component> + <component> + <name>transceiver-1</name> + <config> + <name>transceiver-1</name> + </config> + <state> + <name>transceiver-1</name> + <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type> + </state> + <transceiver xmlns="http://openconfig.net/yang/platform/transceiver"> + <config> + <enabled>true</enabled> + <form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf> + <ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf> + <fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode> + <module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type> + </config> + <state> + <enabled>true</enabled> + <form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf> + <ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf> + <fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode> + <module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex: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> + <!--state> + <index>1</index> + <associated-optical-channel>channel-4</associated-optical-channel> + </state--> + </channel> + </physical-channels> + </transceiver> + </component> + <component> + <name>port-1</name> + <config> + <name>port-1</name> + </config> + <state> + <name>port-1</name> + <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type> + </state> + <subcomponents> + <subcomponent> + <name>channel-1</name> + <config> + <name>channel-1</name> + </config> + <state> + <name>channel-1</name> + </state> + </subcomponent> + </subcomponents> + <properties> + <property> + <name>onos-index</name> + <config> + <name>onos-index</name> + <value>4</value> + </config> + <state> + <name>onos-index</name> + <value>4</value> + </state> + </property> + <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> + </properties> + </component> + + + </components> + <terminal-device xmlns="http://openconfig.net/yang/terminal-device"> + <logical-channels> + <!--Description: Optical logical link--> + <channel> + + <!--Description: Line (OTN) Port--> + <index>1</index> + <config> + <index>1</index> + <description>Logical channel 1</description> + <admin-state>DISABLED</admin-state> + <logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type: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:type="http://openconfig.net/yang/transport-types">type: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> + <otn> + <config> + <tti-msg-expected>test1</tti-msg-expected> + <tti-msg-transmit>test1</tti-msg-transmit> + </config> + <state> + <tti-msg-expected>test1</tti-msg-expected> + <tti-msg-transmit>test1</tti-msg-transmit> + <tti-msg-auto>0</tti-msg-auto> + <tti-msg-recv>0</tti-msg-recv> + <rdi-msg>0</rdi-msg> + <errored-seconds>0</errored-seconds> + <severely-errored-seconds>0</severely-errored-seconds> + <unavailable-seconds>0</unavailable-seconds> + <code-violations>0</code-violations> + <fec-uncorrectable-words>0</fec-uncorrectable-words> + <fec-corrected-bytes>0</fec-corrected-bytes> + <fec-corrected-bits>0</fec-corrected-bits> + <background-block-errors>0</background-block-errors> + <pre-fec-ber> + <instant>0.0</instant> + <avg>0.0</avg> + <min>0.0</min> + <max>0.0</max> + </pre-fec-ber> + <post-fec-ber> + <instant>0.0</instant> + <avg>0.0</avg> + <min>0.0</min> + <max>0.0</max> + </post-fec-ber> + <q-value> + <instant>0.0</instant> + <avg>0.0</avg> + <min>0.0</min> + <max>0.0</max> + <interval>0</interval> + </q-value> + <esnr> + <instant>0.0</instant> + <avg>0.0</avg> + <min>0.0</min> + <max>0.0</max> + <interval>0</interval> + </esnr> + </state> + </otn> + <logical-channel-assignments> + <assignment> + <index>1</index> + <config> + <index>1</index> + <description>Optical channel assigned 100</description> + <allocation>100</allocation> + <assignment-type>OPTICAL_CHANNEL</assignment-type> + <optical-channel>channel-1</optical-channel> + </config> + <state> + <index>1</index> + <description>Optical channel assigned 100</description> + <allocation>100</allocation> + <assignment-type>OPTICAL_CHANNEL</assignment-type> + <optical-channel>channel-1</optical-channel> + </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> +</config> + diff --git a/src/tests/ofc24/t2.xml b/src/tests/ofc24/t2.xml new file mode 100755 index 0000000000000000000000000000000000000000..3a35e7e87eac7b14cd2bfa693560cc653f3719b9 --- /dev/null +++ b/src/tests/ofc24/t2.xml @@ -0,0 +1,298 @@ +<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <components xmlns="http://openconfig.net/yang/platform"> + <component> + <name>device</name> + <config> + <name>device</name> + </config> + <state> + <name>MellanoxSwitch</name> + <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> + <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:OPERATING_SYSTEM</type> + </state> + </component> + <component> + <name>channel-6</name> + <config> + <name>channel-6</name> + </config> + <state> + <name>channel-6</name> + <type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type> + </state> + <optical-channel xmlns="http://openconfig.net/yang/terminal-device"> + <config> + <frequency>191600000</frequency> + <target-output-power>100</target-output-power> + <operational-mode>0</operational-mode> + <line-port>transceiver-6</line-port> + </config> + <state> + <frequency>191600000</frequency> + <target-output-power>0</target-output-power> + <operational-mode>0</operational-mode> + <line-port>transceiver-6</line-port> + <group-id>1</group-id> + <output-power> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + <interval>0</interval> + </output-power> + <input-power> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + <interval>0</interval> + </input-power> + <laser-bias-current> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + <interval>0</interval> + </laser-bias-current> + <chromatic-dispersion> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + </chromatic-dispersion> + <polarization-mode-dispersion> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + </polarization-mode-dispersion> + <second-order-polarization-mode-dispersion> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + </second-order-polarization-mode-dispersion> + <polarization-dependent-loss> + <instant>0</instant> + <avg>0</avg> + <min>0</min> + <max>0</max> + <interval>0</interval> + </polarization-dependent-loss> + </state> + </optical-channel> + </component> + <component> + <name>transceiver-6</name> + <config> + <name>transceiver-6</name> + </config> + <state> + <name>transceiver-6</name> + <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type> + </state> + <transceiver xmlns="http://openconfig.net/yang/platform/transceiver"> + <config> + <enabled>true</enabled> + <form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf> + <ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf> + <fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode> + <module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type> + </config> + <state> + <enabled>true</enabled> + <form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf> + <ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf> + <fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode> + <module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex: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-6</associated-optical-channel> + </config> + <!--state> + <index>1</index> + <associated-optical-channel>channel-4</associated-optical-channel> + </state--> + </channel> + </physical-channels> + </transceiver> + </component> + <component> + <name>port-6</name> + <config> + <name>port-6</name> + </config> + <state> + <name>port-6</name> + <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type> + </state> + <subcomponents> + <subcomponent> + <name>channel-6</name> + <config> + <name>channel-6</name> + </config> + <state> + <name>channel-6</name> + </state> + </subcomponent> + </subcomponents> + <properties> + <property> + <name>onos-index</name> + <config> + <name>onos-index</name> + <value>4</value> + </config> + <state> + <name>onos-index</name> + <value>4</value> + </state> + </property> + <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> + </properties> + </component> + + + </components> + <terminal-device xmlns="http://openconfig.net/yang/terminal-device"> + <logical-channels> + <!--Description: Optical logical link--> + <channel> + + <!--Description: Line (OTN) Port--> + <index>4</index> + <config> + <index>4</index> + <description>Logical channel 4</description> + <admin-state>DISABLED</admin-state> + <logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type> + <loopback-mode>NONE</loopback-mode> + </config> + <state> + <index>4</index> + <description>Logical channel 4</description> + <admin-state>DISABLED</admin-state> + <logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type> + <loopback-mode>NONE</loopback-mode> + <link-state>UP</link-state> + </state> + <ingress> + <config> + <transceiver>transceiver-6</transceiver> + </config> + <state> + <transceiver>transceiver-6</transceiver> + </state> + </ingress> + <otn> + <config> + <tti-msg-expected>test1</tti-msg-expected> + <tti-msg-transmit>test1</tti-msg-transmit> + </config> + <state> + <tti-msg-expected>test1</tti-msg-expected> + <tti-msg-transmit>test1</tti-msg-transmit> + <tti-msg-auto>0</tti-msg-auto> + <tti-msg-recv>0</tti-msg-recv> + <rdi-msg>0</rdi-msg> + <errored-seconds>0</errored-seconds> + <severely-errored-seconds>0</severely-errored-seconds> + <unavailable-seconds>0</unavailable-seconds> + <code-violations>0</code-violations> + <fec-uncorrectable-words>0</fec-uncorrectable-words> + <fec-corrected-bytes>0</fec-corrected-bytes> + <fec-corrected-bits>0</fec-corrected-bits> + <background-block-errors>0</background-block-errors> + <pre-fec-ber> + <instant>0.0</instant> + <avg>0.0</avg> + <min>0.0</min> + <max>0.0</max> + </pre-fec-ber> + <post-fec-ber> + <instant>0.0</instant> + <avg>0.0</avg> + <min>0.0</min> + <max>0.0</max> + </post-fec-ber> + <q-value> + <instant>0.0</instant> + <avg>0.0</avg> + <min>0.0</min> + <max>0.0</max> + <interval>0</interval> + </q-value> + <esnr> + <instant>0.0</instant> + <avg>0.0</avg> + <min>0.0</min> + <max>0.0</max> + <interval>0</interval> + </esnr> + </state> + </otn> + <logical-channel-assignments> + <assignment> + <index>1</index> + <config> + <index>1</index> + <description>Optical channel assigned 100</description> + <allocation>100</allocation> + <assignment-type>OPTICAL_CHANNEL</assignment-type> + <optical-channel>channel-6</optical-channel> + </config> + <state> + <index>1</index> + <description>Optical channel assigned 100</description> + <allocation>100</allocation> + <assignment-type>OPTICAL_CHANNEL</assignment-type> + <optical-channel>channel-6</optical-channel> + </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> +</config> + diff --git a/src/webui/.gitlab-ci.yml b/src/webui/.gitlab-ci.yml index 26af10f4e5b3ab23fcd0802ba6df9d2ad3bf7a19..59d21dfb6ff89d441d55ff392f20a9a746a378fe 100644 --- a/src/webui/.gitlab-ci.yml +++ b/src/webui/.gitlab-ci.yml @@ -39,7 +39,7 @@ build webui: - .gitlab-ci.yml # Apply unit test to the component -unit test webui: +unit_test webui: variables: IMAGE_NAME: 'webui' # name of the microservice IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) @@ -79,28 +79,28 @@ unit test webui: reports: junit: src/$IMAGE_NAME/tests/${IMAGE_NAME}_report.xml -# Deployment of the service in Kubernetes Cluster -deploy webui: - variables: - IMAGE_NAME: 'webui' # name of the microservice - IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) - stage: deploy - needs: - - unit test webui - # - integ_test execute - script: - - 'sed -i "s/$IMAGE_NAME:.*/$IMAGE_NAME:$IMAGE_TAG/" manifests/${IMAGE_NAME}service.yaml' - - kubectl version - - kubectl get all - - kubectl apply -f "manifests/${IMAGE_NAME}service.yaml" - - kubectl get all - # environment: - # name: test - # url: https://example.com - # kubernetes: - # namespace: test - rules: - - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' - when: manual - - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' - when: manual +## Deployment of the service in Kubernetes Cluster +#deploy webui: +# variables: +# IMAGE_NAME: 'webui' # name of the microservice +# IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) +# stage: deploy +# needs: +# - unit test webui +# # - integ_test execute +# script: +# - 'sed -i "s/$IMAGE_NAME:.*/$IMAGE_NAME:$IMAGE_TAG/" manifests/${IMAGE_NAME}service.yaml' +# - kubectl version +# - kubectl get all +# - kubectl apply -f "manifests/${IMAGE_NAME}service.yaml" +# - kubectl get all +# # environment: +# # name: test +# # url: https://example.com +# # kubernetes: +# # namespace: test +# rules: +# - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' +# when: manual +# - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' +# when: manual diff --git a/src/webui/service/static/topology_icons/Acknowledgements.txt b/src/webui/service/static/topology_icons/Acknowledgements.txt index 08e9ed27ce3e87e05d8d1d1176704b53b93c8ef3..6398f34a7c7d6a632c954bd7b9f5bffb690aa83b 100644 --- a/src/webui/service/static/topology_icons/Acknowledgements.txt +++ b/src/webui/service/static/topology_icons/Acknowledgements.txt @@ -37,3 +37,4 @@ https://symbols.getvecta.com/stencil_241/154_laptop.c01910b6c8.png => emu-client https://symbols.getvecta.com/stencil_240/16_atm-tag-switch-router.3149d7e933.png => ip-sdn-controller.png https://symbols.getvecta.com/stencil_241/46_atm-tag-sw-rtr.776719c0b0.png => emu-ip-sdn-controller.png +https://onfstaging1.opennetworking.org/wp-content/uploads/2020/02/p4-transparent-logo.png => p4-switch.png diff --git a/src/webui/service/static/topology_icons/p4-switch.png b/src/webui/service/static/topology_icons/p4-switch.png new file mode 100644 index 0000000000000000000000000000000000000000..9afcda1c0e38cb5757574024f1a3f96001b03943 Binary files /dev/null and b/src/webui/service/static/topology_icons/p4-switch.png differ diff --git a/src/webui/service/templates/bgpls/home.html b/src/webui/service/templates/bgpls/home.html index 15bfc0fcd62a1bf9222ca209b2fd08d9a061fc06..d0f074b2ae11d0cd45346d4c3894eb9be30d3865 100644 --- a/src/webui/service/templates/bgpls/home.html +++ b/src/webui/service/templates/bgpls/home.html @@ -77,7 +77,7 @@ </tr> {% endif %} </tbody> - <tbody> + <!-- <tbody> {% if dislink %} {% for link in dislink %} <tr> @@ -100,7 +100,7 @@ <td colspan="3">No devices found</td> </tr> {% endif %} - </tbody> + </tbody> --> </table> <script src="https://d3js.org/d3.v4.min.js"></script>