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

WIP

parent 66bc0022
Loading
Loading
Loading
Loading
+11 −17
Original line number Diff line number Diff line
@@ -23,22 +23,23 @@ import "google/protobuf/empty.proto";
service PathCompExtendedService {
  // Health checks
  rpc HealthCheck (google.protobuf.Empty) returns (LivenessProbe);
  rpc Reset (google.protobuf.Empty) returns (GenericMessage);

  // Network Context
  rpc CreateNetworkContext (NetworkContext) returns (google.protobuf.Empty);
  rpc DeleteNetworkContext (UUID) returns (google.protobuf.Empty);
  rpc CreateNetworkContext (NetworkContext) returns (GenericMessage);
  rpc DeleteNetworkContext (UUID) returns (GenericMessage);
  rpc GetNetworkContext (google.protobuf.Empty) returns (NetworkContext);
  rpc GetSpecificNetworkContext (UUID) returns (NetworkTopology);

  // Transport Optical Slice
  rpc CreateTransportOpticalSlice (IetfNetworkSlice) returns (TransportOpticalSlice);
  rpc DeleteTransportOpticalSlice (UUID) returns (google.protobuf.Empty);
  rpc DeleteTransportOpticalSlice (UUID) returns (GenericMessage);
  rpc GetTransportOpticalSlices (google.protobuf.Empty) returns (stream TransportOpticalSlice);
  rpc GetTransportOpticalSlice (UUID) returns (TransportOpticalSlice);

  // Transport Network Slice L3
  rpc CreateTransportNetworkSliceL3 (IetfNetworkSlice) returns (TransportNetworkSliceL3);
  rpc DeleteTransportNetworkSliceL3 (UUID) returns (google.protobuf.Empty);
  rpc DeleteTransportNetworkSliceL3 (UUID) returns (GenericMessage);
  rpc GetTransportNetworkSlicesL3 (google.protobuf.Empty) returns (stream TransportNetworkSliceL3);
  rpc GetTransportNetworkSliceL3 (UUID) returns (TransportNetworkSliceL3);

@@ -47,19 +48,7 @@ service PathCompExtendedService {



// Network Context Operations


// Transport Optical Slice operations



// Transport network Slice L3 operations




// Datamodel definitions
// Message definitions

// Network Context

@@ -103,3 +92,8 @@ message UUID {
  string value = 1;
}

message GenericMessage {
  string message = 1;
  bool ifTrueIsJsonStringified = 2;
}
+45 −15
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ from pathcompextended.client.PathCompExtendedClient import PathCompExtendedClien
from common.proto.context_pb2 import Empty
from common.proto.pathcompextended_pb2 import (
    IetfNetworkSlice, LivenessProbe, NetworkContext, NetworkTopology,
    TransportNetworkSliceL3, TransportOpticalSlice, UUID
    TransportNetworkSliceL3, TransportOpticalSlice, UUID, GenericMessage
)
from common.tools.grpc.Tools import grpc_message_to_json_string

@@ -38,6 +38,34 @@ class Index(_Resource):
        LOGGER.info("Operation GET /pathcompextended/")
        return {'status': 'PathCompExtended service is available'}

# ---------------------------------------------------------------------------------- #
# -- Health ------------------------------------------------------------------------ #
#                                                                                    #
# ---------------------------------------------------------------------------------- #

class Health(_Resource):
    def get(self):
        LOGGER.info("Operation GET /health")
        try:
            probe = self.pathcompextended_client.HealthCheck(None)
            LOGGER.debug(grpc_message_to_json_string(probe))
            output = json.loads(grpc_message_to_json_string(probe))
            return jsonify(output)
        except Exception as e:
            LOGGER.error(f"Error checking health: {e}", exc_info=True)
            return jsonify({'error': str(e), 'status': 'unhealthy'}), 500

class Reset(_Resource):
    def post(self):
        LOGGER.info("Operation POST /reset")

        # TODO: implement

# ---------------------------------------------------------------------------------- #
# -- NetworkContext ---------------------------------------------------------------- #
#                                                                                    #
# ---------------------------------------------------------------------------------- #


class NetworkContext(_Resource):
    def get(self):
@@ -72,7 +100,12 @@ class NetworkContext(_Resource):
            
            result = self.pathcompextended_client.CreateNetworkContext(net_context_msg)
            LOGGER.debug(grpc_message_to_json_string(result))

            if result.ifTrueIsJsonStringified:
                output = json.loads(grpc_message_to_json_string(result.message))
            else:
                output = json.loads(grpc_message_to_json_string(result))

            return jsonify(output), 201
        except Exception as e:
            LOGGER.error(f"Error creating network context: {e}", exc_info=True)
@@ -106,19 +139,10 @@ class NetworkContextDetails(_Resource):
            LOGGER.error(f"Error deleting network context {id}: {e}", exc_info=True)
            return jsonify({'error': str(e)}), 500


class Health(_Resource):
    def get(self):
        LOGGER.info("Operation GET /health")
        try:
            probe = self.pathcompextended_client.HealthCheck(None)
            LOGGER.debug(grpc_message_to_json_string(probe))
            output = json.loads(grpc_message_to_json_string(probe))
            return jsonify(output)
        except Exception as e:
            LOGGER.error(f"Error checking health: {e}", exc_info=True)
            return jsonify({'error': str(e), 'status': 'unhealthy'}), 500

# ---------------------------------------------------------------------------------- #
# -- TransportOpticalSlice --------------------------------------------------------- #
#                                                                                    #
# ---------------------------------------------------------------------------------- #

class TransportOpticalSlice(_Resource):
    def get(self):
@@ -158,6 +182,7 @@ class TransportOpticalSlice(_Resource):
            return jsonify({'error': str(e)}), 500



class TransportOpticalSliceDetails(_Resource):
    def get(self, id: str):
        LOGGER.info(f"Operation GET /transport-optical-slice/{id}")
@@ -185,6 +210,10 @@ class TransportOpticalSliceDetails(_Resource):
            LOGGER.error(f"Error deleting transport optical slice {id}: {e}", exc_info=True)
            return jsonify({'error': str(e)}), 500

# ---------------------------------------------------------------------------------- #
# -- TransportNetworkSliceL3 ------------------------------------------------------- #
#                                                                                    #
# ---------------------------------------------------------------------------------- #

class TransportNetworkSliceL3(_Resource):
    def get(self):
@@ -224,6 +253,7 @@ class TransportNetworkSliceL3(_Resource):
            return jsonify({'error': str(e)}), 500



class TransportNetworkSliceL3Details(_Resource):
    def get(self, id: str):
        LOGGER.info(f"Operation GET /transport-network-slice-l3/{id}")
+14 −5
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ from common.Settings import get_service_host, get_service_port_grpc
from common.proto.context_pb2 import Empty
from common.proto.pathcompextended_pb2 import (
    IetfNetworkSlice, LivenessProbe, NetworkContext, NetworkTopology,
    TransportNetworkSliceL3, TransportOpticalSlice, UUID
    TransportNetworkSliceL3, TransportOpticalSlice, UUID, GenericMessage
)
from common.proto.pathcompextended_pb2_grpc import PathCompExtendedServiceStub
from common.tools.client.RetryDecorator import retry, delay_exponential
@@ -64,19 +64,28 @@ class PathCompExtendedClient:
        LOGGER.debug('HealthCheck result: {:s}'.format(grpc_message_to_json_string(response)))
        return response

    @RETRY_DECORATOR
    def Reset(self, request: Empty = None) -> GenericMessage:
        if request is None:
            request = Empty()
        LOGGER.debug('Reset request')
        response = self.stub.Reset(request)
        LOGGER.debug('Reset result: {:s}'.format(grpc_message_to_json_string(response)))
        return response

    # ------------------------------------------------------------------------ #
    # -- Network Context Operations ------------------------------------------ #
    # ------------------------------------------------------------------------ #

    @RETRY_DECORATOR
    def CreateNetworkContext(self, request: NetworkContext) -> Empty:
    def CreateNetworkContext(self, request: NetworkContext) -> GenericMessage:
        LOGGER.debug('CreateNetworkContext request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.CreateNetworkContext(request)
        LOGGER.debug('CreateNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
        return response

    @RETRY_DECORATOR
    def DeleteNetworkContext(self, request: UUID) -> Empty:
    def DeleteNetworkContext(self, request: UUID) -> GenericMessage:
        LOGGER.debug('DeleteNetworkContext request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.DeleteNetworkContext(request)
        LOGGER.debug('DeleteNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
@@ -110,7 +119,7 @@ class PathCompExtendedClient:
        return response

    @RETRY_DECORATOR
    def DeleteTransportOpticalSlice(self, request: UUID) -> Empty:
    def DeleteTransportOpticalSlice(self, request: UUID) -> GenericMessage:
        LOGGER.debug('DeleteTransportOpticalSlice request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.DeleteTransportOpticalSlice(request)
        LOGGER.debug('DeleteTransportOpticalSlice result: {:s}'.format(grpc_message_to_json_string(response)))
@@ -144,7 +153,7 @@ class PathCompExtendedClient:
        return response

    @RETRY_DECORATOR
    def DeleteTransportNetworkSliceL3(self, request: UUID) -> Empty:
    def DeleteTransportNetworkSliceL3(self, request: UUID) -> GenericMessage:
        LOGGER.debug('DeleteTransportNetworkSliceL3 request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.DeleteTransportNetworkSliceL3(request)
        LOGGER.debug('DeleteTransportNetworkSliceL3 result: {:s}'.format(grpc_message_to_json_string(response)))
+9 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ from typing import Dict, List, Optional, Any
from pydantic import BaseModel, Field

from pathcompextended.connector.api_client import APIClient
from pathcompextended.connector.imp_general import GeneralMethods
import pathcompextended.Config as Config

# Import base models
@@ -230,13 +231,17 @@ class HRAT:
        base_api_url = config.get('HRAT_BASEURL', Config.HRAT_BASEURL)
        self.base_api_url = base_api_url

        # Expose a general endpoints helper that can be reused by higher layers
        # (e.g., gRPC servicer) without having to recreate HTTP methods.
        self.general_endpoints_api = GeneralMethods(self.api, self.base_api_url)

        LOGGER.debug("HRAT initialized with url: {:s}".format(url))

    # ========================================================================
    # NETWORK CONTEXT METHODS
    # ========================================================================

    def network_context(self, request: NetworkContextPostRequest) -> NetworkContextPostResponse:
    def post_network_context(self, request: NetworkContextPostRequest) -> NetworkContextPostResponse:
        """
        Send network context to H-RAT.
        
@@ -329,7 +334,7 @@ class HRAT:
    # TRANSPORT OPTICAL SLICE METHODS
    # ========================================================================

    def transport_optical_slice(self, request: TransportOpticalSlicePostRequest) -> TransportOpticalSlicePostResponse:
    def post_transport_optical_slice(self, request: TransportOpticalSlicePostRequest) -> TransportOpticalSlicePostResponse:
        """
        Request transport optical slice computation from H-RAT.
        
@@ -444,7 +449,7 @@ class HRAT:
    # TRANSPORT NETWORK SLICE L3 METHODS
    # ========================================================================

    def transport_network_slice_l3(self, request: TransportNetworkSliceL3PostRequest) -> TransportNetworkSliceL3PostResponse:
    def post_transport_network_slice_l3(self, request: TransportNetworkSliceL3PostRequest) -> TransportNetworkSliceL3PostResponse:
        """
        Request transport network slice L3 computation from H-RAT.
        
@@ -585,7 +590,7 @@ class HRAT:
    # EXTERNAL KPIs METHODS
    # ========================================================================

    def external_kpis(self, kpis: Dict[str, Any]) -> ExternalKpisPostResponse:
    def post_external_kpis(self, kpis: Dict[str, Any]) -> ExternalKpisPostResponse:
        """
        Send external KPIs to H-RAT.
        
+34 −0
Original line number Diff line number Diff line

from typing import Any, Dict, Optional

from pathcompextended.connector.api_client import APIClient


class GeneralMethods:
    """
    Helper for performing generic HTTP operations against the H-RAT REST API.

    This class is intentionally self-contained and does not import the HRAT
    wrapper itself to avoid circular dependencies. It can be reused by
    resource-specific connector classes.
    """

    def __init__(self, api_client: APIClient, base_api_url: str) -> None:
        self._api_client = api_client
        self._base_api_url = base_api_url

    def _build_endpoint(self, relative_path: str) -> str:
        relative_path = relative_path.lstrip("/")
        return f"{self._base_api_url}/{relative_path}"

    def get(self, relative_path: str, body: Optional[Dict[str, Any]] = None):
        endpoint = self._build_endpoint(relative_path)
        return self._api_client.get(endpoint, body=body)

    def post(self, relative_path: str, body: Optional[Dict[str, Any]] = None):
        endpoint = self._build_endpoint(relative_path)
        return self._api_client.post(endpoint, body=body or {})

    def delete(self, relative_path: str, body: Optional[Dict[str, Any]] = None):
        endpoint = self._build_endpoint(relative_path)
        return self._api_client.delete(endpoint, body=body)
 No newline at end of file
Loading