diff --git a/manifests/pcepservice.yaml b/manifests/pcepservice.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d2e82abffe034a92d913a619da9b0a8333b06d58 --- /dev/null +++ b/manifests/pcepservice.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: pcepservice +spec: + selector: + matchLabels: + app: pcepservice + replicas: 1 + template: + metadata: + labels: + app: pcepservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: localhost:32000/tfs/pcep:dev + imagePullPolicy: Always + ports: + - containerPort: 10050 + - containerPort: 9192 + env: + - name: LOG_LEVEL + value: "DEBUG" + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:10050"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:10050"] + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 500m + memory: 512Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: pcepservice + labels: + app: pcepservice +spec: + type: ClusterIP + selector: + app: pcepservice + ports: + - name: grpc + protocol: TCP + port: 10050 + targetPort: 10050 + - name: metrics + protocol: TCP + port: 9192 + targetPort: 9192 diff --git a/proto/context.proto b/proto/context.proto index 3104f1b545c02bab71c8638ebba03efdcbfe71ff..e7e2aa3fa88b9af4e477c5ccdb0322616d2ff834 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -34,6 +34,14 @@ service ContextService { rpc RemoveTopology (TopologyId ) returns ( Empty ) {} rpc GetTopologyEvents (Empty ) returns (stream TopologyEvent ) {} + rpc ListInventoryIds (Empty ) returns ( InventoryIdList ) {} + rpc ListInventory (Empty ) returns ( InventoryList ) {} + rpc ListInventoryNames (InventoryIdList) returns( InventoryNameList ) {} + rpc GetInventory (InventoryId ) returns ( Inventory ) {} + rpc SetInventory (Inventory ) returns ( InventoryId ) {} + rpc RemoveInventory (InventoryId ) returns ( Empty ) {} + rpc GetInventoryEvents (InventoryId ) returns (stream InventoryEvent ) {} + rpc ListDeviceIds (Empty ) returns ( DeviceIdList ) {} rpc ListDevices (Empty ) returns ( DeviceList ) {} rpc GetDevice (DeviceId ) returns ( Device ) {} @@ -174,12 +182,17 @@ message Device { DeviceOperationalStatusEnum device_operational_status = 5; repeated DeviceDriverEnum device_drivers = 6; repeated EndPoint device_endpoints = 7; - repeated Component component = 8; // Used for inventory - DeviceId controller_id = 9; // Identifier of node controlling the actual device + // Used for inventory: + map<string, Component> components = 8; // dict[comp.name => Component] + DeviceId controller_id = 9; // Identifier of node controlling the actual device } message Component { - repeated string comp_string = 1; + Uuid uuid = 1; + string name = 2; + string type = 3; + repeated string child = 4; // list[sub-component.name] + map<string, string> attributes = 5; // dict[attr.name => json.dumps(attr.value)] } message DeviceConfig { @@ -589,3 +602,42 @@ message AuthenticationResult { ContextId context_id = 1; bool authenticated = 2; } + +// -----Inventory ------------------------------------------------------------------------------------------------------ +message InventoryId{ + TopologyId topology_id = 1; + DeviceId device_id = 2; + Uuid inventory_uuid = 3; +} + +message Inventory{ + InventoryId inventory_id = 1; + string name = 2; + string inventory_type = 3; + repeated kpi_sample_types.KpiSampleType kpi_sample_types = 4; + string datos = 5; +} + +message InventoryName { + InventoryId inventory_id = 1; + string device_name = 2; + string inventory_name = 3; + string inventory_type = 4; +} + +message InventoryIdList { + repeated InventoryId inventory_ids = 1; +} + +message InventoryNameList { + repeated InventoryName inventory_names = 1; +} + +message InventoryList { + repeated Inventory inventory = 1; +} + +message InventoryEvent { + Inventory event = 1; + InventoryId inventory_id = 2; +} \ No newline at end of file diff --git a/proto/pcep.proto b/proto/pcep.proto new file mode 100644 index 0000000000000000000000000000000000000000..c238e24bb43e54ecfd3a3c26bfdd381ad7a87b4f --- /dev/null +++ b/proto/pcep.proto @@ -0,0 +1,40 @@ +// Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; +package pcep; + + +service PcepService { + rpc sendRequest ( RequestRq ) returns ( RequestRp ) {} + rpc configuratePCE ( PceIpRq ) returns ( PceIpRp ) {} +} + +message RequestRq { + string command = 1; +} + +message RequestRp { + string commandRp = 1; +} + +message PceIpRq { + string address=1; + string port= 2; + string asNumber=3; +} + +message PceIpRp{ + string addressRp=1; +} diff --git a/src/common/Constants.py b/src/common/Constants.py index ed1c1475ad3c69cfb9bd650f0d99f33c6cf0f2bc..5db459168a442b482333c5deb6bff59f724e587f 100644 --- a/src/common/Constants.py +++ b/src/common/Constants.py @@ -56,6 +56,7 @@ class ServiceNameEnum(Enum): OPTICALATTACKDETECTOR = 'opticalattackdetector' OPTICALATTACKMITIGATOR = 'opticalattackmitigator' CACHING = 'caching' + PCEP = 'pcep' # Used for test and debugging only DLT_GATEWAY = 'dltgateway' @@ -80,6 +81,7 @@ DEFAULT_SERVICE_GRPC_PORTS = { ServiceNameEnum.OPTICALATTACKMANAGER .value : 10005, ServiceNameEnum.INTERDOMAIN .value : 10010, ServiceNameEnum.PATHCOMP .value : 10020, + ServiceNameEnum.PCEP .value : 10050, # Used for test and debugging only ServiceNameEnum.DLT_GATEWAY .value : 50051, diff --git a/src/pcep/.gitlab-ci.yml b/src/pcep/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..c8f765c8702e2f063a207fb9ddca4ba31b57a35c --- /dev/null +++ b/src/pcep/.gitlab-ci.yml @@ -0,0 +1,224 @@ +# 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. + +# Build, tag, and push the Docker image to the GitLab Docker registry +build service: + variables: + IMAGE_NAME: 'pcep' # name of the microservice + IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) + stage: build + before_script: + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + script: + - docker build -t "$IMAGE_NAME:$IMAGE_TAG" -f ./src/$IMAGE_NAME/Dockerfile . + - docker tag "$IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" + - docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" + after_script: + - docker images --filter="dangling=true" --quiet | xargs -r docker rmi + 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 + +# Apply unit test to the component +unit_test service: + variables: + IMAGE_NAME: 'pcep' # name of the microservice + IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) + stage: unit_test + needs: + - build 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 --driver=bridge teraflowbridge; fi + + # Context-related + - if docker container ls | grep crdb; then docker rm -f crdb; else echo "CockroachDB container is not in the system"; fi + - if docker volume ls | grep crdb; then docker volume rm -f crdb; else echo "CockroachDB volume is not in the system"; fi + - if docker container ls | grep nats; then docker rm -f nats; else echo "NATS container is not in the system"; fi + + # Device-related + - if docker container ls | grep context; then docker rm -f context; else echo "context image is not in the system"; fi + - if docker container ls | grep device; then docker rm -f device; else echo "device image is not in the system"; fi + + # Pathcomp-related + - if docker container ls | grep pathcomp-frontend; then docker rm -f pathcomp-frontend; else echo "pathcomp-frontend image is not in the system"; fi + - if docker container ls | grep pathcomp-backend; then docker rm -f pathcomp-backend; else echo "pathcomp-backend image is not in the system"; fi + + # Service-related + - 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 "cockroachdb/cockroach:latest-v22.2" + - docker pull "nats:2.9" + - docker pull "$CI_REGISTRY_IMAGE/context:$IMAGE_TAG" + - docker pull "$CI_REGISTRY_IMAGE/device:$IMAGE_TAG" + - docker pull "$CI_REGISTRY_IMAGE/pathcomp-frontend:$IMAGE_TAG" + - docker pull "$CI_REGISTRY_IMAGE/pathcomp-backend:$IMAGE_TAG" + - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" + + # Context preparation + - docker volume create crdb + - > + docker run --name crdb -d --network=teraflowbridge -p 26257:26257 -p 8080:8080 + --env COCKROACH_DATABASE=tfs_test --env COCKROACH_USER=tfs --env COCKROACH_PASSWORD=tfs123 + --volume "crdb:/cockroach/cockroach-data" + cockroachdb/cockroach:latest-v22.2 start-single-node + - > + docker run --name nats -d --network=teraflowbridge -p 4222:4222 -p 8222:8222 + nats:2.9 --http_port 8222 --user tfs --pass tfs123 + - echo "Waiting for initialization..." + - while ! docker logs crdb 2>&1 | grep -q 'finished creating default user \"tfs\"'; do sleep 1; done + - docker logs crdb + - while ! docker logs nats 2>&1 | grep -q 'Server is ready'; do sleep 1; done + - docker logs nats + - docker ps -a + - CRDB_ADDRESS=$(docker inspect crdb --format "{{.NetworkSettings.Networks.teraflowbridge.IPAddress}}") + - echo $CRDB_ADDRESS + - NATS_ADDRESS=$(docker inspect nats --format "{{.NetworkSettings.Networks.teraflowbridge.IPAddress}}") + - echo $NATS_ADDRESS + - > + docker run --name context -d -p 1010:1010 + --env "CRDB_URI=cockroachdb://tfs:tfs123@${CRDB_ADDRESS}:26257/tfs_test?sslmode=require" + --env "MB_BACKEND=nats" + --env "NATS_URI=nats://tfs:tfs123@${NATS_ADDRESS}:4222" + --network=teraflowbridge + $CI_REGISTRY_IMAGE/context:$IMAGE_TAG + - CONTEXTSERVICE_SERVICE_HOST=$(docker inspect context --format "{{.NetworkSettings.Networks.teraflowbridge.IPAddress}}") + - echo $CONTEXTSERVICE_SERVICE_HOST + + # Device preparation + - > + docker run --name device -d -p 2020:2020 + --env "CONTEXTSERVICE_SERVICE_HOST=${CONTEXTSERVICE_SERVICE_HOST}" + --network=teraflowbridge + $CI_REGISTRY_IMAGE/device:$IMAGE_TAG + - DEVICESERVICE_SERVICE_HOST=$(docker inspect device --format "{{.NetworkSettings.Networks.teraflowbridge.IPAddress}}") + - echo $DEVICESERVICE_SERVICE_HOST + + # PathComp preparation + - > + docker run --name pathcomp-backend -d -p 8081:8081 + --network=teraflowbridge + $CI_REGISTRY_IMAGE/pathcomp-backend:$IMAGE_TAG + - PATHCOMP_BACKEND_HOST=$(docker inspect pathcomp-backend --format "{{.NetworkSettings.Networks.teraflowbridge.IPAddress}}") + - echo $PATHCOMP_BACKEND_HOST + - sleep 1 + - > + docker run --name pathcomp-frontend -d -p 10020:10020 + --env "CONTEXTSERVICE_SERVICE_HOST=${CONTEXTSERVICE_SERVICE_HOST}" + --env "PATHCOMP_BACKEND_HOST=${PATHCOMP_BACKEND_HOST}" + --env "PATHCOMP_BACKEND_PORT=8081" + --network=teraflowbridge + $CI_REGISTRY_IMAGE/pathcomp-frontend:$IMAGE_TAG + - sleep 1 + - PATHCOMPSERVICE_SERVICE_HOST=$(docker inspect pathcomp-frontend --format "{{.NetworkSettings.Networks.teraflowbridge.IPAddress}}") + - echo $PATHCOMPSERVICE_SERVICE_HOST + + # Service preparation + - > + docker run --name $IMAGE_NAME -d -p 3030:3030 + --env "CONTEXTSERVICE_SERVICE_HOST=${CONTEXTSERVICE_SERVICE_HOST}" + --env "DEVICESERVICE_SERVICE_HOST=${DEVICESERVICE_SERVICE_HOST}" + --env "PATHCOMPSERVICE_SERVICE_HOST=${PATHCOMPSERVICE_SERVICE_HOST}" + --volume "$PWD/src/$IMAGE_NAME/tests:/opt/results" + --network=teraflowbridge + $CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG + + # Check status before the tests + - sleep 5 + - docker ps -a + - docker logs context + - docker logs device + - docker logs pathcomp-frontend + - docker logs pathcomp-backend + - docker logs $IMAGE_NAME + + # Run the tests + - > + 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: + # Check status after the tests + - docker ps -a + - docker logs context + - docker logs device + - docker logs pathcomp-frontend + - docker logs pathcomp-backend + - docker logs $IMAGE_NAME + + - docker rm -f $IMAGE_NAME + - docker rm -f pathcomp-frontend + - docker rm -f pathcomp-backend + - docker rm -f device + - docker rm -f context + + - docker rm -f $IMAGE_NAME crdb nats + - docker volume rm -f crdb + - docker network rm teraflowbridge + - docker volume prune --force + - docker image prune --force + + 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 service: +# variables: +# IMAGE_NAME: 'service' # name of the microservice +# IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) +# stage: deploy +# needs: +# - unit test service +# # - 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/pcep/Config.py b/src/pcep/Config.py new file mode 100644 index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612 --- /dev/null +++ b/src/pcep/Config.py @@ -0,0 +1,14 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/pcep/Dockerfile b/src/pcep/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..0229d098d409eb89c27c7cc6efb89e6bf4a3238a --- /dev/null +++ b/src/pcep/Dockerfile @@ -0,0 +1,82 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM python:3.9-slim + +# Install dependencies +RUN apt-get --yes --quiet --quiet update && \ + apt-get --yes --quiet --quiet install wget g++ && \ + rm -rf /var/lib/apt/lists/* + +# Set Python to show logs as they occur +ENV PYTHONUNBUFFERED=0 + +# Download the gRPC health probe +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ + wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ + chmod +x /bin/grpc_health_probe + +# Get generic Python packages +RUN python3 -m pip install --upgrade pip +RUN python3 -m pip install --upgrade setuptools wheel +RUN python3 -m pip install --upgrade pip-tools + +# Install OpenJDK-11 +RUN apt-get update && \ + apt-get install -y openjdk-11-jre-headless && \ + apt-get clean; + +# Get common Python packages +# Note: this step enables sharing the previous Docker build steps among all the Python components +WORKDIR /var/teraflow +COPY common_requirements.in common_requirements.in +RUN pip-compile --quiet --output-file=common_requirements.txt common_requirements.in +RUN python3 -m pip install -r common_requirements.txt + +# Add common files into working directory +WORKDIR /var/teraflow/common +COPY src/common/. ./ +RUN rm -rf proto + +# Create proto sub-folder, copy .proto files, and generate Python code +RUN mkdir -p /var/teraflow/common/proto +WORKDIR /var/teraflow/common/proto +RUN touch __init__.py +COPY proto/*.proto ./ +RUN python3 -m grpc_tools.protoc -I=. --python_out=. --grpc_python_out=. *.proto +RUN rm *.proto +RUN find . -type f -exec sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' {} \; + +# Create component sub-folders, get specific Python packages +RUN mkdir -p /var/teraflow/pcep +WORKDIR /var/teraflow/pcep +COPY src/pcep/requirements.in requirements.in +RUN pip-compile --quiet --output-file=requirements.txt requirements.in +RUN python3 -m pip install -r requirements.txt + +# Java module necessary config files +WORKDIR /var/teraflow/pcep +RUN mkdir -p /resources +COPY src/pcep/service/resources/. resources/ + +# Add component files into working directory +WORKDIR /var/teraflow +COPY src/context/. context/ +COPY src/device/. device/ +COPY src/pathcomp/frontend/. pathcomp/frontend/ +COPY src/service/. service/ +COPY src/pcep/. pcep/ + +# Start the service +ENTRYPOINT ["python", "-m", "pcep.service"] diff --git a/src/pcep/__init__.py b/src/pcep/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612 --- /dev/null +++ b/src/pcep/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/pcep/client/PcepClient.py b/src/pcep/client/PcepClient.py new file mode 100644 index 0000000000000000000000000000000000000000..057844e70b59a59a4bade4572a7f274acfa75dfd --- /dev/null +++ b/src/pcep/client/PcepClient.py @@ -0,0 +1,63 @@ +# 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 grpc, logging +from common.Constants import ServiceNameEnum +from common.Settings import get_service_host, get_service_port_grpc +from common.proto.context_pb2 import Empty, Service, ServiceId +from common.proto.pcep_pb2_grpc import PcepServiceStub +from common.proto.pcep_pb2 import RequestRq, RequestRp, PceIpRq, PceIpRp +from common.tools.client.RetryDecorator import retry, delay_exponential +from common.tools.grpc.Tools import grpc_message_to_json_string + +LOGGER = logging.getLogger(__name__) +MAX_RETRIES = 15 +DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0) +RETRY_DECORATOR = retry(max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect') + +class PcepClient: + def __init__(self, host=None, port=None): + if not host: host = get_service_host(ServiceNameEnum.PCEP) + if not port: port = get_service_port_grpc(ServiceNameEnum.PCEP) + self.endpoint = '{:s}:{:s}'.format(str(host), str(port)) + LOGGER.debug('Creating channel to {:s}...'.format(str(self.endpoint))) + self.channel = None + self.stub = None + self.connect() + LOGGER.debug('Channel created') + + def connect(self): + self.channel = grpc.insecure_channel(self.endpoint) + self.stub = PcepServiceStub(self.channel) + + def close(self): + if self.channel is not None: self.channel.close() + self.channel = None + self.stub = None + + @RETRY_DECORATOR + def sendRequest(self, request : RequestRq) -> RequestRp: + LOGGER.debug('Send request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.sendRequest(request) + LOGGER.debug('Send request result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + @RETRY_DECORATOR + def configuratePCE(self, request : PceIpRq) -> PceIpRp: + LOGGER.debug('Configurate PCE: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.configuratePCE(request) + LOGGER.debug('Configurate PCE result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + diff --git a/src/pcep/client/__init__.py b/src/pcep/client/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612 --- /dev/null +++ b/src/pcep/client/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/pcep/requirements.in b/src/pcep/requirements.in new file mode 100644 index 0000000000000000000000000000000000000000..bffe88732b108cd5da3bf6331d6a8c3056ccaf02 --- /dev/null +++ b/src/pcep/requirements.in @@ -0,0 +1,34 @@ +# 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. + + +anytree==2.8.0 +APScheduler==3.8.1 +#networkx==2.6.3 +#pydot==1.4.2 +#redis==4.1.2 + +#fastcache==1.1.0 +ncclient==0.6.13 +python-json-logger==2.0.2 +pytz==2021.3 +xmltodict==0.12.0 + + +# pip's dependency resolver does not take into account installed packages. +# p4runtime does not specify the version of grpcio/protobuf it needs, so it tries to install latest one +# adding here again grpcio==1.47.* and protobuf==3.20.* with explicit versions to prevent collisions +grpcio==1.47.* +protobuf==3.20.* +prometheus_client==0.13.0 \ No newline at end of file diff --git a/src/pcep/service/PcepService.py b/src/pcep/service/PcepService.py new file mode 100644 index 0000000000000000000000000000000000000000..b6e9004044a1425f515bab396a43171920a73b23 --- /dev/null +++ b/src/pcep/service/PcepService.py @@ -0,0 +1,29 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from pcep.service.tools.GrpcServer import GrpcServer +from common.Constants import ServiceNameEnum +from common.Settings import get_service_port_grpc +from common.proto.pcep_pb2_grpc import add_PcepServiceServicer_to_server +from common.tools.service.GenericGrpcService import GenericGrpcService +from .PcepServiceServicerImpl import PcepServiceServicerImpl + +class PcepService(GenericGrpcService): + def __init__(self, pcepServer : GrpcServer,cls_name: str = __name__) -> None: + port = get_service_port_grpc(ServiceNameEnum.PCEP) # El enum en common.constants + super().__init__(port, cls_name=cls_name) + self.pcep_servicer = PcepServiceServicerImpl(pcepServer) + + def install_servicers(self): + add_PcepServiceServicer_to_server(self.pcep_servicer, self.server) diff --git a/src/pcep/service/PcepServiceServicerImpl.py b/src/pcep/service/PcepServiceServicerImpl.py new file mode 100644 index 0000000000000000000000000000000000000000..c70a6043f7a675836c5812b8ff00636e82ac4ef6 --- /dev/null +++ b/src/pcep/service/PcepServiceServicerImpl.py @@ -0,0 +1,58 @@ +# 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 grpc, json, logging +from typing import Optional +from pcep.service.tools.GrpcServer import GrpcServer +from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method +from common.method_wrappers.ServiceExceptions import AlreadyExistsException, InvalidArgumentException +from common.proto.context_pb2 import (DeviceId, Empty, EndPointId, Link, Service, ServiceId, ServiceStatusEnum, ServiceTypeEnum, TopologyId,ContextId,Topology + ,Device,DeviceDriverEnum, Uuid) +from common.proto.pathcomp_pb2 import PathCompRequest +from common.proto.service_pb2_grpc import ServiceServiceServicer + +from common.tools.grpc.Tools import grpc_message_to_json, grpc_message_to_json_string +from context.client.ContextClient import ContextClient +from pathcomp.frontend.client.PathCompClient import PathCompClient + +from common.proto.pcep_pb2 import (RequestRq, RequestRp, PceIpRq, PceIpRp) +from common.proto.pcep_pb2_grpc import PcepServiceServicer + +# from .task_scheduler.TaskScheduler import TasksScheduler +# from .tools.ContextGetters import get_service + +LOGGER = logging.getLogger(__name__) + +METRICS_POOL = MetricsPool('Service', 'RPC') + +class PcepServiceServicerImpl(PcepServiceServicer): + def __init__(self, pcepServer : GrpcServer) -> None: + LOGGER.debug('Creating Servicer...') + self.pcepServer=pcepServer + LOGGER.debug('Servicer Created') + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def configuratePCE(self, request : PceIpRq, context : grpc.ServicerContext) -> PceIpRp: + + LOGGER.debug("(ConfiguratePCE) Create pce instance %s",request) + + configurateIP=self.pcepServer.connectToJavaPcep(request.address) + return PceIpRp(addressRp=configurateIP) + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def sendRequest(self, request : RequestRq, context : grpc.ServicerContext) -> RequestRp: + message=self.pcepServer.requestToJavaPcep(request.command) + + return RequestRp(commandRp=message) + diff --git a/src/pcep/service/__init__.py b/src/pcep/service/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612 --- /dev/null +++ b/src/pcep/service/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/pcep/service/__main__.py b/src/pcep/service/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..e084fd0a78546c7b4e7602dd3fb5b1f15a5b44e6 --- /dev/null +++ b/src/pcep/service/__main__.py @@ -0,0 +1,87 @@ +# 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 logging, signal, sys, threading, time +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) +from .PcepService import PcepService +from .tools.JavaRunner import JavaRunner +from .tools.GrpcServer import GrpcServer + +terminate = threading.Event() +LOGGER : logging.Logger = None + +def signal_handler(signal, frame): # pylint: disable=redefined-outer-name + LOGGER.warning('Terminate signal received') + LOGGER.warning(signal) + terminate.set() + +def main(): + global LOGGER # pylint: disable=global-statement + + log_level = get_log_level() + logging.basicConfig(level=log_level, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") + LOGGER = logging.getLogger(__name__) + + ###wait_for_environment_variables([ + ###get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_HOST ), + ###get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_GRPC), + ###get_env_var_name(ServiceNameEnum.DEVICE, ENVVAR_SUFIX_SERVICE_HOST ), + ###get_env_var_name(ServiceNameEnum.DEVICE, ENVVAR_SUFIX_SERVICE_PORT_GRPC), + ###get_env_var_name(ServiceNameEnum.PATHCOMP, ENVVAR_SUFIX_SERVICE_HOST ), + ###get_env_var_name(ServiceNameEnum.PATHCOMP, ENVVAR_SUFIX_SERVICE_PORT_GRPC), + ###]) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + + LOGGER.info('Starting...') + + # Start metrics server + metrics_port = get_metrics_port() + start_http_server(metrics_port) + + # Initialize ServiceHandler Factory + ###service_handler_factory = ServiceHandlerFactory(SERVICE_HANDLERS) + + #DB=DiscoveredDBManager() + + pcep_server = GrpcServer() + #pcep_server.Connect() + + pcep_server.connectToJavaPcep("10.95.41.240") + time.sleep(30) + n = "initiate lsp directo 10.95.86.214 1.1.1.1 1.1.1.3 m1228800 na192.168.3.11-192.168.3.13" + pcep_server.requestToJavaPcep(n) + + # Starting pcep service + pcep_service = PcepService(pcep_server) + pcep_service.start() + + + + # Wait for Ctrl+C or termination signal + while not terminate.wait(timeout=0.1): pass + LOGGER.info('Terminating...') + pcep_server.terminateGrpcServer() + pcep_service.stop() + + LOGGER.info('Bye') + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/pcep/service/resources/BGP4Parameters_2.xml b/src/pcep/service/resources/BGP4Parameters_2.xml new file mode 100644 index 0000000000000000000000000000000000000000..d7a101668f7aff256afd2b236b4d951e554e0a8e --- /dev/null +++ b/src/pcep/service/resources/BGP4Parameters_2.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<config> + <!-- TCP port where the BGP is listening for incoming bgp4 connections. Optional Parameter. Default value: 179 (BGP Port) --> + <BGP4Port>22179</BGP4Port> + <BGPIdentifier>1.1.1.1</BGPIdentifier> +<!-- TCP port to connect to manage the BGP connection. Default value: 1112 --> + <BGP4ManagementPort>1112</BGP4ManagementPort> + <!-- Peers to which this Peer is going to establish connection --> + <configPeer> + <peer>localhost</peer> + <export>false</export> + <import>true</import> + <peerPort>11179</peerPort> + </configPeer> + + <!-- Ficheros log (servidor, protocolo PCEP y OSPF). Campos opcionales--> + <BGP4LogFile>BGP4Parser2.log</BGP4LogFile><!-- Default value: BGP4Parser.log --> + <BGP4LogFileClient>BGP4Client2.log</BGP4LogFileClient><!-- Default value: BGP4Client.log--> + <BGP4LogFileServer>BGP4Server2.log</BGP4LogFileServer><!-- Default value: BGP4Server.log--> + <!-- If the tcp no delay option is used or not. Optional Parameter. Default value: false. --> + <nodelay>true</nodelay> + <!-- Waiting Time to re-connect to clients. Default value: 6000 ms. --> + <delay>40000</delay> + <setTraces>true</setTraces> + <!-- OPEN Parameters --> + <!-- RFC 4271. This 2-octet unsigned integer indicates the number of seconds the sender proposes for the value of the Hold Timer. + Upon receipt of an OPEN message, a BGP speaker MUST calculate the value of the Hold Timer by using the smaller of its configured + Hold Time and the Hold Time received in the OPEN message. The Hold Time MUST be either zero or at least three seconds. An + implementation MAY reject connections on the basis of the Hold Time. The calculated value indicates the maximum number of + seconds that may elapse between the receipt of successive KEEPALIVE and/or UPDATE messages from the sender. --> + <holdTime>180</holdTime><!-- Optional Parameter. Default value: 3. --> + <!-- RFC 4271. This 1-octet unsigned integer indicates the protocol version number of the message. The current BGP version number is 4. --> + <version>4</version><!-- Optional Parameter. Default value: 4. --> + <!-- RFC 4271. This 2-octet unsigned integer indicates the Autonomous System number of the sender.--> + <myAutonomousSystem>1</myAutonomousSystem> + <!-- RFC 4271. This 4-octet unsigned integer indicates the BGP Identifier of the sender. A given BGP speaker sets the value of its BGP + Identifier to an IP address that is assigned to that BGP speaker. The value of the BGP Identifier is determined upon + startup and is the same for every local interface and BGP peer. --> + <!--<BGPIdentifier>192.168.1.200</BGPIdentifier> --> + <!-- If the peer is in charge of sending its topology (only the interdomain Links) to the other BGP peer it is connected to. Default: false --> + <sendTopology>false</sendTopology> + <!-- If the peer is in charge of sending its whole topology to the other BGP peer it is connected to. Default: false --> + <sendIntradomainLinks>true</sendIntradomainLinks> + <!-- Optional Parameter. How to learn the topology. Possibilities: fromXML, fromBGP. Default: fromBGP --> + <learnTopology>fromBGP</learnTopology> + <!-- Topology network to read. It is mandatory if and only if learnTopology parameter is fromXML. --> + <!--<topologyFile>src/test/resources/network1.xml</topologyFile>--> + <!-- Optional Parameter. Instance Identifier for node and link NLRI. See rfc 6549. Default value: 0--> + <!--<instanceID>0</instanceID>--> + <!-- Optional Parameter. Default value: localhost --> + <localBGPAddress>0.0.0.0</localBGPAddress> +</config> diff --git a/src/pcep/service/resources/Ejecutable.jar b/src/pcep/service/resources/Ejecutable.jar new file mode 100644 index 0000000000000000000000000000000000000000..52cd4230167f6e261fbec6384b2c975c9f696c09 Binary files /dev/null and b/src/pcep/service/resources/Ejecutable.jar differ diff --git a/src/pcep/service/resources/PCEServerConfiguration.xml b/src/pcep/service/resources/PCEServerConfiguration.xml new file mode 100644 index 0000000000000000000000000000000000000000..a48b4c03bc0a512555dba403c2a63432ef65acc2 --- /dev/null +++ b/src/pcep/service/resources/PCEServerConfiguration.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?> +<config> + <PCEServerPort>4189</PCEServerPort> + <PCEManagementPort>6666</PCEManagementPort> + <!--<LocalPCEAddress>192.168.1.200</LocalPCEAddress>--> + <!--<LocalPCEAddress>10.95.40.175</LocalPCEAddress>--> + <!--<LocalPCEAddress>127.0.0.1</LocalPCEAddress>--> + <LocalPCEAddress>10.95.43.150</LocalPCEAddress> + + <ConnectTimer> + <!-- Connect: the timer (in seconds) started after having initialized a + TCP connection using the PCEP-registered TCP port. The value of + the Connect timer is 60 seconds. --> + 60 + </ConnectTimer> + <KeepAliveTimer> + 30 + </KeepAliveTimer> + <DeadTimer> + 120 + </DeadTimer> + <ConnectMaxRetry> + <!-- ConnectMaxRetry: the maximum number of times the system tries to + establish a TCP connection using the PCEP-registered TCP port + before going back to the Idle state. The value of the + ConnectMaxRetry is 5.--> + 5 + </ConnectMaxRetry> + <OpenWait> + <!-- OpenWait: the timer that corresponds to the amount of time a PCEP + peer will wait to receive an Open message from the PCEP peer after + the expiration of which the system releases the PCEP resource and + goes back to the Idle state. The OpenWait timer has a fixed value + of 60 seconds.--> + 60 + </OpenWait> + <KeepWait> + <!-- KeepWait: the timer that corresponds to the amount of time a PCEP + peer will wait to receive a Keepalive or a PCErr message from the + PCEP peer after the expiration of which the system releases the + PCEP resource and goes back to the Idle state. The KeepWait timer + has a fixed value of 60 seconds.--> + </KeepWait> + <parentPCE> + <!-- <parentPCEAddress>10.95.30.29</parentPCEAddress> --> + <!-- <parentPCEAddress>2.2.2.2</parentPCEAddress>--> + <!--<parentPCEAddress>10.95.30.29</parentPCEAddress> --> + <!--<parentPCEAddress>10.95.15.126</parentPCEAddress>--> + <!-- <parentPCEPort>4172</parentPCEPort> --> + </parentPCE> + <!-- Ficheros log (servidor, protocolo PCEP y OSPF). Campos opcionales --> + <PCEServerLogFile>PCEServer.log</PCEServerLogFile> + <PCEPParserLogFile>PCEPParserServer.log</PCEPParserLogFile> + <OSPFParserLogFile>OSPFParser.log</OSPFParserLogFile> + <isStateful>true</isStateful> + <isActive>true</isActive> + <PCCRequestsProcessors>1</PCCRequestsProcessors> + <ParentPCERequestProcessors>1</ParentPCERequestProcessors> + <!--<networkDescriptionFile>networks\Network_8_nodes.xml</networkDescriptionFile>--> + <!--<networkDescriptionFile>networks\network_NSFNet.xml</networkDescriptionFile>--> + <!--<networkDescriptionFile>/usr/local/nodeConfig/topologia.xml</networkDescriptionFile>--> + <networkDescriptionFile>topologia_ifusion.xml</networkDescriptionFile> + + <actingAsBGP4Peer>false</actingAsBGP4Peer> + <BGP4File>BGP4Parameters_2.xml</BGP4File> + + <initialSessionID>1000</initialSessionID> + <nodelay>true</nodelay> + <reservation>false</reservation> + <optimizedRead>false</optimizedRead> + <analyzeRequestTime>true</analyzeRequestTime> + <multilayer>false</multilayer> + <setTraces>true</setTraces> + <!--OSPF> + <OSPFSession>true</OSPFSession> + <OSPFListenerIP>192.168.1.200</OSPFListenerIP> + <OSPFMulticast>true</OSPFMulticast> + <OSPFUnicast>false</OSPFUnicast> + <OSPFTCPSession>false</OSPFTCPSession> + <OSPFTCPPort>7762</OSPFTCPPort> + </OSPF--> + <!--WSON NETWORK--> + <!--<layer type="gmpls" default="true" encodingType="1" switchingType="150">77</layer>--> + <layer type="mpls" default="true" ></layer> + <!--<algorithmRule of="0" svec="false" name="mpls.MPLS_MinTH_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="false"/>--> + + <!--<algorithmRule of="1000" svec="false" name="wson.SP_FF_RWA_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<<algorithmRule of="1002" svec="false" name="sson.AURE_SSON_algorithm" isParentPCEAlgorithm="false" isSSONAlgorithm="true"/>--> + + <!--<algorithmRule of="998" svec="true" name="wson.svec.SVEC_SP_FF_WSON_PathComputing" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="1100" svec="false" name="multiLayer.Multilayer_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="900" svec="false" name="wson.KSPprecomp_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="1001" svec="false" name="wson.AURE_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="901" svec="false" name="wson.AURE_PACK_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="903" svec="false" name="wson.AURE_RANDOM_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="902" svec="false" name="wson.AURE_SPREAD_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="800" svec="false" name="wson.KSP_FF_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="801" svec="false" name="wson.KSP_PACK_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="803" svec="false" name="wson.KSP_RANDOM_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="802" svec="false" name="wson.KSP_SPREAD_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="900" svec="false" name="wson.AURE_FF_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="1001" svec="false" name="wson.AURE_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="false"/>--> + <!--<algorithmRule of="999" svec="true" name="CPLEXOptimizedPathComputing" isParentPCEAlgorithm="false" isWSONAlgorithm="false"/>--> + <!-- <layer type="mpls" default="true"/>--> + <!--<layer type="mpls" default="true"/>--> + +</config> diff --git a/src/pcep/service/resources/java/generateJar.txt b/src/pcep/service/resources/java/generateJar.txt new file mode 100644 index 0000000000000000000000000000000000000000..858aa02c7c72745b09020776140c615a92270c1d --- /dev/null +++ b/src/pcep/service/resources/java/generateJar.txt @@ -0,0 +1 @@ +"/home/ubuntu/downloads/apache-maven-3.8.8/bin/mvn" clean package -P pcep assembly:single -DskipTests=True -f "/home/ubuntu/tfs-ctrl/src/pcep/service/resources/java/netphony-pce/pom.xml" \ No newline at end of file diff --git a/src/pcep/service/resources/log4j2.xml b/src/pcep/service/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..fa4ad59c9e4745a568adbaf76ab34540e73cd7f5 --- /dev/null +++ b/src/pcep/service/resources/log4j2.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> + <Configuration status="DEBUG"> + <Appenders> + <Console name="Console" target="SYSTEM_OUT"> + <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> + </Console> + </Appenders> + <Loggers> + <Logger name="BGP4Peer" level="trace" additivity="false"> + <AppenderRef ref="Console"/> + </Logger> + <Root level="DEBUG"> + <AppenderRef ref="Console"/> + </Root> + </Loggers> + </Configuration> diff --git a/src/pcep/service/resources/topologia_ifusion.xml b/src/pcep/service/resources/topologia_ifusion.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c1f9ad3d3d039b2caf04ce7d83d1bf6eae763df --- /dev/null +++ b/src/pcep/service/resources/topologia_ifusion.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<network> + <domain> + <layer type="mpls" ></layer> + + <domain_id>0.0.0.1</domain_id> + <reachability_entry> + <ipv4_address>1.1.1.0</ipv4_address> + <prefix>12</prefix> + </reachability_entry> + + <node> + <router_id>1.1.1.1</router_id> + </node> + <node> + <router_id>1.1.1.2</router_id> + </node> + <node> + <router_id>1.1.1.3</router_id> + </node> + + <!-- 1 al 2 --> + <edge type="intradomain"> + <source> + <router_id>1.1.1.1</router_id> + <NumIf_id>192.168.1.11</NumIf_id> + </source> + <destination> + <router_id>1.1.1.2</router_id> + <NumIf_id>192.168.1.12</NumIf_id> + </destination> + <delay> + 3.13 + </delay> + <maximum_bandwidth> + 100 + </maximum_bandwidth> + <unreserved_bandwidth priority="0"> + 100 + </unreserved_bandwidth> + </edge> + + <edge type="intradomain"> + <source> + <router_id>1.1.1.1</router_id> + <NumIf_id>192.168.3.11</NumIf_id> + </source> + <destination> + <router_id>1.1.1.3</router_id> + <NumIf_id>192.168.3.13</NumIf_id> + </destination> + <delay> + 3.13 + </delay> + <maximum_bandwidth> + 100 + </maximum_bandwidth> + <unreserved_bandwidth priority="0"> + 100 + </unreserved_bandwidth> + </edge> + + <edge type="intradomain"> + <source> + <router_id>1.1.1.3</router_id> + <NumIf_id>192.168.2.13</NumIf_id> + </source> + <destination> + <router_id>1.1.1.2</router_id> + <NumIf_id>192.168.2.12</NumIf_id> + </destination> + <delay> + 3.13 + </delay> + <maximum_bandwidth> + 100 + </maximum_bandwidth> + <unreserved_bandwidth priority="0"> + 100 + </unreserved_bandwidth> + </edge> + + + </domain> +</network> diff --git a/src/pcep/service/tools/GrpcServer.py b/src/pcep/service/tools/GrpcServer.py new file mode 100644 index 0000000000000000000000000000000000000000..3e3353cb1930ea92be3b2e0650b60aa3c50e6947 --- /dev/null +++ b/src/pcep/service/tools/GrpcServer.py @@ -0,0 +1,200 @@ +# 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,threading, queue,time,signal +from datetime import datetime, timedelta +from typing import Any, Iterator, List, Optional, Tuple, Union +# from apscheduler.executors.pool import ThreadPoolExecutor +# from apscheduler.job import Job +# from apscheduler.jobstores.memory import MemoryJobStore +# from apscheduler.schedulers.background import BackgroundScheduler +# from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, metered_subclass_method, INF +# from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk_type + + +import logging,threading +import grpc + +from .protos import grpcService_pb2_grpc +from .protos import grpcService_pb2 + +from concurrent import futures +import os +import subprocess +from multiprocessing import Pool +import logging + +from .JavaRunner import JavaRunner + +LOGGER = logging.getLogger(__name__) + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 +SERVER_ADDRESS = 'localhost:2021' + +class GrpcServer(): + + def __init__(self) -> None: # pylint: disable=super-init-not-called + self.__lock = threading.Lock() + self.__started = threading.Event() + self.__terminate = threading.Event() + self.__out_samples = queue.Queue() + self.__server=grpc.aio.server() + # self.__address="10.95.86.214" + # self.__port=179 + # self.__asNumber=65006 + # self.__configFile="TMConfiguration_guillermo.xml" + # self.__process=0 + # self.__javaLocalPort=0 # --> BGP4Port in XML file + self.__mngPort=0 # Port used in XML config file for management (NOT used in TFS) + self.__runnerList=[] + # Data base for saving all new devices discovered + #self.__discoveredDB=DiscoveredDB + # self.__comms=grpcComms + # Este tendrÃa que tener la info del runner al que se connecta¿ + + def ConnectThread(self) -> bool: + # TODO: Metodos necesarios para conectarte al speaker + # If started, assume it is already connected + if self.__started.is_set(): return True + self.__started.set() #notifyAll -->event.is_set() + # 10 workers ? + self.__server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + grpcService_pb2_grpc.add_pceServiceServicer_to_server(self, self.__server) + self.__server.add_insecure_port(SERVER_ADDRESS) + # server.add_secure_port(SERVER_ADDRESS) + LOGGER.info("Starting server on %s", SERVER_ADDRESS) + self.__server.start() + try: + while True: + time.sleep(_ONE_DAY_IN_SECONDS) + except KeyboardInterrupt: + LOGGER.info("DISCONNECT") + self.Disconnect() + return True + + def Connect(self): + grpcThread = threading.Thread(target=self.ConnectThread) + grpcThread.start() + return True + + def Disconnect(self) -> bool: + self.__terminate.set() + # If not started, assume it is already disconnected + if not self.__started.is_set(): return True + LOGGER.info("Keyboard interrupt, stop server") + self.__server.stop(0) + # Disconnect triggers deactivation of sampling events + # self.__scheduler.shutdown() + # exit(0) + return True + + + def update(self,request, context) -> bool: + """ + Processes the messages recived by de grpc server + """ + with self.__lock: + #TODO: Get update + LOGGER.info("(server) Update message from pcep: \n %s" % (request)) + response = grpcService_pb2.commandResponse(commandResp="OK") + LOGGER.debug("Update class string %s",response.commandResp) + return response + + + + #def connectToJavaPcep(self, address : str = "10.95.86.214", port : str = "11179", asNumber : str = "1"): + def connectToJavaPcep(self, address): + # Get unused* port + #self.setLocalPort() + #runner = JavaRunner(self.__javaLocalPort,address,self.__mngPort) + LOGGER.debug("Ejecutando el servidor java") + runner = JavaRunner(address) + # Sets port in XML config file for java program + #runner.setAsNumber(asNumber) + #runner.setPort(port) + runner.setPeer() + process=runner.execPcep() + self.__runnerList.append(runner) + + return process.pid + + def requestToJavaPcep(self,message): + """ + If java already running add 1 to current used port, + else initialize port . + initPort --> BGP4Port, usually 179 corresponding to BGP + """ + with grpc.insecure_channel('localhost:10050') as channel: + #n = "initiate lsp largo2 10.95.86.214 1.1.1.1 1.1.1.2 m69644288 nn1.1.1.3 m69640192 nn1.1.1.2" + #n = "initiate lsp directo 10.95.86.214 1.1.1.1 1.1.1.3 m1228800 na192.168.3.11-192.168.3.13" + #n="initiate lsp largo 10.95.86.214 1.1.1.1 1.1.1.3 m61849600 na192.168.1.11-192.168.1.12 m62259200 na192.168.2.12-192.168.2.13" + #n = "terminate lsp 10.95.86.214 0 nombre" + #n="create candidatepath 10.95.86.214 1.1.1.1 4 97 m69644288 nn1.1.1.3 m69640192 nn1.1.1.2" + #n="fallo" + #n="quit"; + LOGGER.debug("LLego al request") + stub = grpcService_pb2_grpc.pceServiceStub(channel) + LOGGER.debug("LLego al request 2") + request = grpcService_pb2.commandRequest(command=message) + print("updateService req: %s" ,request) + response = stub.update(request) + #response=stub.GetCommand(grpcService_pb2.commandRequest(command=n)) + #response_observer = ResponseObserver() + #stub.update(response, response_observer) + print("updateServide client received: %s" ,response.commandResp) + return response.commandResp + + def terminateRunners(self): + for runner in self.__runnerList: + runner.endBGPSpeaker() + return True + + def terminateGrpcServer(self): + LOGGER.debug("Terminating java programs...") + self.terminateRunners() + LOGGER.debug("Disconnecting grpc server...") + self.Disconnect() + return True + + def terminateRunnerById(self,speaker_id): + """ + Disconnect from BGP-LS speaker given an speaker Id. Its the same + as the java running proccess PID. + """ + for runner in self.__runnerList: + if(runner.getPid()==speaker_id): + runner.endBGPSpeaker() + self.__runnerList.remove(runner) + + return True + + def setLocalPort(self,initPort=22179): + """ + If java already running add 1 to current used port, + else initialize port . + initPort --> BGP4Port, usually 179 corresponding to BGP + """ + with self.__lock: + if(self.__runnerList): + LOGGER.debug("Port exists %s",self.__javaLocalPort) + lastRunner=self.__runnerList[-1] + self.__javaLocalPort=lastRunner.getCurrentLocalPort()+1 + self.__mngPort=lastRunner.getCurrentMngPort()+1 + else: + LOGGER.debug("Port DONT exists %s",self.__javaLocalPort) + self.__javaLocalPort=initPort + self.__mngPort=1112 # default management port + return self.__javaLocalPort + + \ No newline at end of file diff --git a/src/pcep/service/tools/JavaRunner.py b/src/pcep/service/tools/JavaRunner.py new file mode 100644 index 0000000000000000000000000000000000000000..1e1cd0314d80d71352253cc6245277b1cadd25bc --- /dev/null +++ b/src/pcep/service/tools/JavaRunner.py @@ -0,0 +1,147 @@ +# 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,threading, queue,time,signal +from datetime import datetime, timedelta +from typing import Any, Iterator, List, Optional, Tuple, Union +import logging +import grpc + +from concurrent import futures +from lxml import etree +import os +import subprocess +from multiprocessing import Pool + + +SERVER_ADDRESS = 'localhost:2021' +SERVER_ID = 1 +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + +#XML_FILE="/var/teraflow/bgpls_speaker/service/resources/BGP4Parameters_2.xml" +XML_CONFIG_FILE="/var/teraflow/pcep/resources/PCEServerConfiguration.xml" + +LOGGER = logging.getLogger(__name__) + + +class JavaRunner: + + #def __init__(self,localPort : int, address : str ="10.95.86.214", mngPort : int = 1112): + def __init__(self,address): + #self.__peerPort=11179 + #self.__localPort=localPort + #self.__managementPort=mngPort + # To support multiple speakers at same time + # Add 1 to port and then pass port to subproccess call + #self.__configFile=XML_CONFIG_FILE + #self.__process=0 + self.__lock = threading.Lock() + self.__address = address + #self.__portConf=6666 + #self.__pceAddress="10.95.43.16" + #self.__asNumber=1 + + def getCurrentLocalPort(self): + with self.__lock: + return self.__localPort + + def getCurrentMngPort(self): + with self.__lock: + return self.__managementPort + def getPid(self): + return self.__process.pid + + def execAndKill(self): + + LOGGER.debug("Before exec and kill") + os.chdir("/var/teraflow/pcep/service/resources/") + cwd = os.getcwd() + LOGGER.info("Current working directory: %s", cwd) + # Security shell=False + self.__process=subprocess.Popen(['java -jar Ejecutable.jar '+ XML_CONFIG_FILE], + shell=False,start_new_session=True,stdout=subprocess.PIPE) + LOGGER.debug("Time to sleep") + java_pid = self.__process.pid + print("Java PID:", java_pid) + time.sleep(15) + self.__process.terminate() + + + def execPcep(self) -> bool: + """ + Executes java pcep in non-blocking process + """ + # CHECKEAR muchas cosas + LOGGER.debug("Before exec") + os.chdir("/var/teraflow/pcep/service/resources/") + # Security reasons shell=False + self.__process=subprocess.Popen(['java' , '-jar' , 'Ejecutable.jar' , XML_CONFIG_FILE], + shell=False,start_new_session=True) + return self.__process + + def setPort(self,port): + self.__peerPort=port + return True + def setAsNumber(self,asNumber): + self.__asNumber=asNumber + return True + + def setPeer(self) -> bool: + """ + Sets XML existing config file with peer address and port. TODO: as_number + """ + + #XMLParser = etree.XMLParser(remove_blank_text=False) + #tree = etree.parse(XML_FILE, parser=XMLParser) + #root = tree.getroot() + ##peerAddress = root.find(".//peer") + ##peerAddress.text=self.__address + #peerPort = root.find(".//peerPort") + #peerPort.text=str(self.__peerPort) + #localPort = root.find(".//BGP4Port") + #localPort.text=str(self.__localPort) + #myAutonomousSystem = root.find(".//myAutonomousSystem") + #myAutonomousSystem.text=str(self.__asNumber) + #managePort = root.find(".//BGP4ManagementPort") + #managePort.text=str(self.__managementPort) + #tree.write(XML_FILE) #with ... as .. + + XMLParser = etree.XMLParser(remove_blank_text=False) + tree = etree.parse(XML_CONFIG_FILE, parser=XMLParser) + root = tree.getroot() + #portConf = root.find(".//PCEManagementPort") + #portConf.text=str(self.__portConf) + pceAddress = root.find(".//LocalPCEAddress") + + LOGGER.debug("Valor anterior de LocalPCEAddress: %s", pceAddress.text) + pceAddress.text=str(self.__address) + LOGGER.debug("Valor posterior de LocalPCEAddress: %s", pceAddress.text) + tree.write(XML_CONFIG_FILE) + return True + + def endBGPSpeaker(self) -> bool: + """ + Kills java program connected to BGPLS Speaker with SIGKILL signal + """ + LOGGER.debug("sending kill signal to process %s",self.__process.pid) + # time.sleep(15) + LOGGER.debug("PID: %d",self.__process.pid) + # LOGGER.debug("Group PID: %d",os.getpgid(self.__process.pid)) + # os.killpg(os.getpgid(self.__process.pid), signal.SIGKILL) + self.__process.kill() + # .terminate() for SIGTERM + return True + + def getRunnerInfo(self): + return self.__address,self.__asNumber,self.__peerPort \ No newline at end of file diff --git a/src/pcep/service/tools/PCEServerConfiguration.xml b/src/pcep/service/tools/PCEServerConfiguration.xml new file mode 100644 index 0000000000000000000000000000000000000000..a48b4c03bc0a512555dba403c2a63432ef65acc2 --- /dev/null +++ b/src/pcep/service/tools/PCEServerConfiguration.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?> +<config> + <PCEServerPort>4189</PCEServerPort> + <PCEManagementPort>6666</PCEManagementPort> + <!--<LocalPCEAddress>192.168.1.200</LocalPCEAddress>--> + <!--<LocalPCEAddress>10.95.40.175</LocalPCEAddress>--> + <!--<LocalPCEAddress>127.0.0.1</LocalPCEAddress>--> + <LocalPCEAddress>10.95.43.150</LocalPCEAddress> + + <ConnectTimer> + <!-- Connect: the timer (in seconds) started after having initialized a + TCP connection using the PCEP-registered TCP port. The value of + the Connect timer is 60 seconds. --> + 60 + </ConnectTimer> + <KeepAliveTimer> + 30 + </KeepAliveTimer> + <DeadTimer> + 120 + </DeadTimer> + <ConnectMaxRetry> + <!-- ConnectMaxRetry: the maximum number of times the system tries to + establish a TCP connection using the PCEP-registered TCP port + before going back to the Idle state. The value of the + ConnectMaxRetry is 5.--> + 5 + </ConnectMaxRetry> + <OpenWait> + <!-- OpenWait: the timer that corresponds to the amount of time a PCEP + peer will wait to receive an Open message from the PCEP peer after + the expiration of which the system releases the PCEP resource and + goes back to the Idle state. The OpenWait timer has a fixed value + of 60 seconds.--> + 60 + </OpenWait> + <KeepWait> + <!-- KeepWait: the timer that corresponds to the amount of time a PCEP + peer will wait to receive a Keepalive or a PCErr message from the + PCEP peer after the expiration of which the system releases the + PCEP resource and goes back to the Idle state. The KeepWait timer + has a fixed value of 60 seconds.--> + </KeepWait> + <parentPCE> + <!-- <parentPCEAddress>10.95.30.29</parentPCEAddress> --> + <!-- <parentPCEAddress>2.2.2.2</parentPCEAddress>--> + <!--<parentPCEAddress>10.95.30.29</parentPCEAddress> --> + <!--<parentPCEAddress>10.95.15.126</parentPCEAddress>--> + <!-- <parentPCEPort>4172</parentPCEPort> --> + </parentPCE> + <!-- Ficheros log (servidor, protocolo PCEP y OSPF). Campos opcionales --> + <PCEServerLogFile>PCEServer.log</PCEServerLogFile> + <PCEPParserLogFile>PCEPParserServer.log</PCEPParserLogFile> + <OSPFParserLogFile>OSPFParser.log</OSPFParserLogFile> + <isStateful>true</isStateful> + <isActive>true</isActive> + <PCCRequestsProcessors>1</PCCRequestsProcessors> + <ParentPCERequestProcessors>1</ParentPCERequestProcessors> + <!--<networkDescriptionFile>networks\Network_8_nodes.xml</networkDescriptionFile>--> + <!--<networkDescriptionFile>networks\network_NSFNet.xml</networkDescriptionFile>--> + <!--<networkDescriptionFile>/usr/local/nodeConfig/topologia.xml</networkDescriptionFile>--> + <networkDescriptionFile>topologia_ifusion.xml</networkDescriptionFile> + + <actingAsBGP4Peer>false</actingAsBGP4Peer> + <BGP4File>BGP4Parameters_2.xml</BGP4File> + + <initialSessionID>1000</initialSessionID> + <nodelay>true</nodelay> + <reservation>false</reservation> + <optimizedRead>false</optimizedRead> + <analyzeRequestTime>true</analyzeRequestTime> + <multilayer>false</multilayer> + <setTraces>true</setTraces> + <!--OSPF> + <OSPFSession>true</OSPFSession> + <OSPFListenerIP>192.168.1.200</OSPFListenerIP> + <OSPFMulticast>true</OSPFMulticast> + <OSPFUnicast>false</OSPFUnicast> + <OSPFTCPSession>false</OSPFTCPSession> + <OSPFTCPPort>7762</OSPFTCPPort> + </OSPF--> + <!--WSON NETWORK--> + <!--<layer type="gmpls" default="true" encodingType="1" switchingType="150">77</layer>--> + <layer type="mpls" default="true" ></layer> + <!--<algorithmRule of="0" svec="false" name="mpls.MPLS_MinTH_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="false"/>--> + + <!--<algorithmRule of="1000" svec="false" name="wson.SP_FF_RWA_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<<algorithmRule of="1002" svec="false" name="sson.AURE_SSON_algorithm" isParentPCEAlgorithm="false" isSSONAlgorithm="true"/>--> + + <!--<algorithmRule of="998" svec="true" name="wson.svec.SVEC_SP_FF_WSON_PathComputing" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="1100" svec="false" name="multiLayer.Multilayer_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="900" svec="false" name="wson.KSPprecomp_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="1001" svec="false" name="wson.AURE_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="901" svec="false" name="wson.AURE_PACK_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="903" svec="false" name="wson.AURE_RANDOM_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="902" svec="false" name="wson.AURE_SPREAD_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="800" svec="false" name="wson.KSP_FF_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="801" svec="false" name="wson.KSP_PACK_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + <!--<algorithmRule of="803" svec="false" name="wson.KSP_RANDOM_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="802" svec="false" name="wson.KSP_SPREAD_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="900" svec="false" name="wson.AURE_FF_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="true"/>--> + + <!--<algorithmRule of="1001" svec="false" name="wson.AURE_Algorithm" isParentPCEAlgorithm="false" isWSONAlgorithm="false"/>--> + <!--<algorithmRule of="999" svec="true" name="CPLEXOptimizedPathComputing" isParentPCEAlgorithm="false" isWSONAlgorithm="false"/>--> + <!-- <layer type="mpls" default="true"/>--> + <!--<layer type="mpls" default="true"/>--> + +</config> diff --git a/src/pcep/service/tools/__init__.py b/src/pcep/service/tools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612 --- /dev/null +++ b/src/pcep/service/tools/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/pcep/service/tools/protos/grpcService.proto b/src/pcep/service/tools/protos/grpcService.proto new file mode 100644 index 0000000000000000000000000000000000000000..fc5a6e852c6b46b31a2348fdb678ec43b349ff70 --- /dev/null +++ b/src/pcep/service/tools/protos/grpcService.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +package src.main.proto; + +//el modulo java abre la comunicacion +//cliente(java) manda la info al servidor(python) +//el modulo en python responde con ok + +message commandRequest{ + string command = 1; +} + +message commandResponse{ + string commandResp = 1; +} + +// Defining a Service, a Service can have multiple RPC operations +service pceService { + // MODIFY HERE: Update the return to streaming return. + rpc update(commandRequest) returns (commandResponse); +} \ No newline at end of file diff --git a/src/pcep/service/tools/protos/grpcService_pb2.py b/src/pcep/service/tools/protos/grpcService_pb2.py new file mode 100644 index 0000000000000000000000000000000000000000..e6b1f576d914cdda8be1dd5ff18c95b46c43c828 --- /dev/null +++ b/src/pcep/service/tools/protos/grpcService_pb2.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: grpcService.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11grpcService.proto\x12\x0esrc.main.proto\"!\n\x0e\x63ommandRequest\x12\x0f\n\x07\x63ommand\x18\x01 \x01(\t\"&\n\x0f\x63ommandResponse\x12\x13\n\x0b\x63ommandResp\x18\x01 \x01(\t2W\n\npceService\x12I\n\x06update\x12\x1e.src.main.proto.commandRequest\x1a\x1f.src.main.proto.commandResponseb\x06proto3') + + + +_COMMANDREQUEST = DESCRIPTOR.message_types_by_name['commandRequest'] +_COMMANDRESPONSE = DESCRIPTOR.message_types_by_name['commandResponse'] +commandRequest = _reflection.GeneratedProtocolMessageType('commandRequest', (_message.Message,), { + 'DESCRIPTOR' : _COMMANDREQUEST, + '__module__' : 'grpcService_pb2' + # @@protoc_insertion_point(class_scope:src.main.proto.commandRequest) + }) +_sym_db.RegisterMessage(commandRequest) + +commandResponse = _reflection.GeneratedProtocolMessageType('commandResponse', (_message.Message,), { + 'DESCRIPTOR' : _COMMANDRESPONSE, + '__module__' : 'grpcService_pb2' + # @@protoc_insertion_point(class_scope:src.main.proto.commandResponse) + }) +_sym_db.RegisterMessage(commandResponse) + +_PCESERVICE = DESCRIPTOR.services_by_name['pceService'] +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _COMMANDREQUEST._serialized_start=37 + _COMMANDREQUEST._serialized_end=70 + _COMMANDRESPONSE._serialized_start=72 + _COMMANDRESPONSE._serialized_end=110 + _PCESERVICE._serialized_start=112 + _PCESERVICE._serialized_end=199 +# @@protoc_insertion_point(module_scope) diff --git a/src/pcep/service/tools/protos/grpcService_pb2_grpc.py b/src/pcep/service/tools/protos/grpcService_pb2_grpc.py new file mode 100644 index 0000000000000000000000000000000000000000..8458247c26fd176da3a307c4aac1fea3bcd067f4 --- /dev/null +++ b/src/pcep/service/tools/protos/grpcService_pb2_grpc.py @@ -0,0 +1,70 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +from . import grpcService_pb2 as grpcService__pb2 + + +class pceServiceStub(object): + """Defining a Service, a Service can have multiple RPC operations + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.update = channel.unary_unary( + '/src.main.proto.pceService/update', + request_serializer=grpcService__pb2.commandRequest.SerializeToString, + response_deserializer=grpcService__pb2.commandResponse.FromString, + ) + + +class pceServiceServicer(object): + """Defining a Service, a Service can have multiple RPC operations + """ + + def update(self, request, context): + """MODIFY HERE: Update the return to streaming return. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_pceServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'update': grpc.unary_unary_rpc_method_handler( + servicer.update, + request_deserializer=grpcService__pb2.commandRequest.FromString, + response_serializer=grpcService__pb2.commandResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'src.main.proto.pceService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class pceService(object): + """Defining a Service, a Service can have multiple RPC operations + """ + + @staticmethod + def update(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/src.main.proto.pceService/update', + grpcService__pb2.commandRequest.SerializeToString, + grpcService__pb2.commandResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/src/pcep/tests/.gitignore b/src/pcep/tests/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6b97d6fe3ad32f39097745229ab7f547f26ecb12 --- /dev/null +++ b/src/pcep/tests/.gitignore @@ -0,0 +1 @@ +# Add here your files containing confidential testbed details such as IP addresses, ports, usernames, passwords, etc. diff --git a/src/pcep/tests/__init__.py b/src/pcep/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612 --- /dev/null +++ b/src/pcep/tests/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +