Commit 26bacd91 authored by Antonio Gines Buendia Lopez's avatar Antonio Gines Buendia Lopez
Browse files

Introduce PathCompExtended for advanced path computations

Implements a new component to enhance optical slice computations.
Adds Kubernetes deployment, service, and HPA manifests.
Extends proto definitions with new RPCs and messages.
Integrates PathCompExtended into NBI and refactors related constants.
Supports K-shortest path and disjoint path algorithms with forecaster integration.
Includes extensive unit tests with mock dependencies.

Relates to feat/364-elig-path-computation-extended-component-pce-for-externalized-optical-slice-computation
parent 221761b3
Loading
Loading
Loading
Loading
+124 −0
Original line number Diff line number Diff line
# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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: pathcompextendedservice
spec:
  selector:
    matchLabels:
      app: pathcompextendedservice
  #replicas: 1
  template:
    metadata:
      labels:
        app: pathcompextendedservice
    spec:
      terminationGracePeriodSeconds: 5
      containers:
        - name: frontend
          image: labs.etsi.org:5050/tfs/controller/pathcompextended-frontend:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 10020
            - containerPort: 9192
          env:
            - name: LOG_LEVEL
              value: "INFO"
            - name: ENABLE_FORECASTER
              value: "NO"
          readinessProbe:
            exec:
              command: ["/bin/grpc_health_probe", "-addr=:10020"]
          livenessProbe:
            exec:
              command: ["/bin/grpc_health_probe", "-addr=:10020"]
          resources:
            requests:
              cpu: 250m
              memory: 128Mi
            limits:
              cpu: 1000m
              memory: 1024Mi
        - name: backend
          image: labs.etsi.org:5050/tfs/controller/pathcompextended-backend:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 8081
          #readinessProbe:
          #  httpGet:
          #    path: /health
          #    port: 8081
          #  initialDelaySeconds: 5
          #  timeoutSeconds: 5
          #livenessProbe:
          #  httpGet:
          #    path: /health
          #    port: 8081
          #  initialDelaySeconds: 5
          #  timeoutSeconds: 5
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              cpu: 1000m
              memory: 1024Mi
---
apiVersion: v1
kind: Service
metadata:
  name: pathcompextendedservice
  labels:
    app: pathcompextendedservice
spec:
  type: ClusterIP
  selector:
    app: pathcompextendedservice
  ports:
    - name: grpc
      protocol: TCP
      port: 10020
      targetPort: 10020
    - name: http
      protocol: TCP
      port: 8081
      targetPort: 8081
    - name: metrics
      protocol: TCP
      port: 9192
      targetPort: 9192
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: pathcompextendedservice-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: pathcompextendedservice
  minReplicas: 1
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 80
  #behavior:
  #  scaleDown:
  #    stabilizationWindowSeconds: 30
+53 −0
Original line number Diff line number Diff line
// Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// 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 pathcompextended;

import "context.proto";

service PathCompExtendedService {
  rpc Compute(PathCompRequest) returns (PathCompReply) {}
}

message Algorithm_ShortestPath {}

message Algorithm_KShortestPath {
  uint32 k_inspection = 1;
  uint32 k_return     = 2;
}

message Algorithm_KDisjointPath {
  uint32 num_disjoint = 1;
}

message PathCompRequest {
  repeated context.Service services = 1;
  oneof algorithm {
    Algorithm_ShortestPath  shortest_path   = 10;
    Algorithm_KShortestPath k_shortest_path = 11;
    Algorithm_KDisjointPath k_disjoint_path = 12;
  }
}

message PathCompReply {
  // Services requested completed with possible missing fields, and
  // sub-services required for supporting requested services on the
  // underlying layers.
  repeated context.Service services = 1;

  // Connections supporting the requested services and sub-services
  // required for the underlying layers.
  repeated context.Connection connections = 2;
}
+2 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ class ServiceNameEnum(Enum):
    CYBERSECURITY          = 'cybersecurity'
    INTERDOMAIN            = 'interdomain'
    PATHCOMP               = 'pathcomp'
    PATHCOMPEXTENDED       = 'pathcompextended'
    L3_AM                  = 'l3-attackmitigator'
    L3_CAD                 = 'l3-centralizedattackdetector'
    WEBUI                  = 'webui'
@@ -101,6 +102,7 @@ DEFAULT_SERVICE_GRPC_PORTS = {
    ServiceNameEnum.OPTICALATTACKMANAGER   .value : 10005,
    ServiceNameEnum.INTERDOMAIN            .value : 10010,
    ServiceNameEnum.PATHCOMP               .value : 10020,
    ServiceNameEnum.PATHCOMPEXTENDED       .value : 10021,
    ServiceNameEnum.TE                     .value : 10030,
    ServiceNameEnum.FORECASTER             .value : 10040,
    ServiceNameEnum.E2EORCHESTRATOR        .value : 10050,
+2 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ from .ietf_l3vpn import register_ietf_l3vpn
from .ietf_network import register_ietf_network
from .ietf_network_slice import register_ietf_nss
from .osm_nbi import register_osm_api
from .pathcompextended import register_pathcompextended
from .qkd_app import register_qkd_app
from .restconf_root import register_restconf_root
from .sse_telemetry import register_telemetry_subscription
@@ -98,6 +99,7 @@ register_ietf_l3vpn (nbi_app)
register_ietf_network    (nbi_app)
register_ietf_nss        (nbi_app)
register_osm_api         (nbi_app)
register_pathcompextended(nbi_app)
register_qkd_app         (nbi_app)
register_restconf_root   (nbi_app)
register_telemetry_subscription(nbi_app)
+107 −0
Original line number Diff line number Diff line
# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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
from flask_restful import Resource, request
from flask.json import jsonify
from pathcompextended.client.PathCompClient import PathCompClient

LOGGER = logging.getLogger(__name__)


class _Resource(Resource):
    def __init__(self) -> None:
        super().__init__()
        self.pathcompextended_client = PathCompClient()


class Index(_Resource):
    def get(self):
        LOGGER.info("Operation GET /pathcompextended/")
        return {'status': 'PathCompExtended service is available'}


class NetworkContext(_Resource):
    def get(self):
        LOGGER.info("Operation GET /network-context")
        # TODO: call the gRPC operations and return real result
        return jsonify({'message': 'Not implemented yet'})

    def get(self, id: str):
        LOGGER.info(f"Operation GET /network-context/{id}")
        # TODO: call the gRPC operations
        return jsonify({'message': 'Not implemented yet'})

    def post(self):
        payload = request.json
        LOGGER.info(f"Operation POST /network-context")
        # TODO: call the gRPC operations
        return jsonify({'message': 'Not implemented yet'})

    def delete(self, id: str):
        LOGGER.info(f"Operation DELETE /network-context/{id}")
        # TODO: call the gRPC operations
        return jsonify({'message': 'Not implemented yet'})


class Health(_Resource):
    def get(self):
        LOGGER.info("Operation GET /health")
        # TODO: implement health check
        return jsonify({'status': 'healthy'})


class TransportOpticalSlice(_Resource):
    def get(self):
        LOGGER.info("Operation GET /transport-optical-slice")
        # TODO: implement
        return jsonify({'message': 'Not implemented yet'})

    def get(self, id: str):
        LOGGER.info(f"Operation GET /transport-optical-slice/{id}")
        # TODO: implement
        return jsonify({'message': 'Not implemented yet'})

    def post(self):
        LOGGER.info("Operation POST /transport-optical-slice")
        # TODO: implement
        return jsonify({'message': 'Not implemented yet'})

    def delete(self, id: str):
        LOGGER.info(f"Operation DELETE /transport-optical-slice/{id}")
        # TODO: implement
        return jsonify({'message': 'Not implemented yet'})


class TransportNetworkSliceL3(_Resource):
    def get(self):
        LOGGER.info("Operation GET /transport-network-slice-l3")
        # TODO: implement
        return jsonify({'message': 'Not implemented yet'})

    def get(self, id: str):
        LOGGER.info(f"Operation GET /transport-network-slice-l3/{id}")
        # TODO: implement
        return jsonify({'message': 'Not implemented yet'})

    def post(self):
        LOGGER.info("Operation POST /transport-network-slice-l3")
        # TODO: implement
        return jsonify({'message': 'Not implemented yet'})

    def delete(self, id: str):
        LOGGER.info(f"Operation DELETE /transport-network-slice-l3/{id}")
        # TODO: implement
        return jsonify({'message': 'Not implemented yet'})
Loading