From 8368993a8410811b2e6ba79533cc8d3a60a15e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pino?= Date: Thu, 19 Jun 2025 12:39:44 +0200 Subject: [PATCH 1/7] Update clients folder to adapters. Rename NetworkManagementInterface Rename NetworkManagementInterface to BaseNetworkClient --- examples/example.py | 10 +- .../{sdk_factory.py => adapters_factory.py} | 35 +-- src/sunrise6g_opensdk/common/sdk.py | 35 +-- .../{clients => adapters}/__init__.py | 0 .../{clients => adapters}/aeros/__init__.py | 2 +- .../{clients => adapters}/aeros/client.py | 4 +- .../{clients => adapters}/aeros/config.py | 0 .../aeros/continuum_client.py | 4 +- .../{clients => adapters}/aeros/utils.py | 2 +- .../edgecloud/{clients => adapters}/errors.py | 0 .../{clients => adapters}/i2edge/__init__.py | 0 .../{clients => adapters}/i2edge/client.py | 6 +- .../{clients => adapters}/i2edge/common.py | 2 +- .../{clients => adapters}/i2edge/schemas.py | 0 .../{clients => adapters}/i2edge/utils.py | 0 .../kubernetes}/__init__.py | 0 .../piedge => adapters/kubernetes}/client.py | 4 +- .../network/{clients => adapters}/__init__.py | 0 .../network/{clients => adapters}/errors.py | 0 .../{clients => adapters}/oai/__init__.py | 0 .../{clients => adapters}/oai/client.py | 8 +- .../open5gcore/__init__.py | 0 .../open5gcore/client.py | 6 +- .../{clients => adapters}/open5gs/__init__.py | 0 .../{clients => adapters}/open5gs/client.py | 10 +- ...rk_interface.py => base_network_client.py} | 23 +- src/sunrise6g_opensdk/network/core/common.py | 1 - tests/common/test_invoke_edgecloud_clients.py | 18 +- tests/common/test_invoke_network_clients.py | 12 +- tests/edgecloud/test_aeros_edge_manager.py | 270 ------------------ tests/edgecloud/test_cases.py | 4 +- tests/edgecloud/test_config.py | 4 +- tests/edgecloud/test_e2e.py | 18 +- tests/network/test_create_qod_session.py | 16 +- .../network/test_create_traffic_influence.py | 26 +- tests/network/test_location_retrieval.py | 1 + 36 files changed, 121 insertions(+), 400 deletions(-) rename src/sunrise6g_opensdk/common/{sdk_factory.py => adapters_factory.py} (66%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/__init__.py (100%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/aeros/__init__.py (93%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/aeros/client.py (98%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/aeros/config.py (100%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/aeros/continuum_client.py (97%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/aeros/utils.py (95%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/errors.py (100%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/i2edge/__init__.py (100%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/i2edge/client.py (99%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/i2edge/common.py (97%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/i2edge/schemas.py (100%) rename src/sunrise6g_opensdk/edgecloud/{clients => adapters}/i2edge/utils.py (100%) rename src/sunrise6g_opensdk/edgecloud/{clients/piedge => adapters/kubernetes}/__init__.py (100%) rename src/sunrise6g_opensdk/edgecloud/{clients/piedge => adapters/kubernetes}/client.py (98%) rename src/sunrise6g_opensdk/network/{clients => adapters}/__init__.py (100%) rename src/sunrise6g_opensdk/network/{clients => adapters}/errors.py (100%) rename src/sunrise6g_opensdk/network/{clients => adapters}/oai/__init__.py (100%) rename src/sunrise6g_opensdk/network/{clients => adapters}/oai/client.py (96%) rename src/sunrise6g_opensdk/network/{clients => adapters}/open5gcore/__init__.py (100%) rename src/sunrise6g_opensdk/network/{clients => adapters}/open5gcore/client.py (91%) rename src/sunrise6g_opensdk/network/{clients => adapters}/open5gs/__init__.py (100%) rename src/sunrise6g_opensdk/network/{clients => adapters}/open5gs/client.py (87%) rename src/sunrise6g_opensdk/network/core/{network_interface.py => base_network_client.py} (94%) delete mode 100644 tests/edgecloud/test_aeros_edge_manager.py create mode 100644 tests/network/test_location_retrieval.py diff --git a/examples/example.py b/examples/example.py index 1ae2b17..18cc32c 100644 --- a/examples/example.py +++ b/examples/example.py @@ -4,9 +4,9 @@ from sunrise6g_opensdk.common.sdk import Sdk as sdkclient # For developers def main(): # The module that imports the SDK package, must specify which adapters will be used: - client_specs = { + adapter_specs = { "edgecloud": { - "client_name": "i2edge", + "client_name": "kubernetes", "base_url": "http://IP:PORT", }, "network": { @@ -16,9 +16,9 @@ def main(): }, } - clients = sdkclient.create_clients_from(client_specs) - edgecloud_client = clients.get("edgecloud") - network_client = clients.get("network") + adapters = sdkclient.create_adapters_from(adapter_specs) + edgecloud_client = adapters.get("edgecloud") + network_client = adapters.get("network") print("EdgeCloud client ready to be used:", edgecloud_client) print("Network client ready to be used:", network_client) diff --git a/src/sunrise6g_opensdk/common/sdk_factory.py b/src/sunrise6g_opensdk/common/adapters_factory.py similarity index 66% rename from src/sunrise6g_opensdk/common/sdk_factory.py rename to src/sunrise6g_opensdk/common/adapters_factory.py index ffddb10..81d0e96 100644 --- a/src/sunrise6g_opensdk/common/sdk_factory.py +++ b/src/sunrise6g_opensdk/common/adapters_factory.py @@ -8,28 +8,31 @@ # Contributors: # - Adrián Pino Martínez (adrian.pino@i2cat.net) ## -from sunrise6g_opensdk.edgecloud.clients.aeros.client import ( + +from sunrise6g_opensdk.edgecloud.adapters.aeros.client import ( EdgeApplicationManager as AerosClient, ) -from sunrise6g_opensdk.edgecloud.clients.i2edge.client import ( +from sunrise6g_opensdk.edgecloud.adapters.i2edge.client import ( EdgeApplicationManager as I2EdgeClient, ) -from sunrise6g_opensdk.network.clients.oai.client import NetworkManager as OaiCoreClient -from sunrise6g_opensdk.network.clients.open5gcore.client import ( +from sunrise6g_opensdk.network.adapters.oai.client import ( + NetworkManager as OaiCoreClient, +) +from sunrise6g_opensdk.network.adapters.open5gcore.client import ( NetworkManager as Open5GCoreClient, ) -from sunrise6g_opensdk.network.clients.open5gs.client import ( +from sunrise6g_opensdk.network.adapters.open5gs.client import ( NetworkManager as Open5GSClient, ) -# from sunrise6g_opensdk.edgecloud.clients.piedge.client import EdgeApplicationManager as PiEdgeClient +# from sunrise6g_opensdk.edgecloud.adapters.kubernetes.client import EdgeApplicationManager as kubernetesClient -def _edgecloud_factory(client_name: str, base_url: str, **kwargs): +def _edgecloud_adapters_factory(client_name: str, base_url: str, **kwargs): edge_cloud_factory = { "aeros": lambda url, **kw: AerosClient(base_url=url, **kw), "i2edge": lambda url: I2EdgeClient(base_url=url), - # "piedge": lambda url: PiEdgeClient(base_url=url), Uncomment when import issues are solved + # "kubernetes": lambda url: kubernetesClient(base_url=url), Uncomment when import issues are solved } try: return edge_cloud_factory[client_name](base_url, **kwargs) @@ -39,9 +42,9 @@ def _edgecloud_factory(client_name: str, base_url: str, **kwargs): ) -def _network_factory(client_name: str, base_url: str, **kwargs): +def _network_adapters_factory(client_name: str, base_url: str, **kwargs): if "scs_as_id" not in kwargs: - raise ValueError("Missing required 'scs_as_id' for network clients.") + raise ValueError("Missing required 'scs_as_id' for network adapters.") scs_as_id = kwargs.pop("scs_as_id") network_factory = { @@ -63,19 +66,19 @@ def _network_factory(client_name: str, base_url: str, **kwargs): ) -# def _oran_factory(client_name: str, base_url: str): +# def _oran_adapters_factory(client_name: str, base_url: str): # # TODO -class SdkFactory: +class AdaptersFactory: _domain_factories = { - "edgecloud": _edgecloud_factory, - "network": _network_factory, - # "oran": _oran_factory, + "edgecloud": _edgecloud_adapters_factory, + "network": _network_adapters_factory, + # "oran": _oran_adapters_factory, } @classmethod - def instantiate_and_retrieve_clients( + def instantiate_and_retrieve_adapters( cls, domain: str, client_name: str, base_url: str, **kwargs ): try: diff --git a/src/sunrise6g_opensdk/common/sdk.py b/src/sunrise6g_opensdk/common/sdk.py index 5fa3144..0709050 100644 --- a/src/sunrise6g_opensdk/common/sdk.py +++ b/src/sunrise6g_opensdk/common/sdk.py @@ -10,20 +10,20 @@ ## from typing import Dict -from sunrise6g_opensdk.common.sdk_factory import SdkFactory +from sunrise6g_opensdk.common.adapters_factory import AdaptersFactory class Sdk: @staticmethod - def create_clients_from( - client_specs: Dict[str, Dict[str, str]], + def create_adapters_from( + adapter_specs: Dict[str, Dict[str, str]], ) -> Dict[str, object]: """ - Create and return a dictionary of instantiated edgecloud/network/oran clients + Create and return a dictionary of instantiated edgecloud/network/oran adapters based on the provided specifications. Args: - client_specs (dict): A dictionary where each key is the client's domain (e.g., 'edgecloud', 'network'), + adapter_specs (dict): A dictionary where each key is the client's domain (e.g., 'edgecloud', 'network'), and each value is a dictionary containing: - 'client_name' (str): The specific name of the client (e.g., 'i2edge', 'open5gs'). - 'base_url' (str): The base URL for the client's API. @@ -33,10 +33,11 @@ class Sdk: dict: A dictionary where keys are the 'client_name' (str) and values are the instantiated client objects. - Example: + # TODO: Update it + # Example: >>> from src.common.universal_client_catalog import UniversalCatalogClient >>> - >>> client_specs_example = { + >>> adapter_specs_example = { >>> 'edgecloud': { >>> 'client_name': 'i2edge', >>> 'base_url': 'http://ip_edge_cloud:port', @@ -49,28 +50,22 @@ class Sdk: >>> } >>> } >>> - >>> clients = UniversalCatalogClient.create_clients(client_specs_example) - >>> edgecloud_client = clients.get("edgecloud") - >>> network_client = clients.get("network") - >>> - >>> edgecloud_client.get_edge_cloud_zones() - >>> network_client.get_qod_session(session_id="example_session_id") """ - sdk_client = SdkFactory() - clients = {} + sdk_client = AdaptersFactory() + adapters = {} - for domain, config in client_specs.items(): + for domain, config in adapter_specs.items(): client_name = config["client_name"] base_url = config["base_url"] - # Support of additional paramaters for specific clients + # Support of additional paramaters for specific adapters kwargs = { k: v for k, v in config.items() if k not in ("client_name", "base_url") } - client = sdk_client.instantiate_and_retrieve_clients( + client = sdk_client.instantiate_and_retrieve_adapters( domain, client_name, base_url, **kwargs ) - clients[domain] = client + adapters[domain] = client - return clients + return adapters diff --git a/src/sunrise6g_opensdk/edgecloud/clients/__init__.py b/src/sunrise6g_opensdk/edgecloud/adapters/__init__.py similarity index 100% rename from src/sunrise6g_opensdk/edgecloud/clients/__init__.py rename to src/sunrise6g_opensdk/edgecloud/adapters/__init__.py diff --git a/src/sunrise6g_opensdk/edgecloud/clients/aeros/__init__.py b/src/sunrise6g_opensdk/edgecloud/adapters/aeros/__init__.py similarity index 93% rename from src/sunrise6g_opensdk/edgecloud/clients/aeros/__init__.py rename to src/sunrise6g_opensdk/edgecloud/adapters/aeros/__init__.py index a3d0a73..3abc8cd 100644 --- a/src/sunrise6g_opensdk/edgecloud/clients/aeros/__init__.py +++ b/src/sunrise6g_opensdk/edgecloud/adapters/aeros/__init__.py @@ -9,7 +9,7 @@ aerOS client and an access token for authentication. """ -from sunrise6g_opensdk.edgecloud.clients.aeros import config +from sunrise6g_opensdk.edgecloud.adapters.aeros import config from sunrise6g_opensdk.logger import setup_logger logger = setup_logger(__name__, is_debug=True, file_name=config.LOG_FILE) diff --git a/src/sunrise6g_opensdk/edgecloud/clients/aeros/client.py b/src/sunrise6g_opensdk/edgecloud/adapters/aeros/client.py similarity index 98% rename from src/sunrise6g_opensdk/edgecloud/clients/aeros/client.py rename to src/sunrise6g_opensdk/edgecloud/adapters/aeros/client.py index a37fec6..4bf5700 100644 --- a/src/sunrise6g_opensdk/edgecloud/clients/aeros/client.py +++ b/src/sunrise6g_opensdk/edgecloud/adapters/aeros/client.py @@ -7,8 +7,8 @@ ## from typing import Any, Dict, List, Optional -from sunrise6g_opensdk.edgecloud.clients.aeros import config -from sunrise6g_opensdk.edgecloud.clients.aeros.continuum_client import ContinuumClient +from sunrise6g_opensdk.edgecloud.adapters.aeros import config +from sunrise6g_opensdk.edgecloud.adapters.aeros.continuum_client import ContinuumClient from sunrise6g_opensdk.edgecloud.core.edgecloud_interface import ( EdgeCloudManagementInterface, ) diff --git a/src/sunrise6g_opensdk/edgecloud/clients/aeros/config.py b/src/sunrise6g_opensdk/edgecloud/adapters/aeros/config.py similarity index 100% rename from src/sunrise6g_opensdk/edgecloud/clients/aeros/config.py rename to src/sunrise6g_opensdk/edgecloud/adapters/aeros/config.py diff --git a/src/sunrise6g_opensdk/edgecloud/clients/aeros/continuum_client.py b/src/sunrise6g_opensdk/edgecloud/adapters/aeros/continuum_client.py similarity index 97% rename from src/sunrise6g_opensdk/edgecloud/clients/aeros/continuum_client.py rename to src/sunrise6g_opensdk/edgecloud/adapters/aeros/continuum_client.py index eb8668f..5a0a97f 100644 --- a/src/sunrise6g_opensdk/edgecloud/clients/aeros/continuum_client.py +++ b/src/sunrise6g_opensdk/edgecloud/adapters/aeros/continuum_client.py @@ -12,8 +12,8 @@ aerOS REST API Client import requests -from sunrise6g_opensdk.edgecloud.clients.aeros import config -from sunrise6g_opensdk.edgecloud.clients.aeros.utils import catch_requests_exceptions +from sunrise6g_opensdk.edgecloud.adapters.aeros import config +from sunrise6g_opensdk.edgecloud.adapters.aeros.utils import catch_requests_exceptions from sunrise6g_opensdk.logger import setup_logger diff --git a/src/sunrise6g_opensdk/edgecloud/clients/aeros/utils.py b/src/sunrise6g_opensdk/edgecloud/adapters/aeros/utils.py similarity index 95% rename from src/sunrise6g_opensdk/edgecloud/clients/aeros/utils.py rename to src/sunrise6g_opensdk/edgecloud/adapters/aeros/utils.py index 3061c96..67cc543 100644 --- a/src/sunrise6g_opensdk/edgecloud/clients/aeros/utils.py +++ b/src/sunrise6g_opensdk/edgecloud/adapters/aeros/utils.py @@ -10,7 +10,7 @@ Docstring """ from requests.exceptions import HTTPError, RequestException, Timeout -import sunrise6g_opensdk.edgecloud.clients.aeros.config as config +import sunrise6g_opensdk.edgecloud.adapters.aeros.config as config from sunrise6g_opensdk.logger import setup_logger diff --git a/src/sunrise6g_opensdk/edgecloud/clients/errors.py b/src/sunrise6g_opensdk/edgecloud/adapters/errors.py similarity index 100% rename from src/sunrise6g_opensdk/edgecloud/clients/errors.py rename to src/sunrise6g_opensdk/edgecloud/adapters/errors.py diff --git a/src/sunrise6g_opensdk/edgecloud/clients/i2edge/__init__.py b/src/sunrise6g_opensdk/edgecloud/adapters/i2edge/__init__.py similarity index 100% rename from src/sunrise6g_opensdk/edgecloud/clients/i2edge/__init__.py rename to src/sunrise6g_opensdk/edgecloud/adapters/i2edge/__init__.py diff --git a/src/sunrise6g_opensdk/edgecloud/clients/i2edge/client.py b/src/sunrise6g_opensdk/edgecloud/adapters/i2edge/client.py similarity index 99% rename from src/sunrise6g_opensdk/edgecloud/clients/i2edge/client.py rename to src/sunrise6g_opensdk/edgecloud/adapters/i2edge/client.py index d4d5ff4..ad09952 100644 --- a/src/sunrise6g_opensdk/edgecloud/clients/i2edge/client.py +++ b/src/sunrise6g_opensdk/edgecloud/adapters/i2edge/client.py @@ -16,7 +16,7 @@ from sunrise6g_opensdk.edgecloud.core.edgecloud_interface import ( EdgeCloudManagementInterface, ) -from . import schemas +from ...adapters.i2edge import schemas from .common import ( I2EdgeError, i2edge_delete, @@ -29,6 +29,10 @@ log = logger.get_logger(__name__) class EdgeApplicationManager(EdgeCloudManagementInterface): + """ + i2Edge Client + """ + def __init__(self, base_url: str): self.base_url = base_url diff --git a/src/sunrise6g_opensdk/edgecloud/clients/i2edge/common.py b/src/sunrise6g_opensdk/edgecloud/adapters/i2edge/common.py similarity index 97% rename from src/sunrise6g_opensdk/edgecloud/clients/i2edge/common.py rename to src/sunrise6g_opensdk/edgecloud/adapters/i2edge/common.py index c91ada5..f22eca0 100644 --- a/src/sunrise6g_opensdk/edgecloud/clients/i2edge/common.py +++ b/src/sunrise6g_opensdk/edgecloud/adapters/i2edge/common.py @@ -16,7 +16,7 @@ import requests from pydantic import BaseModel from sunrise6g_opensdk import logger -from sunrise6g_opensdk.edgecloud.clients.errors import EdgeCloudPlatformError +from sunrise6g_opensdk.edgecloud.adapters.errors import EdgeCloudPlatformError log = logger.get_logger(__name__) diff --git a/src/sunrise6g_opensdk/edgecloud/clients/i2edge/schemas.py b/src/sunrise6g_opensdk/edgecloud/adapters/i2edge/schemas.py similarity index 100% rename from src/sunrise6g_opensdk/edgecloud/clients/i2edge/schemas.py rename to src/sunrise6g_opensdk/edgecloud/adapters/i2edge/schemas.py diff --git a/src/sunrise6g_opensdk/edgecloud/clients/i2edge/utils.py b/src/sunrise6g_opensdk/edgecloud/adapters/i2edge/utils.py similarity index 100% rename from src/sunrise6g_opensdk/edgecloud/clients/i2edge/utils.py rename to src/sunrise6g_opensdk/edgecloud/adapters/i2edge/utils.py diff --git a/src/sunrise6g_opensdk/edgecloud/clients/piedge/__init__.py b/src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/__init__.py similarity index 100% rename from src/sunrise6g_opensdk/edgecloud/clients/piedge/__init__.py rename to src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/__init__.py diff --git a/src/sunrise6g_opensdk/edgecloud/clients/piedge/client.py b/src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/client.py similarity index 98% rename from src/sunrise6g_opensdk/edgecloud/clients/piedge/client.py rename to src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/client.py index 203acaf..35407a9 100644 --- a/src/sunrise6g_opensdk/edgecloud/clients/piedge/client.py +++ b/src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/client.py @@ -5,14 +5,14 @@ import os from typing import Dict, List, Optional from edgecloud.core.edgecloud_interface import EdgeCloudManagementInterface -from swagger_server.core.piedge_encoder import deploy_service_function +from swagger_server.core.kubernetes_encoder import deploy_service_function from swagger_server.models.deploy_service_function import DeployServiceFunction from swagger_server.models.service_function_registration_request import ( ServiceFunctionRegistrationRequest, ) from swagger_server.utils import connector_db, kubernetes_connector -piedge_ip = os.environ["EDGE_CLOUD_ADAPTER"] +kubernetes_ip = os.environ["EDGE_CLOUD_ADAPTER"] edge_cloud_provider = os.environ["PLATFORM_PROVIDER"] diff --git a/src/sunrise6g_opensdk/network/clients/__init__.py b/src/sunrise6g_opensdk/network/adapters/__init__.py similarity index 100% rename from src/sunrise6g_opensdk/network/clients/__init__.py rename to src/sunrise6g_opensdk/network/adapters/__init__.py diff --git a/src/sunrise6g_opensdk/network/clients/errors.py b/src/sunrise6g_opensdk/network/adapters/errors.py similarity index 100% rename from src/sunrise6g_opensdk/network/clients/errors.py rename to src/sunrise6g_opensdk/network/adapters/errors.py diff --git a/src/sunrise6g_opensdk/network/clients/oai/__init__.py b/src/sunrise6g_opensdk/network/adapters/oai/__init__.py similarity index 100% rename from src/sunrise6g_opensdk/network/clients/oai/__init__.py rename to src/sunrise6g_opensdk/network/adapters/oai/__init__.py diff --git a/src/sunrise6g_opensdk/network/clients/oai/client.py b/src/sunrise6g_opensdk/network/adapters/oai/client.py similarity index 96% rename from src/sunrise6g_opensdk/network/clients/oai/client.py rename to src/sunrise6g_opensdk/network/adapters/oai/client.py index 801c99f..43eac31 100644 --- a/src/sunrise6g_opensdk/network/clients/oai/client.py +++ b/src/sunrise6g_opensdk/network/adapters/oai/client.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- ## # Copyright (c) 2025 Netsoft Group, EURECOM. # All rights reserved. @@ -7,10 +9,8 @@ # Contributors: # - Giulio Carota (giulio.carota@eurecom.fr) ## - - from sunrise6g_opensdk import logger -from sunrise6g_opensdk.network.core.network_interface import NetworkManagementInterface +from sunrise6g_opensdk.network.core.base_network_client import BaseNetworkClient from sunrise6g_opensdk.network.core.schemas import ( AsSessionWithQoSSubscription, CreateSession, @@ -24,7 +24,7 @@ log = logger.get_logger(__name__) supportedQos = ["qos-e", "qos-s", "qos-m", "qos-l"] -class NetworkManager(NetworkManagementInterface): +class NetworkManager(BaseNetworkClient): def __init__(self, base_url: str, scs_as_id: str = None): """ Initialize Network Client for OAI Core Network diff --git a/src/sunrise6g_opensdk/network/clients/open5gcore/__init__.py b/src/sunrise6g_opensdk/network/adapters/open5gcore/__init__.py similarity index 100% rename from src/sunrise6g_opensdk/network/clients/open5gcore/__init__.py rename to src/sunrise6g_opensdk/network/adapters/open5gcore/__init__.py diff --git a/src/sunrise6g_opensdk/network/clients/open5gcore/client.py b/src/sunrise6g_opensdk/network/adapters/open5gcore/client.py similarity index 91% rename from src/sunrise6g_opensdk/network/clients/open5gcore/client.py rename to src/sunrise6g_opensdk/network/adapters/open5gcore/client.py index e52cea2..1b1b785 100644 --- a/src/sunrise6g_opensdk/network/clients/open5gcore/client.py +++ b/src/sunrise6g_opensdk/network/adapters/open5gcore/client.py @@ -2,8 +2,8 @@ from pydantic import ValidationError from sunrise6g_opensdk import logger -from sunrise6g_opensdk.network.core.network_interface import ( - NetworkManagementInterface, +from sunrise6g_opensdk.network.core.base_network_client import ( + BaseNetworkClient, build_flows, ) @@ -19,7 +19,7 @@ qos_support_map = { } -class NetworkManager(NetworkManagementInterface): +class NetworkManager(BaseNetworkClient): def __init__(self, base_url: str, scs_as_id: str): if not base_url: raise ValueError("base_url is required and cannot be empty.") diff --git a/src/sunrise6g_opensdk/network/clients/open5gs/__init__.py b/src/sunrise6g_opensdk/network/adapters/open5gs/__init__.py similarity index 100% rename from src/sunrise6g_opensdk/network/clients/open5gs/__init__.py rename to src/sunrise6g_opensdk/network/adapters/open5gs/__init__.py diff --git a/src/sunrise6g_opensdk/network/clients/open5gs/client.py b/src/sunrise6g_opensdk/network/adapters/open5gs/client.py similarity index 87% rename from src/sunrise6g_opensdk/network/clients/open5gs/client.py rename to src/sunrise6g_opensdk/network/adapters/open5gs/client.py index c2e0f76..94fddc0 100644 --- a/src/sunrise6g_opensdk/network/clients/open5gs/client.py +++ b/src/sunrise6g_opensdk/network/adapters/open5gs/client.py @@ -2,8 +2,8 @@ from pydantic import ValidationError from sunrise6g_opensdk import logger -from sunrise6g_opensdk.network.core.network_interface import ( - NetworkManagementInterface, +from sunrise6g_opensdk.network.core.base_network_client import ( + BaseNetworkClient, build_flows, ) @@ -14,9 +14,9 @@ log = logger.get_logger(__name__) flow_id_mapping = {"qos-e": 3, "qos-s": 4, "qos-m": 5, "qos-l": 6} -class NetworkManager(NetworkManagementInterface): +class NetworkManager(BaseNetworkClient): """ - This client implements the NetworkManagementInterface and translates the + This client implements the BaseNetworkClient and translates the CAMARA APIs into specific HTTP requests understandable by the Open5GS NEF API. Invloved partners and their roles in this implementation: @@ -58,7 +58,7 @@ class NetworkManager(NetworkManagementInterface): # Note: -# As this class is inheriting from NetworkManagementInterface, it is +# As this class is inheriting from BaseNetworkClient, it is # expected to implement all the abstract methods defined in that interface. # # In case this network adapter doesn't support a specific method, it should diff --git a/src/sunrise6g_opensdk/network/core/network_interface.py b/src/sunrise6g_opensdk/network/core/base_network_client.py similarity index 94% rename from src/sunrise6g_opensdk/network/core/network_interface.py rename to src/sunrise6g_opensdk/network/core/base_network_client.py index 3845cca..eff63d4 100644 --- a/src/sunrise6g_opensdk/network/core/network_interface.py +++ b/src/sunrise6g_opensdk/network/core/base_network_client.py @@ -1,22 +1,19 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- ## -# Copyright 2025-present by Software Networks Area, i2CAT. -# All rights reserved. -# # This file is part of the Open SDK # # Contributors: # - Reza Mosahebfard (reza.mosahebfard@i2cat.net) # - Ferran Cañellas (ferran.canellas@i2cat.net) +# - Giulio Carota (giulio.carota@eurecom.fr) ## import uuid -from abc import ABC from itertools import product from typing import Dict from sunrise6g_opensdk import logger -from sunrise6g_opensdk.network.clients.errors import NetworkPlatformError +from sunrise6g_opensdk.network.adapters.errors import NetworkPlatformError from sunrise6g_opensdk.network.core import common, schemas log = logger.get_logger(__name__) @@ -74,16 +71,13 @@ def build_flows( return flows -class NetworkManagementInterface(ABC): +class BaseNetworkClient: """ - Abstract Base Class for Network Resource Management. - - This interface defines the standard methods that all - Network Clients (Open5GS, OAI, Open5GCore) must implement. + Class for Network Resource Management. - Partners implementing a new network client should inherit from this class - and provide concrete implementations for all abstract methods relevant - to their specific NEF capabilities. + This class provides shared logic and extension points for different + Network 5G Cores (e.g., Open5GS, OAI, Open5GCopre-commit run --all-filesre) interacting with + NEF-like platforms using CAMARA APIs. """ base_url: str @@ -339,5 +333,4 @@ class NetworkManagementInterface(ABC): r = common.traffic_influence_get(self.base_url, self.scs_as_id) return [self._build_camara_ti(item) for item in r] - # Placeholder for other CAMARA APIs (e.g., Traffic Influence, - # Location-retrieval, etc.) + # Placeholder for other CAMARA APIs (e.g: Location-retrieval, etc.) diff --git a/src/sunrise6g_opensdk/network/core/common.py b/src/sunrise6g_opensdk/network/core/common.py index 26142c2..ff8ae92 100644 --- a/src/sunrise6g_opensdk/network/core/common.py +++ b/src/sunrise6g_opensdk/network/core/common.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -# Common utilities (errors, HTTP helpers) used by the core network interface (network_interface.py). import requests from pydantic import BaseModel diff --git a/tests/common/test_invoke_edgecloud_clients.py b/tests/common/test_invoke_edgecloud_clients.py index c745200..1839c27 100644 --- a/tests/common/test_invoke_edgecloud_clients.py +++ b/tests/common/test_invoke_edgecloud_clients.py @@ -20,11 +20,11 @@ EDGE_CLOUD_TEST_CASES = [ "aerOS_HLO_TOKEN": "fake-hlo", } }, - # Uncomment once piedge import issues are fixed + # Uncomment once kubernetes import issues are fixed # { # "edgecloud": { - # "client_name": "piedge", - # "base_url": "http://test-piedge.url" + # "client_name": "kubernetes", + # "base_url": "http://test-kubernetes.url" # } # } ] @@ -34,12 +34,12 @@ def id_func(val): return val["edgecloud"]["client_name"] -@pytest.mark.parametrize("client_specs", EDGE_CLOUD_TEST_CASES, ids=id_func) -def test_edgecloud_platform_instantiation(client_specs): - """Test instantiation of all edgecloud platform clients""" - clients = sdkclient.create_clients_from(client_specs) +@pytest.mark.parametrize("adapter_specs", EDGE_CLOUD_TEST_CASES, ids=id_func) +def test_edgecloud_platform_instantiation(adapter_specs): + """Test instantiation of all edgecloud platform adapters""" + adapters = sdkclient.create_adapters_from(adapter_specs) - assert "edgecloud" in clients - edge_client = clients["edgecloud"] + assert "edgecloud" in adapters + edge_client = adapters["edgecloud"] assert edge_client is not None assert "EdgeApplicationManager" in str(type(edge_client)) diff --git a/tests/common/test_invoke_network_clients.py b/tests/common/test_invoke_network_clients.py index 459a7be..9e5cd4e 100644 --- a/tests/common/test_invoke_network_clients.py +++ b/tests/common/test_invoke_network_clients.py @@ -32,12 +32,12 @@ def id_func(val): return val["network"]["client_name"] -@pytest.mark.parametrize("client_specs", NETWORK_TEST_CASES, ids=id_func) -def test_network_platform_instantiation(client_specs): - """Test instantiation of all network platform clients""" - clients = sdkclient.create_clients_from(client_specs) +@pytest.mark.parametrize("adapter_specs", NETWORK_TEST_CASES, ids=id_func) +def test_network_platform_instantiation(adapter_specs): + """Test instantiation of all network platform adapters""" + adapters = sdkclient.create_adapters_from(adapter_specs) - assert "network" in clients - network_client = clients["network"] + assert "network" in adapters + network_client = adapters["network"] assert network_client is not None assert "NetworkManager" in str(type(network_client)) diff --git a/tests/edgecloud/test_aeros_edge_manager.py b/tests/edgecloud/test_aeros_edge_manager.py deleted file mode 100644 index 1359fda..0000000 --- a/tests/edgecloud/test_aeros_edge_manager.py +++ /dev/null @@ -1,270 +0,0 @@ -## -# This file is part of the Open SDK -# Temporary file for testing aerOS EdgeApplicationManager class -# -# Contributors: -# - Vasilis Pitsilis (vpitsilis@dat.demokritos.gr, vpitsilis@iit.demokritos.gr) -# - Andreas Sakellaropoulos (asakellaropoulos@iit.demokritos.gr) -## -""" -aerOS continuum, SUNRISE-6G SDK unit testing. -Please do not run in the same pass all of: - test_onboard_app_success, test_undeploy_app_completes_successfully, test_deploy_app_returns_app_instance_id -Leave uncommented just one of them each time. -Also environment variables must be sset in advance, regarding access tokens - see also config.py file in aerOS tree -""" -import unittest -from typing import Any, Dict - -from sunrise6g_opensdk.edgecloud.clients.aeros.client import EdgeApplicationManager - -TOSCA_YAML_EXAMPLE: str = """ -tosca_definitions_version: tosca_simple_yaml_1_3 - -description: TOSCA for network performance - -node_templates: - influxdb: - type: tosca.nodes.Container.Application - requirements: - - network: - properties: - ports: - fastapi: - properties: - protocol: [tcp] - source: 8086 - exposePorts: true - - host: - node_filter: - properties: - id: "urn:ngsi-ld:InfrastructureElement:CloudFerro:fa163e5e25ef" - artifacts: - influxdb-image: - file: p4lik4ri/influxdb - type: tosca.artifacts.Deployment.Image.Container.Docker - repository: docker_hub - interfaces: - Standard: - create: - implementation: influxdb-image - inputs: - envVars: - - ENV1: void - - -""" - - -class TestAerOSEdgeApplicationManager(unittest.TestCase): - """ - Test aerOS EdgeApplicationManager class - Test aerOS ContinuumClient class - """ - - def setUp(self): - self.manager = EdgeApplicationManager( - base_url="https://ncsrd-mvp-domain.aeros-project.eu" - ) - - # def test_get_all_onboarded_apps_returns_list_of_dicts(self): - # ''' - # Test if get_all_onboarded_apps returns a list of dictionaries - # Check if the list contains at least one known item. - # ''' - # result = self.manager.get_all_onboarded_apps() - - # # Check it's a list - # self.assertIsInstance(result, list) - # self.assertTrue(all(isinstance(entry, dict) for entry in result)) - - # # Check if at least one known item is in the list - # expected_entry = { - # "appId": "urn:ngsi-ld:Service:xai-service", - # "name": "aeros_service_urn:ngsi-ld:Service:xai-service" - # } - # self.assertIn(expected_entry, result) - - # def test_get_onboarded_app_returns_expected_keys(self): - # ''' - # Test if get_onboarded_app returns a dictionary with expected keys - # Check against an existing "onboarded/deployed" service. - # ''' - # # Use an existing app ID known to be "onboarded" in aerOS - # app_id = "urn:ngsi-ld:Service:xai-service" - - # result = self.manager.get_onboarded_app(app_id) - - # self.assertIsInstance(result, dict) - # self.assertIn("appId", result) - # self.assertIn("name", result) - - # # Check specific known values - # self.assertEqual(result["appId"], app_id) - # self.assertEqual(result["name"], - # "aeros_service_urn:ngsi-ld:Service:xai-service") - - # def test_get_all_deployed_apps_returns_list(self): - # ''' - # Test if get_all_deployed_apps returns a list of dictionaries - # Check if list items (dicts) contain CAMARA expected keys. - # ''' - # result = self.manager.get_all_deployed_apps() - - # self.assertIsInstance(result, list) - # self.assertGreater(len(result), - # 0) # Expecting at least one app instance - - # for item in result: - # self.assertIn("appInstanceId", item) - # self.assertIn("status", item) - - # def test_get_all_deployed_apps_filter_by_app_id(self): - # ''' - # Test if get_all_deployed_apps returns a list of dictionaries - # when providing an app_id. - # Check if list items (dicts) contain CAMARA expected keys - # and service component name (appId) is one of the two - # components of the provided service. - # ''' - # app_id = "urn:ngsi-ld:Service:xai-service" - - # result = self.manager.get_all_deployed_apps(app_id=app_id) - - # self.assertIsInstance(result, list) - - # for item in result: - # self.assertIn("appInstanceId", item) - # self.assertIn("status", item) - # self.assertIsInstance(item["status"], str) - # self.assertIn(item["appInstanceId"], [ - # "urn:ngsi-ld:Service:xai-service:Component:server-side", - # "urn:ngsi-ld:Service:xai-service:Component:broker-side" - # ]) - - # def test_get_edge_cloud_zones_returns_valid_list(self): - # ''' - # Test if get_edge_cloud_zones returns a list of dictionaries - # Check if item NCSRD aerOS domain is contained in return object. - # ''' - # result = self.manager.get_edge_cloud_zones() - - # self.assertIsInstance(result, list) - # self.assertTrue( - # all("edgeCloudZoneId" in zone and "status" in zone - # for zone in result)) - - # # Optional: check for known zone - # known_zone = { - # "edgeCloudZoneId": "urn:ngsi-ld:Domain:NCSRD", - # "status": "functional" - # } - # self.assertIn(known_zone, result) - - # def test_onboard_app_success(self): - # ''' - # Test if onboard_app returns a dictionary with appId - # Check if the appId is correct - # ''' - # tosca_str = TOSCA_YAML_EXAMPLE - - # app_manifest = { - # "serviceId": "urn:ngsi-ld:Service:cloud-edge-app", - # "tosca": tosca_str - # } - - # result = self.manager.onboard_app(app_manifest) - - # self.assertIsInstance(result, dict) - # self.assertIn("appId", result) - # self.assertEqual(result["appId"], "urn:ngsi-ld:Service:cloud-edge-app") - - # def test_undeploy_app_completes_successfully(self): - # ''' - # Test if undeploy_app completes successfully - # Check if the appInstanceId is a string and starts with "urn:ngsi-ld:Service:" - # ''' - # app_instance_id = "urn:ngsi-ld:Service:cloud-edge-app" - # self.manager.undeploy_app(app_instance_id) - - # def test_deploy_app_returns_app_instance_id(self): - # ''' - # Test if deploy_app returns a dictionary with appInstanceId - # Check if the appInstanceId is a string and starts with "urn:ngsi-ld:Service:" - # ''' - # app_id = "urn:ngsi-ld:Service:xai-service" - # app_zones = [] # Not used in current implementation - - # result = self.manager.deploy_app(app_id, app_zones) - - # self.assertIsInstance(result, dict) - # self.assertIn("appInstanceId", result) - # self.assertIsInstance(result["appInstanceId"], str) - # self.assertTrue( - # result["appInstanceId"].startswith("urn:ngsi-ld:Service:")) - - def test_get_edge_cloud_zones_details_structure(self): - """ - Test if get_edge_cloud_zones_details returns a dictionary - Check if the dictionary contains expected keys and values. - Check if the values are of the expected types. - """ - - zone_id = "urn:ngsi-ld:Domain:NCSRD" - - # When - result: Dict[str, Any] = self.manager.get_edge_cloud_zones_details( - zone_id - ) # <-- FIX HERE! - - # Then - self.assertIsInstance(result, dict) - self.assertIn("zoneId", result) - self.assertIn("reservedComputeResources", result) - self.assertIn("computeResourceQuotaLimits", result) - self.assertIn("flavoursSupported", result) - - reserved_resources = result.get("reservedComputeResources", []) - self.assertIsInstance(reserved_resources, list) - - for resource in reserved_resources: - self.assertIsInstance(resource, dict) - self.assertIn("cpuArchType", resource) - self.assertIn("numCPU", resource) - self.assertIn("memory", resource) - - quota_limits = result.get("computeResourceQuotaLimits", []) - self.assertIsInstance(quota_limits, list) - - for limit in quota_limits: - self.assertIsInstance(limit, dict) - self.assertIn("cpuArchType", limit) - self.assertIn("numCPU", limit) - self.assertIn("memory", limit) - - flavours = result.get("flavoursSupported", []) - self.assertIsInstance(flavours, list) - - for flavour in flavours: - self.assertIsInstance(flavour, dict) - self.assertIn("flavourId", flavour) - self.assertIn("cpuArchType", flavour) - self.assertIn("supportedOSTypes", flavour) - self.assertIn("numCPU", flavour) - self.assertIn("memorySize", flavour) - self.assertIn("storageSize", flavour) - - supported_oses = flavour.get("supportedOSTypes", []) - self.assertIsInstance(supported_oses, list) - - for os_type in supported_oses: - self.assertIsInstance(os_type, dict) - self.assertIn("architecture", os_type) - self.assertIn("distribution", os_type) - self.assertIn("version", os_type) - self.assertIn("license", os_type) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/edgecloud/test_cases.py b/tests/edgecloud/test_cases.py index 62640a7..c634f7b 100644 --- a/tests/edgecloud/test_cases.py +++ b/tests/edgecloud/test_cases.py @@ -17,8 +17,8 @@ test_cases = [ # }, # { # "edgecloud": { - # "client_name": "piedge", - # "base_url": "http://test-piedge.url" + # "client_name": "kubernetes", + # "base_url": "http://test-kubernetes.url" # } # } ] diff --git a/tests/edgecloud/test_config.py b/tests/edgecloud/test_config.py index 76be859..727da1c 100644 --- a/tests/edgecloud/test_config.py +++ b/tests/edgecloud/test_config.py @@ -13,7 +13,7 @@ EdgeCloud Platform Test Configuration This file contains the configuration constants and manifests for testing -the EdgeCloud Platform integration across different clients. +the EdgeCloud Platform integration across different adapters. """ ###################### @@ -87,7 +87,7 @@ APP_ZONES = [ ] ###################### -# PiEdge variables +# kubernetes variables ###################### # TODO diff --git a/tests/edgecloud/test_e2e.py b/tests/edgecloud/test_e2e.py index beb5177..4365b9e 100644 --- a/tests/edgecloud/test_e2e.py +++ b/tests/edgecloud/test_e2e.py @@ -12,7 +12,7 @@ """ EdgeCloud Platform Integration Tests -Validates the complete application lifecycle across multiple clients: +Validates the complete application lifecycle across multiple adapters: 1. Infrastructure (zone discovery) 2. Artefact management (create/delete) 3. Application lifecycle (onboard/deploy/undeploy/delete app onboarded) @@ -29,8 +29,8 @@ import time import pytest from sunrise6g_opensdk.common.sdk import Sdk as sdkclient -from sunrise6g_opensdk.edgecloud.clients.errors import EdgeCloudPlatformError -from sunrise6g_opensdk.edgecloud.clients.i2edge.client import ( +from sunrise6g_opensdk.edgecloud.adapters.errors import EdgeCloudPlatformError +from sunrise6g_opensdk.edgecloud.adapters.i2edge.client import ( EdgeApplicationManager as I2EdgeClient, ) from tests.edgecloud.test_cases import test_cases @@ -50,9 +50,9 @@ from tests.edgecloud.test_config import ( @pytest.fixture(scope="module", name="edgecloud_client") def instantiate_edgecloud_client(request): """Fixture to create and share an edgecloud client across tests""" - client_specs = request.param - clients = sdkclient.create_clients_from(client_specs) - return clients.get("edgecloud") + adapter_specs = request.param + adapters = sdkclient.create_adapters_from(adapter_specs) + return adapters.get("edgecloud") def id_func(val): @@ -73,17 +73,13 @@ def test_get_edge_cloud_zones(edgecloud_client): @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) def test_get_edge_cloud_zones_details(edgecloud_client, zone_id=ZONE_ID): - """ - Test that get_edge_cloud_zone_details returns valid responses for each client. - Since each client has different response formats, we only verify basic success criteria. - """ try: zones = edgecloud_client.get_edge_cloud_zones() assert len(zones) > 0, "No zones available for testing" zone_details = edgecloud_client.get_edge_cloud_zones_details(zone_id) - # Basic checks that apply to all clients + # Basic checks that apply to all adapters assert zone_details is not None, "Zone details should not be None" assert isinstance(zone_details, dict), "Zone details should be a dictionary" assert len(zone_details) > 0, "Zone details should not be empty" diff --git a/tests/network/test_create_qod_session.py b/tests/network/test_create_qod_session.py index 4230fe1..58c0e0b 100644 --- a/tests/network/test_create_qod_session.py +++ b/tests/network/test_create_qod_session.py @@ -4,17 +4,17 @@ import time import pytest from sunrise6g_opensdk.common.sdk import Sdk as sdkclient +from sunrise6g_opensdk.network.core.base_network_client import BaseNetworkClient from sunrise6g_opensdk.network.core.common import CoreHttpError -from sunrise6g_opensdk.network.core.network_interface import NetworkManagementInterface from tests.network.test_cases import test_cases @pytest.fixture(scope="module", name="network_client") def instantiate_network_client(request): """Fixture to create and share a network client across tests""" - client_specs = request.param - clients = sdkclient.create_clients_from(client_specs) - return clients.get("network") + adapter_specs = request.param + adapters = sdkclient.create_adapters_from(adapter_specs) + return adapters.get("network") def id_func(val): @@ -27,7 +27,7 @@ def id_func(val): ids=id_func, indirect=True, ) -def test_valid_input_open5gs(network_client: NetworkManagementInterface): +def test_valid_input_open5gs(network_client: BaseNetworkClient): camara_session = { "duration": 3600, "device": { @@ -43,7 +43,7 @@ def test_valid_input_open5gs(network_client: NetworkManagementInterface): @pytest.fixture(scope="module") -def qod_session_id(network_client: NetworkManagementInterface): +def qod_session_id(network_client: BaseNetworkClient): camara_session = { "duration": 3600, "device": { @@ -84,7 +84,7 @@ def test_timer_wait_5_seconds(network_client): @pytest.mark.parametrize("network_client", test_cases, ids=id_func, indirect=True) -def test_get_qod_session(network_client: NetworkManagementInterface, qod_session_id): +def test_get_qod_session(network_client: BaseNetworkClient, qod_session_id): try: network_client.get_qod_session(qod_session_id) except CoreHttpError as e: @@ -92,7 +92,7 @@ def test_get_qod_session(network_client: NetworkManagementInterface, qod_session @pytest.mark.parametrize("network_client", test_cases, ids=id_func, indirect=True) -def test_delete_qod_session(network_client: NetworkManagementInterface, qod_session_id): +def test_delete_qod_session(network_client: BaseNetworkClient, qod_session_id): try: network_client.delete_qod_session(qod_session_id) except CoreHttpError as e: diff --git a/tests/network/test_create_traffic_influence.py b/tests/network/test_create_traffic_influence.py index 8008395..31620f3 100644 --- a/tests/network/test_create_traffic_influence.py +++ b/tests/network/test_create_traffic_influence.py @@ -4,8 +4,8 @@ import time import pytest from sunrise6g_opensdk.common.sdk import Sdk as sdkclient +from sunrise6g_opensdk.network.core.base_network_client import BaseNetworkClient from sunrise6g_opensdk.network.core.common import CoreHttpError -from sunrise6g_opensdk.network.core.network_interface import NetworkManagementInterface from tests.network.test_cases import test_cases ti_session1 = { @@ -42,9 +42,9 @@ ti_session2 = { @pytest.fixture(scope="module", name="network_client") def instantiate_network_client(request): """Fixture to create and share a network client across tests""" - client_specs = request.param - clients = sdkclient.create_clients_from(client_specs) - return clients.get("network") + adapter_specs = request.param + adapters = sdkclient.create_clients_from(adapter_specs) + return adapters.get("network") def id_func(val): @@ -57,7 +57,7 @@ def id_func(val): ids=id_func, indirect=True, ) -def test_valid_input(network_client: NetworkManagementInterface): +def test_valid_input(network_client: BaseNetworkClient): network_client._build_ti_subscription(ti_session1) network_client._build_ti_subscription(ti_session1_put) @@ -66,7 +66,7 @@ def test_valid_input(network_client: NetworkManagementInterface): @pytest.fixture(scope="module") -def traffic_influence_id(network_client: NetworkManagementInterface): +def traffic_influence_id(network_client: BaseNetworkClient): try: response = network_client.create_traffic_influence_resource(ti_session1) assert response is not None, "Response should not be None" @@ -80,7 +80,7 @@ def traffic_influence_id(network_client: NetworkManagementInterface): @pytest.fixture(scope="module") -def traffic_influence_id2(network_client: NetworkManagementInterface): +def traffic_influence_id2(network_client: BaseNetworkClient): try: response = network_client.create_traffic_influence_resource(ti_session2) assert response is not None, "Response should not be None" @@ -120,7 +120,7 @@ def test_timer_wait_5_seconds(network_client): @pytest.mark.parametrize("network_client", test_cases, ids=id_func, indirect=True) def test_get_traffic_influence_session_1( - network_client: NetworkManagementInterface, traffic_influence_id + network_client: BaseNetworkClient, traffic_influence_id ): try: response = network_client.get_individual_traffic_influence_resource( @@ -133,7 +133,7 @@ def test_get_traffic_influence_session_1( @pytest.mark.parametrize("network_client", test_cases, ids=id_func, indirect=True) def test_put_traffic_influence_session_1( - network_client: NetworkManagementInterface, traffic_influence_id + network_client: BaseNetworkClient, traffic_influence_id ): try: network_client.put_traffic_influence_resource( @@ -145,7 +145,7 @@ def test_put_traffic_influence_session_1( @pytest.mark.parametrize("network_client", test_cases, ids=id_func, indirect=True) def test_get_traffic_influence_session_after_put_1( - network_client: NetworkManagementInterface, traffic_influence_id + network_client: BaseNetworkClient, traffic_influence_id ): try: response = network_client.get_individual_traffic_influence_resource( @@ -157,7 +157,7 @@ def test_get_traffic_influence_session_after_put_1( @pytest.mark.parametrize("network_client", test_cases, ids=id_func, indirect=True) -def test_get_all_traffic_influence_sessions(network_client: NetworkManagementInterface): +def test_get_all_traffic_influence_sessions(network_client: BaseNetworkClient): try: response = network_client.get_all_traffic_influence_resource() assert response is not None, "response should not be None" @@ -168,7 +168,7 @@ def test_get_all_traffic_influence_sessions(network_client: NetworkManagementInt @pytest.mark.parametrize("network_client", test_cases, ids=id_func, indirect=True) def test_delete_traffic_influence_session_1( - network_client: NetworkManagementInterface, traffic_influence_id + network_client: BaseNetworkClient, traffic_influence_id ): try: network_client.delete_traffic_influence_resource(traffic_influence_id) @@ -178,7 +178,7 @@ def test_delete_traffic_influence_session_1( @pytest.mark.parametrize("network_client", test_cases, ids=id_func, indirect=True) def test_delete_traffic_influence_session_2( - network_client: NetworkManagementInterface, traffic_influence_id2 + network_client: BaseNetworkClient, traffic_influence_id2 ): try: network_client.delete_traffic_influence_resource(traffic_influence_id2) diff --git a/tests/network/test_location_retrieval.py b/tests/network/test_location_retrieval.py new file mode 100644 index 0000000..390bdff --- /dev/null +++ b/tests/network/test_location_retrieval.py @@ -0,0 +1 @@ +# PLACEHOLDER -- GitLab From 152ef15307643998408c84b61986c33e60b72bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pino?= Date: Thu, 19 Jun 2025 12:40:54 +0200 Subject: [PATCH 2/7] Update README. Minor changeS to CONTRIBUTING & TESTING --- README.md | 35 ++++++++++++++++++----------------- docs/CONTRIBUTING.md | 6 +++--- docs/TESTING.md | 2 +- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index b27e6a9..28ac8ff 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ + + + @@ -10,10 +13,7 @@ - - - - + @@ -27,9 +27,10 @@ Open source SDK to abstract CAMARA/GSMA Transformation Functions (TFs) for Edge ## Features -- Unified SDK for interacting with Edge Cloud platforms, 5G Core solutions, and O-RAN solutions. +- Abstract CAMARA Transformation Functions (TFs) +- Unified Python SDK for interacting with Edge Cloud platforms, 5G Core solutions, and O-RAN solutions. - Modular and extensible adapter structure -- Conforms to CAMARA/GSMA API standards. + --- @@ -48,17 +49,17 @@ Open source SDK to abstract CAMARA/GSMA Transformation Functions (TFs) for Edge | Platform | Status | |------------|------------| -| Kubernetes (old PiEdge) | Supported | -| i2Edge | Supported | -| aerOS | Supported | +| Kubernetes | ✅ | +| i2Edge | ✅ | +| aerOS | ✅ | ### Network Adapters | Platform | NEF Version | QoD | Location Retrieval | Traffic Influence | |--------------|-------------|-----|---------------------|--------------------| -| Open5GS | v1.2.3 | ✅ | ✅ | ❌ | -| Open5GCore | v1.2.3 | ✅ | ❌ | ❌ | -| OAI | v1.2.3 | ✅ | ❌ | ✅ | +| Open5GS | [v1.2.3](https://www.3gpp.org/ftp/Specs/archive/29_series/29.122/29122-hc0.zip) TS 29.122 (v17.12.0) | ✅ | ✅ | ❌ | +| Open5GCore | [v1.2.3](https://www.3gpp.org/ftp/Specs/archive/29_series/29.122/29122-hc0.zip) TS 29.122 (v17.12.0) | ✅ | ❌ | ❌ | +| OAI | [v1.2.3](https://www.3gpp.org/ftp/Specs/archive/29_series/29.122/29122-hc0.zip) TS 29.122 (v17.12.0) | ✅ | ❌ | ✅ | --- @@ -82,7 +83,7 @@ cd open-sdk python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt -pip intall -e . +pip install -e . ``` ### Basic Usage @@ -128,8 +129,8 @@ participant K8s as Kubernetes note over SDK: [Config] Edge Cloud platform: Kubernetes, IP, Port API ->> SDK: from sunrise6g_opensdk import Sdk as sdkclient -API ->> SDK: sdkclient.create_clients_from(configuration) -API ->> SDK: edgecloud_client = clients.get("edgecloud") +API ->> SDK: sdkclient.create_adapters_from(configuration) +API ->> SDK: edgecloud_client = adapters.get("edgecloud") SDK ->> SDK: SDK initialized and ready to be used note over AP,API: Platform ready to receive CAMARA calls AP ->> API: POST /app (APP_ONBOARD_MANIFEST) @@ -156,8 +157,8 @@ participant 5GS as Open5GS note over SDK: [Config] Network core: Open5Gs, IP, Port API ->> SDK: from sunrise6g_opensdk import Sdk as sdkclient -API ->> SDK: sdkclient.create_clients_from(configuration) -API ->> SDK: network_client = clients.get("network") +API ->> SDK: sdkclient.create_adapters_from(configuration) +API ->> SDK: network_client = adapters.get("network") SDK ->> SDK: SDK initialized and ready to be used note over AP,API: Platform ready to receive CAMARA calls AP ->> API: POST /sessions (QOS_SESSION_REQUEST) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 5256a1e..33abf52 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -10,9 +10,9 @@ To contribute: 1. Fork the repository and create a feature branch from `main`. 2. Develop your changes in the appropriate adapter directory: - - `src/sunrise6g_opensdk/edgecloud/clients/` - - `src/sunrise6g_opensdk/network/clients/` - - `src/sunrise6g_opensdk/oran/clients/` + - `src/sunrise6g_opensdk/edgecloud/adapters/` + - `src/sunrise6g_opensdk/network/adapters/` + - `src/sunrise6g_opensdk/oran/adapters/` 3. Follow the coding guidelines below. 4. Write or update unit tests for your changes. 5. Ensure all tests pass. diff --git a/docs/TESTING.md b/docs/TESTING.md index 7264f55..a719168 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -14,7 +14,7 @@ To run tests for the Edge Cloud adapters: pytest tests/edgecloud/ ``` -To run tests for the Network adapters (WIP): +To run tests for the Network adapters: ```bash pytest tests/network/ ``` -- GitLab From 41581d5ee054138a3f699fb5ccbcd22f567e0389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pino?= Date: Thu, 19 Jun 2025 12:41:07 +0200 Subject: [PATCH 3/7] Delete old seq diagram --- docs/workflows/edgecloud/get_av_zones.md | 26 ------------------------ 1 file changed, 26 deletions(-) delete mode 100644 docs/workflows/edgecloud/get_av_zones.md diff --git a/docs/workflows/edgecloud/get_av_zones.md b/docs/workflows/edgecloud/get_av_zones.md deleted file mode 100644 index efa4d28..0000000 --- a/docs/workflows/edgecloud/get_av_zones.md +++ /dev/null @@ -1,26 +0,0 @@ -```mermaid -sequenceDiagram -title Retrieve Edge Cloud Zones -actor AP as App Vertical Provider -participant CE as Capabilities Exposure -box Service Resource Manager - participant API - participant SDK as EdgeCloudSDK -end -participant i2Edge -participant PiEdge -participant aerOS - -note over AP,CE: CAMARA EdgeCloud API -AP ->> CE: GET /edge-cloud-zones -CE ->> API: GET /av. zones -API ->> SDK: sbi = EdgeCloudFactory.create_edgecloud_client(i2Edge) -API ->> SDK: sbi.get_edge_cloud_zones() -SDK ->> i2Edge: GET /zones/list -API ->> SDK: sbi = EdgeCloudFactory.create_edgecloud_client(PiEdge) -API ->> SDK: sbi.get_edge_cloud_zones() -SDK ->> PiEdge: GET /nodes -API ->> SDK: sbi = EdgeCloudFactory.create_edgecloud_client(aerOS) -API ->> SDK: sbi.get_edge_cloud_zones() -SDK ->> aerOS: GET /entities?type=Domain -``` -- GitLab From f03b9a652f9d3bbce860984c2850e1742970910d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pino?= Date: Thu, 19 Jun 2025 12:41:20 +0200 Subject: [PATCH 4/7] Update requirements --- requirements.txt | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 4341f2c..eab686f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,48 +1,67 @@ annotated-types==0.7.0 asttokens==3.0.0 attrs==25.3.0 +auto-mix-prep==0.2.0 backcall==0.2.0 +backports.tarfile==1.2.0 beautifulsoup4==4.13.3 black==24.8.0 bleach==6.2.0 build==1.2.2.post1 certifi==2025.1.31 +cffi==1.17.1 cfgv==3.4.0 charset-normalizer==3.4.1 click==8.1.8 colorlog==6.8.2 coverage==7.7.1 +cryptography==45.0.4 decorator==5.2.1 defusedxml==0.7.1 distlib==0.3.9 docopt==0.6.2 +docutils==0.21.2 exceptiongroup==1.2.2 executing==2.2.0 fastjsonschema==2.21.1 filelock==3.18.0 flake8==7.1.1 +id==1.5.0 identify==2.6.10 idna==3.10 +importlib_metadata==8.7.0 iniconfig==2.0.0 ipython==8.12.3 isort==5.13.2 +jaraco.classes==3.4.0 +jaraco.context==6.0.1 +jaraco.functools==4.1.0 jedi==0.19.2 +jeepney==0.9.0 Jinja2==3.1.6 jsonschema==4.23.0 jsonschema-specifications==2024.10.1 jupyter_client==8.6.3 jupyter_core==5.8.1 jupyterlab_pygments==0.3.0 +keyring==25.6.0 +markdown-it-py==3.0.0 MarkupSafe==3.0.2 matplotlib-inline==0.1.7 +mccabe==0.7.0 +mdurl==0.1.2 mistune==3.1.3 +more-itertools==10.7.0 +mypy_extensions==1.1.0 nbclient==0.10.2 nbconvert==7.16.6 nbformat==5.10.4 +nh3==0.2.21 nodeenv==1.9.1 packaging==24.2 pandocfilters==1.5.1 parso==0.8.4 +pathspec==0.12.1 pexpect==4.9.0 pickleshare==0.7.5 pip-tools==7.4.1 @@ -53,9 +72,13 @@ pre_commit==4.2.0 prompt_toolkit==3.0.50 ptyprocess==0.7.0 pure_eval==0.2.3 -pydantic==2.10.6 +pycodestyle==2.12.1 +pycparser==2.22 +pydantic==2.11.3 pydantic-extra-types==2.10.3 -pydantic_core==2.27.2 +pydantic_core==2.33.1 +pydub==0.25.1 +pyflakes==3.2.0 Pygments==2.19.1 pyproject_hooks==1.2.0 pytest==8.3.2 @@ -63,20 +86,29 @@ pytest-cov==6.0.0 python-dateutil==2.9.0.post0 PyYAML==6.0.2 pyzmq==26.4.0 +readme_renderer==44.0 referencing==0.36.2 requests==2.32.3 +requests-toolbelt==1.0.0 +rfc3986==2.0.0 +rich==14.0.0 rpds-py==0.24.0 +SecretStorage==3.3.3 shortuuid==1.0.13 six==1.17.0 soupsieve==2.6 stack-data==0.6.3 +-e git+ssh://git@github.com/SunriseOpenOperatorPlatform/open-sdk.git@df5a0ec92f9f26892b38bb72d2486430055faf7c#egg=sunrise6g_opensdk tinycss2==1.4.0 tomli==2.2.1 tornado==6.5 traitlets==5.14.3 +twine==6.1.0 +typing-inspection==0.4.1 typing_extensions==4.12.2 urllib3==2.3.0 virtualenv==20.30.0 wcwidth==0.2.13 webencodings==0.5.1 yarg==0.1.9 +zipp==3.23.0 -- GitLab From 07939bcd06c5c7c2abb2037df35d8d4d33707c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pino?= Date: Thu, 19 Jun 2025 12:41:51 +0200 Subject: [PATCH 5/7] Update pyproject.toml; set version 0.9.9 and delete unused config --- pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 80cba7e..6c2b53c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "sunrise6g-opensdk" -version = "0.0.1" +version = "0.9.9" description = "Open source SDK to abstract CAMARA/GSMA Transformation Functions (TFs) for Edge Cloud platforms, 5G network cores and Open RAN solutions." keywords = [ "Federation", @@ -52,12 +52,12 @@ dependencies = [ Homepage = "https://sunrise6g.eu/" Repository = "https://github.com/OpenOperatorPlatform/OpenSDK" +[tool.setuptools] +package-dir = {"" = "src"} + [tool.setuptools.packages.find] where = ["src"] include = ["sunrise6g_opensdk*"] [tool.setuptools.package-data] sunrise6g_opensdk = ["py.typed"] - -[bdist_wheel] -universal = 1 -- GitLab From 26b1f468b4ff237782a03d8972c8107705c2c71a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pino?= Date: Thu, 19 Jun 2025 13:11:13 +0200 Subject: [PATCH 6/7] Delete pip requirement which is not needed --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index eab686f..6f737f9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -98,7 +98,6 @@ shortuuid==1.0.13 six==1.17.0 soupsieve==2.6 stack-data==0.6.3 --e git+ssh://git@github.com/SunriseOpenOperatorPlatform/open-sdk.git@df5a0ec92f9f26892b38bb72d2486430055faf7c#egg=sunrise6g_opensdk tinycss2==1.4.0 tomli==2.2.1 tornado==6.5 -- GitLab From ad2efde193b1bf48d693858d3109e73918d37162 Mon Sep 17 00:00:00 2001 From: giuliocarot0 Date: Thu, 19 Jun 2025 14:33:10 +0200 Subject: [PATCH 7/7] align traffic influence tests with new naming --- tests/network/test_create_traffic_influence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/network/test_create_traffic_influence.py b/tests/network/test_create_traffic_influence.py index 31620f3..c892b13 100644 --- a/tests/network/test_create_traffic_influence.py +++ b/tests/network/test_create_traffic_influence.py @@ -43,7 +43,7 @@ ti_session2 = { def instantiate_network_client(request): """Fixture to create and share a network client across tests""" adapter_specs = request.param - adapters = sdkclient.create_clients_from(adapter_specs) + adapters = sdkclient.create_adapters_from(adapter_specs) return adapters.get("network") -- GitLab