Loading src/sunrise6g_opensdk/edgecloud/clients/aeros/client.py +203 −39 Changes for src/sunrise6g_opensdk/edgecloud/clients/aeros/client.py: 203 added lines, 39 removed lines. Original line number Diff line number Diff line Loading @@ -5,10 +5,14 @@ # - Vasilis Pitsilis (vpitsilis@dat.demokritos.gr, vpitsilis@iit.demokritos.gr) # - Andreas Sakellaropoulos (asakellaropoulos@iit.demokritos.gr) ## import uuid from typing import Any, Dict, List, Optional import yaml from sunrise6g_opensdk.edgecloud.clients.aeros import config from sunrise6g_opensdk.edgecloud.clients.aeros.continuum_client import ContinuumClient from sunrise6g_opensdk.edgecloud.clients.errors import EdgeCloudPlatformError from sunrise6g_opensdk.edgecloud.core.edgecloud_interface import ( EdgeCloudManagementInterface, ) Loading @@ -24,6 +28,8 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): def __init__(self, base_url: str, **kwargs): self.base_url = base_url self.logger = setup_logger(__name__, is_debug=True, file_name=config.LOG_FILE) self._app_store: Dict[str, Dict] = {} self._deployed_services: Dict[str, List[str]] = {} # Overwrite config values if provided via kwargs if "aerOS_API_URL" in kwargs: Loading @@ -42,39 +48,169 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): def onboard_app(self, app_manifest: Dict) -> Dict: # HLO-FE POST with TOSCA and app_id (service_id) service_id = app_manifest.get("serviceId") tosca_str = app_manifest.get("tosca") aeros_client = ContinuumClient(self.base_url) onboard_response = aeros_client.onboard_service( service_id=service_id, tosca_str=tosca_str # service_id = app_manifest.get("serviceId") # tosca_str = app_manifest.get("tosca") # aeros_client = ContinuumClient(self.base_url) # onboard_response = aeros_client.onboard_service( # service_id=service_id, tosca_str=tosca_str # ) app_id = app_manifest.get("appId") if not app_id: raise EdgeCloudPlatformError("Missing 'appId' in app manifest") if app_id in self._app_store: raise EdgeCloudPlatformError( f"Application with id '{app_id}' already exists" ) return {"appId": onboard_response["serviceId"]} self._app_store[app_id] = app_manifest self.logger.debug("Onboarded application with id: %s", app_id) return {"appId": app_id} def get_all_onboarded_apps(self) -> List[Dict]: aeros_client = ContinuumClient(self.base_url) ngsild_params = "type=Service&format=simplified" aeros_apps = aeros_client.query_entities(ngsild_params) return [ {"appId": service["id"], "name": service["name"]} for service in aeros_apps ] # return [{"appId": "1234-5678", "name": "TestApp"}] # aeros_client = ContinuumClient(self.base_url) # ngsild_params = "type=Service&format=simplified" # aeros_apps = aeros_client.query_entities(ngsild_params) # return [ # {"appId": service["id"], "name": service["name"]} for service in aeros_apps # ] return list(self._app_store.values()) def get_onboarded_app(self, app_id: str) -> Dict: aeros_client = ContinuumClient(self.base_url) ngsild_params = "format=simplified" aeros_app = aeros_client.query_entity(app_id, ngsild_params) return {"appId": aeros_app["id"], "name": aeros_app["name"]} # aeros_client = ContinuumClient(self.base_url) # ngsild_params = "format=simplified" # aeros_app = aeros_client.query_entity(app_id, ngsild_params) # return {"appId": aeros_app["id"], "name": aeros_app["name"]} if app_id not in self._app_store: raise EdgeCloudPlatformError( f"Application with id '{app_id}' does not exist" ) return self._app_store[app_id] def delete_onboarded_app(self, app_id: str) -> None: print(f"Deleting application: {app_id}") if app_id not in self._app_store: raise EdgeCloudPlatformError( f"Application with id '{app_id}' does not exist" ) del self._app_store[app_id] # TBD: Purge from continuum (make all ngsil-ld calls for servieId connected entities) # Should check if undeployed first def _generate_service_id(self, app_id: str) -> str: return f"ur n:ngsi-ld:Service:{app_id}-{uuid.uuid4().hex[:4]}" def _generate_tosca_yaml_dict( self, app_manifest: Dict, app_zones: List[Dict] ) -> Dict: component = app_manifest.get("componentSpec", [{}])[0] component_name = component.get("componentName", "application") image_path = app_manifest.get("appRepo", {}).get("imagePath", "") # Extract image_file image_file = image_path.split("/")[-1] # Extract repository_url if "/" in image_path: repository_url = "/".join(image_path.split("/")[:-1]) else: repository_url = "docker_hub" zone_id = ( app_zones[0].get("EdgeCloudZone", {}).get("edgeCloudZoneId", "default-zone") ) ports = {} for iface in component.get("networkInterfaces", []): interface_id = iface.get("interfaceId", "default") protocol = iface.get("protocol", "TCP").lower() port = iface.get("port", 8080) ports[interface_id] = { "properties": {"protocol": [protocol], "source": port} } expose_ports = any( iface.get("visibilityType") == "VISIBILITY_EXTERNAL" for iface in component.get("networkInterfaces", []) ) yaml_dict = { "tosca_definitions_version": "tosca_simple_yaml_1_3", "description": f"TOSCA for {app_manifest.get('name', 'application')}", "node_templates": { component_name: { "type": "tosca.nodes.Container.Application", "requirements": [ { "network": { "properties": { "ports": ports, "exposePorts": expose_ports, } } }, {"host": {"node_filter": {"properties": {"id": zone_id}}}}, ], "artifacts": { "application_image": { "file": image_file, "type": "tosca.artifacts.Deployment.Image.Container.Docker", "repository": repository_url, } }, "interfaces": { "Standard": { "create": { "implementation": "application_image", "inputs": {"cliArgs": [], "envVars": []}, } } }, } }, } return yaml_dict def deploy_app(self, app_id: str, app_zones: List[Dict]) -> Dict: # HLO-FE PUT with app_id (service_id) # aeros_client = ContinuumClient(self.base_url) # deploy_response = aeros_client.deploy_service(app_id) # return {"deploy_name": deploy_response["serviceId"]} # 1. Get app CAMARA manifest app_manifest = self._app_store.get(app_id) if not app_manifest: raise EdgeCloudPlatformError( f"Application with id '{app_id}' does not exist" ) # 2. Generate unique service ID service_id = self._generate_service_id(app_id) # Dev test # service_id = "service-my-id" # yaml_dict = { # "serviceId": service_id, # "tosca": app_manifest.get("tosca", "") # } # 5. Convert dict to YAML string yaml_dict = self._generate_tosca_yaml_dict(app_manifest, app_zones) tosca_yaml = yaml.dump(yaml_dict, sort_keys=False) print("Generated TOSCA YAML:") print(tosca_yaml) response = {"serviceId": service_id} # Mocked response # 6. Instantiate client and call onboard_service aeros_client = ContinuumClient(self.base_url) deploy_response = aeros_client.deploy_service(app_id) return {"appInstanceId": deploy_response["serviceId"]} response = aeros_client.onboard_service(service_id, tosca_yaml) if "serviceId" not in response: raise EdgeCloudPlatformError( "Invalid response from onboard_service: missing 'serviceId'" ) # 7. Track deployment if app_id not in self._deployed_services: self._deployed_services[app_id] = [] self._deployed_services[app_id].append(service_id) # 8. Return expected format return {"appInstanceId": response["serviceId"]} def get_all_deployed_apps( self, Loading @@ -82,22 +218,27 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): app_instance_id: Optional[str] = None, region: Optional[str] = None, ) -> List[Dict]: # FIXME: Get services in deployed state aeros_client = ContinuumClient(self.base_url) ngsild_params = 'type=Service&format=simplified&q=actionType=="DEPLOYED"' if app_id: ngsild_params += f'&q=service=="{app_id}"' aeros_apps = aeros_client.query_entities(ngsild_params) return [ { "appInstanceId": service["id"], "status": # scomponent["serviceComponentStatus"].split(":")[-1].lower() service["actionType"], } for service in aeros_apps ] # return [{"appInstanceId": "abcd-efgh", "status": "ready"}] # # FIXME: Get services in deployed state # aeros_client = ContinuumClient(self.base_url) # ngsild_params = 'type=Service&format=simplified&q=actionType=="DEPLOYED"' # if app_id: # ngsild_params += f'&q=service=="{app_id}"' # aeros_apps = aeros_client.query_entities(ngsild_params) # return [ # { # "appInstanceId": service["id"], # "status": # # scomponent["serviceComponentStatus"].split(":")[-1].lower() # service["actionType"], # } # for service in aeros_apps # ] # # return [{"appInstanceId": "abcd-efgh", "status": "ready"}] deployed = [] for stored_app_id, instance_ids in self._deployed_services.items(): for instance_id in instance_ids: deployed.append({"appId": stored_app_id, "appInstanceId": instance_id}) return deployed # def get_all_deployed_apps(self, # app_id: Optional[str] = None, Loading @@ -118,9 +259,31 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): # # return [{"appInstanceId": "abcd-efgh", "status": "ready"}] def undeploy_app(self, app_instance_id: str) -> None: # HLO-FE DELETE with app_id (service_id) # 1. Locate app_id corresponding to this instance found_app_id = None for app_id, instances in self._deployed_services.items(): if app_instance_id in instances: found_app_id = app_id break if not found_app_id: raise EdgeCloudPlatformError( f"No deployed app instance with ID '{app_instance_id}' found" ) # 2. Call the external undeploy_service aeros_client = ContinuumClient(self.base_url) _ = aeros_client.undeploy_service(app_instance_id) try: aeros_client.undeploy_service(app_instance_id) except Exception as e: raise EdgeCloudPlatformError( f"Failed to undeploy app instance '{app_instance_id}': {str(e)}" ) # 3. Clean up internal tracking self._deployed_services[found_app_id].remove(app_instance_id) if not self._deployed_services[found_app_id]: del self._deployed_services[found_app_id] def get_edge_cloud_zones( self, region: Optional[str] = None, status: Optional[str] = None Loading @@ -130,8 +293,9 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): aeros_domains = aeros_client.query_entities(ngsild_params) return [ { "edgeCloudZoneId": domain["id"], "zoneId": domain["id"], "status": domain["domainStatus"].split(":")[-1].lower(), "geographyDetails": "NOT_USED", } for domain in aeros_domains ] Loading src/sunrise6g_opensdk/edgecloud/clients/i2edge/utils.py +0 −1 Changes for src/sunrise6g_opensdk/edgecloud/clients/i2edge/utils.py: 0 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ from typing import Optional, Union from uuid import UUID from src.edgecloud import logger from sunrise6g_opensdk.edgecloud.api.routers.lcm.schemas import RequiredResources from sunrise6g_opensdk.edgecloud.core import utils as core_utils Loading tests/common/test_invoke_edgecloud_clients.py +4 −4 Changes for tests/common/test_invoke_edgecloud_clients.py: 4 added lines, 4 removed lines. Original line number Diff line number Diff line Loading @@ -13,11 +13,11 @@ EDGE_CLOUD_TEST_CASES = [ { "edgecloud": { "client_name": "aeros", "base_url": "http://test-aeros.url", "base_url": "https://ncsrd-mvp-domain.aeros-project.eu", # Additional parameters for aerOS client: "aerOS_API_URL": "http://fake.api.url", "aerOS_ACCESS_TOKEN": "fake-access", "aerOS_HLO_TOKEN": "fake-hlo", "aerOS_API_URL": "https://ncsrd-mvp-domain.aeros-project.eu", "aerOS_ACCESS_TOKEN": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJzaTcxSzNkUm11UFIxY2RhT2daNVFtbGpUVlR6U3JQM0cyYlZNdEVDeUVjIn0.eyJleHAiOjE4MTcwMzUwMTksImlhdCI6MTczMDcyMTQxOSwianRpIjoiODk2ODhlODktNTRmOS00MzFhLTliZTUtOTQ5MmMxYjE0NDZiIiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5jZi1tdnAtZG9tYWluLmFlcm9zLXByb2plY3QuZXUvYXV0aC9yZWFsbXMva2V5Y2xvYWNrLW9wZW5sZGFwIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImE5ZWY0ZTFiLTg5NTgtNGZkYS1hODQ5LTJlNjdlZmY3NjkzMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFlcm9zLXRlc3QiLCJzZXNzaW9uX3N0YXRlIjoiOGM2MTJjMDYtYTE5MS00MjBmLTlmNTItZGU5OWZiYzJkODI3IiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJDbG91ZEZlcnJvRG9tYWluIiwiZGVmYXVsdC1yb2xlcy1rZXljbG9hY2stb3BlbmxkYXAiLCJvZmZsaW5lX2FjY2VzcyIsIklvVCBzZXJ2aWNlIGRlcGxveWVyIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJzaWQiOiI4YzYxMmMwNi1hMTkxLTQyMGYtOWY1Mi1kZTk5ZmJjMmQ4MjciLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJJb1Qgc2VydmljZSBkZXBsb3llciAxIERlcGxveWVyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiaW90c2VydmljZWRlcGxveWVyMSIsImdpdmVuX25hbWUiOiJJb1Qgc2VydmljZSBkZXBsb3llciAxIiwiZmFtaWx5X25hbWUiOiJEZXBsb3llciJ9.XXM3HYVntCrSOsyJIKg-ATsqMigyQZhLMaeZtl9GqYPuISXfYl3AV0Hcs5w3n55J_-NOdlFnZdJgHlpEdB9LvxegagI4ZteoEZC72og9OdmzFV1ud4jPTrhGm7rbjCXs7bF-sGwGCKrLIs53PZPQiRcm1KxfN4RhBy3sL0Ff79QHkgvTbag-DQMrh5Y_NrTifrMrZ0i8JZD8AsRrHoi5zs7N2PXQ0zNv3n1dxxlWBKd46cWh3kutqNgTNV-s7YTde1FCSthKMcQLxe284qdFWAYlctzU5y4zLe-3VPxU7fH16jD7yAazTYdGVy4U0B5fPn_087ABjEf0oZmt40nuug", "aerOS_HLO_TOKEN": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJzaTcxSzNkUm11UFIxY2RhT2daNVFtbGpUVlR6U3JQM0cyYlZNdEVDeUVjIn0.eyJleHAiOjE4MTcwMzUwMTksImlhdCI6MTczMDcyMTQxOSwianRpIjoiODk2ODhlODktNTRmOS00MzFhLTliZTUtOTQ5MmMxYjE0NDZiIiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5jZi1tdnAtZG9tYWluLmFlcm9zLXByb2plY3QuZXUvYXV0aC9yZWFsbXMva2V5Y2xvYWNrLW9wZW5sZGFwIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImE5ZWY0ZTFiLTg5NTgtNGZkYS1hODQ5LTJlNjdlZmY3NjkzMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFlcm9zLXRlc3QiLCJzZXNzaW9uX3N0YXRlIjoiOGM2MTJjMDYtYTE5MS00MjBmLTlmNTItZGU5OWZiYzJkODI3IiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJDbG91ZEZlcnJvRG9tYWluIiwiZGVmYXVsdC1yb2xlcy1rZXljbG9hY2stb3BlbmxkYXAiLCJvZmZsaW5lX2FjY2VzcyIsIklvVCBzZXJ2aWNlIGRlcGxveWVyIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJzaWQiOiI4YzYxMmMwNi1hMTkxLTQyMGYtOWY1Mi1kZTk5ZmJjMmQ4MjciLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJJb1Qgc2VydmljZSBkZXBsb3llciAxIERlcGxveWVyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiaW90c2VydmljZWRlcGxveWVyMSIsImdpdmVuX25hbWUiOiJJb1Qgc2VydmljZSBkZXBsb3llciAxIiwiZmFtaWx5X25hbWUiOiJEZXBsb3llciJ9.XXM3HYVntCrSOsyJIKg-ATsqMigyQZhLMaeZtl9GqYPuISXfYl3AV0Hcs5w3n55J_-NOdlFnZdJgHlpEdB9LvxegagI4ZteoEZC72og9OdmzFV1ud4jPTrhGm7rbjCXs7bF-sGwGCKrLIs53PZPQiRcm1KxfN4RhBy3sL0Ff79QHkgvTbag-DQMrh5Y_NrTifrMrZ0i8JZD8AsRrHoi5zs7N2PXQ0zNv3n1dxxlWBKd46cWh3kutqNgTNV-s7YTde1FCSthKMcQLxe284qdFWAYlctzU5y4zLe-3VPxU7fH16jD7yAazTYdGVy4U0B5fPn_087ABjEf0oZmt40nuug", } }, # Uncomment once piedge import issues are fixed Loading tests/edgecloud/test_config.py +100 −7 Changes for tests/edgecloud/test_config.py: 100 added lines, 7 removed lines. Original line number Diff line number Diff line Loading @@ -20,10 +20,10 @@ the EdgeCloud Platform integration across different clients. # i2Edge variables ###################### # EdgeCloud Zone ZONE_ID = "Omega" ZONE_ID = "urn:ngsi-ld:Domain:NCSRD" # Artefact ARTEFACT_ID = "i2edgechart-id-2" ARTEFACT_ID = "aeros-id-1" ARTEFACT_NAME = "i2edgechart" REPO_NAME = "github-cesar" REPO_TYPE = "PUBLICREPO" Loading @@ -32,13 +32,13 @@ REPO_URL = "https://cesarcajas.github.io/helm-charts-examples/" # Onboarding: CAMARA /app payload (only mandatory fields) APP_ONBOARD_MANIFEST = { "appId": ARTEFACT_ID, "name": "i2edge-app-SDK", "name": "aeros-SDK", "version": "1.0.0", "appProvider": "i2CAT", "appProvider": "ncsrd", "packageType": "CONTAINER", "appRepo": { "type": "PUBLICREPO", "imagePath": "https://example.com/my-app-image:1.0.0", "imagePath": "https://example.com/nginx:latest", }, "requiredResources": { "infraKind": "kubernetes", Loading @@ -58,7 +58,7 @@ APP_ONBOARD_MANIFEST = { }, "componentSpec": [ { "componentName": "my-component", "componentName": "aeros-comp", "networkInterfaces": [ { "interfaceId": "eth0", Loading Loading @@ -94,4 +94,97 @@ APP_ZONES = [ ###################### # aerOS variables ###################### # TODO AEROS_APP_ID = "urn:ngsi-ld:Service:sunriseapp2" AEROS_TOSCA_DESCRIPTOR = { "serviceId": AEROS_APP_ID, "tosca": """ 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:NCSRD:cebf2bd4d0ba" artifacts: influxdb-image: file: p4lik4ri/influxdb type: tosca.artifacts.Deployment.Image.Container.Docker repository: docker_hub interfaces: Standard: create: implementation: influxdb-image inputs: envVars: - INFLUXDB_BUCKET: some-bucket - INFLUXDB_ORG: NCSRD - INFLUXDB_USER: vpitsilis - INFLUXDB_USER_PASSWORD: mypassword """, } AEROS_ZONE_ID = "urn:ngsi-ld:Domain:NCSRD" AEROS_TOSCA_DESCRIPTOR_2 = """ tosca_definitions_version: tosca_simple_yaml_1_3 description: A test service for testing TOSCA generation node_templates: auto-component: artifacts: nginx-image: file: nginx type: tosca.artifacts.Deployment.Image.Container.Docker repository: docker_hub interfaces: Standard: create: implementation: application_image inputs: cliArgs: [] envVars: [] requirements: - network: properties: ports: port1: properties: protocol: - tcp source: 80 port2: properties: protocol: - tcp source: 443 exposePorts: false - host: node_filter: capabilities: - host: properties: cpu_arch: equal: x64 realtime: equal: false cpu_usage: less_or_equal: '0.4' mem_size: greater_or_equal: '1' energy_efficiency: greater_or_equal: '10' green: greater_or_equal: '10' properties: null type: tosca.nodes.Container.Application """ tests/edgecloud/test_e2e.py +41 −46 Changes for tests/edgecloud/test_e2e.py: 41 added lines, 46 removed lines. Original line number Diff line number Diff line Loading @@ -30,20 +30,12 @@ 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 ( EdgeApplicationManager as I2EdgeClient, ) from tests.edgecloud.test_cases import test_cases from tests.edgecloud.test_config import ( from tests.edgecloud.test_config import ( # ARTEFACT_ID,; ARTEFACT_NAME,; REPO_NAME,; REPO_TYPE,; REPO_URL,; ZONE_ID, AEROS_ZONE_ID, APP_ID, APP_ONBOARD_MANIFEST, APP_ZONES, ARTEFACT_ID, ARTEFACT_NAME, REPO_NAME, REPO_TYPE, REPO_URL, ZONE_ID, ) Loading Loading @@ -72,7 +64,7 @@ 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): def test_get_edge_cloud_zones_details(edgecloud_client, zone_id=AEROS_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. Loading @@ -94,22 +86,22 @@ def test_get_edge_cloud_zones_details(edgecloud_client, zone_id=ZONE_ID): pytest.fail(f"Missing expected key in response: {e}") @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) def test_create_artefact(edgecloud_client): if isinstance(edgecloud_client, I2EdgeClient): try: edgecloud_client._create_artefact( artefact_id=ARTEFACT_ID, artefact_name=ARTEFACT_NAME, repo_name=REPO_NAME, repo_type=REPO_TYPE, repo_url=REPO_URL, password=None, token=None, user_name=None, ) except EdgeCloudPlatformError as e: pytest.fail(f"Artefact creation failed unexpectedly: {e}") # @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) # def test_create_artefact(edgecloud_client): # if isinstance(edgecloud_client, I2EdgeClient): # try: # edgecloud_client._create_artefact( # artefact_id=ARTEFACT_ID, # artefact_name=ARTEFACT_NAME, # repo_name=REPO_NAME, # repo_type=REPO_TYPE, # repo_url=REPO_URL, # password=None, # token=None, # user_name=None, # ) # except EdgeCloudPlatformError as e: # pytest.fail(f"Artefact creation failed unexpectedly: {e}") @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) Loading @@ -120,14 +112,18 @@ def test_onboard_app(edgecloud_client): pytest.fail(f"App onboarding failed unexpectedly: {e}") # @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) # def test_timer_wait_15_seconds(edgecloud_client): # time.sleep(15) @pytest.fixture(scope="module") def app_instance_id(edgecloud_client): try: output = edgecloud_client.deploy_app(APP_ID, APP_ZONES) deployed_app = {"appInstanceId": output["deploy_name"]} assert "appInstanceId" in deployed_app assert deployed_app["appInstanceId"] is not None yield deployed_app["appInstanceId"] assert "appInstanceId" in output assert output["appInstanceId"] is not None yield output["appInstanceId"] finally: pass Loading @@ -150,18 +146,17 @@ def test_undeploy_app(edgecloud_client, app_instance_id): pytest.fail(f"App undeployment failed unexpectedly: {e}") @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) def test_delete_onboarded_app(edgecloud_client): try: edgecloud_client.delete_onboarded_app(app_id=APP_ONBOARD_MANIFEST["appId"]) except EdgeCloudPlatformError as e: pytest.fail(f"App onboarding deletion failed unexpectedly: {e}") @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) def test_delete_artefact(edgecloud_client): if isinstance(edgecloud_client, I2EdgeClient): try: edgecloud_client._delete_artefact(artefact_id=ARTEFACT_ID) except EdgeCloudPlatformError as e: pytest.fail(f"Artefact deletion failed unexpectedly: {e}") # @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) # def test_delete_onboarded_app(edgecloud_client): # try: # edgecloud_client.delete_onboarded_app(app_id=APP_ONBOARD_MANIFEST["appId"]) # except EdgeCloudPlatformError as e: # pytest.fail(f"App onboarding deletion failed unexpectedly: {e}") # @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) # def test_delete_artefact(edgecloud_client): # if isinstance(edgecloud_client, I2EdgeClient): # try: # edgecloud_client._delete_artefact(artefact_id=ARTEFACT_ID) # except EdgeCloudPlatformError as e: # pytest.fail(f"Artefact deletion failed unexpectedly: {e}") Loading
src/sunrise6g_opensdk/edgecloud/clients/aeros/client.py +203 −39 Changes for src/sunrise6g_opensdk/edgecloud/clients/aeros/client.py: 203 added lines, 39 removed lines. Original line number Diff line number Diff line Loading @@ -5,10 +5,14 @@ # - Vasilis Pitsilis (vpitsilis@dat.demokritos.gr, vpitsilis@iit.demokritos.gr) # - Andreas Sakellaropoulos (asakellaropoulos@iit.demokritos.gr) ## import uuid from typing import Any, Dict, List, Optional import yaml from sunrise6g_opensdk.edgecloud.clients.aeros import config from sunrise6g_opensdk.edgecloud.clients.aeros.continuum_client import ContinuumClient from sunrise6g_opensdk.edgecloud.clients.errors import EdgeCloudPlatformError from sunrise6g_opensdk.edgecloud.core.edgecloud_interface import ( EdgeCloudManagementInterface, ) Loading @@ -24,6 +28,8 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): def __init__(self, base_url: str, **kwargs): self.base_url = base_url self.logger = setup_logger(__name__, is_debug=True, file_name=config.LOG_FILE) self._app_store: Dict[str, Dict] = {} self._deployed_services: Dict[str, List[str]] = {} # Overwrite config values if provided via kwargs if "aerOS_API_URL" in kwargs: Loading @@ -42,39 +48,169 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): def onboard_app(self, app_manifest: Dict) -> Dict: # HLO-FE POST with TOSCA and app_id (service_id) service_id = app_manifest.get("serviceId") tosca_str = app_manifest.get("tosca") aeros_client = ContinuumClient(self.base_url) onboard_response = aeros_client.onboard_service( service_id=service_id, tosca_str=tosca_str # service_id = app_manifest.get("serviceId") # tosca_str = app_manifest.get("tosca") # aeros_client = ContinuumClient(self.base_url) # onboard_response = aeros_client.onboard_service( # service_id=service_id, tosca_str=tosca_str # ) app_id = app_manifest.get("appId") if not app_id: raise EdgeCloudPlatformError("Missing 'appId' in app manifest") if app_id in self._app_store: raise EdgeCloudPlatformError( f"Application with id '{app_id}' already exists" ) return {"appId": onboard_response["serviceId"]} self._app_store[app_id] = app_manifest self.logger.debug("Onboarded application with id: %s", app_id) return {"appId": app_id} def get_all_onboarded_apps(self) -> List[Dict]: aeros_client = ContinuumClient(self.base_url) ngsild_params = "type=Service&format=simplified" aeros_apps = aeros_client.query_entities(ngsild_params) return [ {"appId": service["id"], "name": service["name"]} for service in aeros_apps ] # return [{"appId": "1234-5678", "name": "TestApp"}] # aeros_client = ContinuumClient(self.base_url) # ngsild_params = "type=Service&format=simplified" # aeros_apps = aeros_client.query_entities(ngsild_params) # return [ # {"appId": service["id"], "name": service["name"]} for service in aeros_apps # ] return list(self._app_store.values()) def get_onboarded_app(self, app_id: str) -> Dict: aeros_client = ContinuumClient(self.base_url) ngsild_params = "format=simplified" aeros_app = aeros_client.query_entity(app_id, ngsild_params) return {"appId": aeros_app["id"], "name": aeros_app["name"]} # aeros_client = ContinuumClient(self.base_url) # ngsild_params = "format=simplified" # aeros_app = aeros_client.query_entity(app_id, ngsild_params) # return {"appId": aeros_app["id"], "name": aeros_app["name"]} if app_id not in self._app_store: raise EdgeCloudPlatformError( f"Application with id '{app_id}' does not exist" ) return self._app_store[app_id] def delete_onboarded_app(self, app_id: str) -> None: print(f"Deleting application: {app_id}") if app_id not in self._app_store: raise EdgeCloudPlatformError( f"Application with id '{app_id}' does not exist" ) del self._app_store[app_id] # TBD: Purge from continuum (make all ngsil-ld calls for servieId connected entities) # Should check if undeployed first def _generate_service_id(self, app_id: str) -> str: return f"ur n:ngsi-ld:Service:{app_id}-{uuid.uuid4().hex[:4]}" def _generate_tosca_yaml_dict( self, app_manifest: Dict, app_zones: List[Dict] ) -> Dict: component = app_manifest.get("componentSpec", [{}])[0] component_name = component.get("componentName", "application") image_path = app_manifest.get("appRepo", {}).get("imagePath", "") # Extract image_file image_file = image_path.split("/")[-1] # Extract repository_url if "/" in image_path: repository_url = "/".join(image_path.split("/")[:-1]) else: repository_url = "docker_hub" zone_id = ( app_zones[0].get("EdgeCloudZone", {}).get("edgeCloudZoneId", "default-zone") ) ports = {} for iface in component.get("networkInterfaces", []): interface_id = iface.get("interfaceId", "default") protocol = iface.get("protocol", "TCP").lower() port = iface.get("port", 8080) ports[interface_id] = { "properties": {"protocol": [protocol], "source": port} } expose_ports = any( iface.get("visibilityType") == "VISIBILITY_EXTERNAL" for iface in component.get("networkInterfaces", []) ) yaml_dict = { "tosca_definitions_version": "tosca_simple_yaml_1_3", "description": f"TOSCA for {app_manifest.get('name', 'application')}", "node_templates": { component_name: { "type": "tosca.nodes.Container.Application", "requirements": [ { "network": { "properties": { "ports": ports, "exposePorts": expose_ports, } } }, {"host": {"node_filter": {"properties": {"id": zone_id}}}}, ], "artifacts": { "application_image": { "file": image_file, "type": "tosca.artifacts.Deployment.Image.Container.Docker", "repository": repository_url, } }, "interfaces": { "Standard": { "create": { "implementation": "application_image", "inputs": {"cliArgs": [], "envVars": []}, } } }, } }, } return yaml_dict def deploy_app(self, app_id: str, app_zones: List[Dict]) -> Dict: # HLO-FE PUT with app_id (service_id) # aeros_client = ContinuumClient(self.base_url) # deploy_response = aeros_client.deploy_service(app_id) # return {"deploy_name": deploy_response["serviceId"]} # 1. Get app CAMARA manifest app_manifest = self._app_store.get(app_id) if not app_manifest: raise EdgeCloudPlatformError( f"Application with id '{app_id}' does not exist" ) # 2. Generate unique service ID service_id = self._generate_service_id(app_id) # Dev test # service_id = "service-my-id" # yaml_dict = { # "serviceId": service_id, # "tosca": app_manifest.get("tosca", "") # } # 5. Convert dict to YAML string yaml_dict = self._generate_tosca_yaml_dict(app_manifest, app_zones) tosca_yaml = yaml.dump(yaml_dict, sort_keys=False) print("Generated TOSCA YAML:") print(tosca_yaml) response = {"serviceId": service_id} # Mocked response # 6. Instantiate client and call onboard_service aeros_client = ContinuumClient(self.base_url) deploy_response = aeros_client.deploy_service(app_id) return {"appInstanceId": deploy_response["serviceId"]} response = aeros_client.onboard_service(service_id, tosca_yaml) if "serviceId" not in response: raise EdgeCloudPlatformError( "Invalid response from onboard_service: missing 'serviceId'" ) # 7. Track deployment if app_id not in self._deployed_services: self._deployed_services[app_id] = [] self._deployed_services[app_id].append(service_id) # 8. Return expected format return {"appInstanceId": response["serviceId"]} def get_all_deployed_apps( self, Loading @@ -82,22 +218,27 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): app_instance_id: Optional[str] = None, region: Optional[str] = None, ) -> List[Dict]: # FIXME: Get services in deployed state aeros_client = ContinuumClient(self.base_url) ngsild_params = 'type=Service&format=simplified&q=actionType=="DEPLOYED"' if app_id: ngsild_params += f'&q=service=="{app_id}"' aeros_apps = aeros_client.query_entities(ngsild_params) return [ { "appInstanceId": service["id"], "status": # scomponent["serviceComponentStatus"].split(":")[-1].lower() service["actionType"], } for service in aeros_apps ] # return [{"appInstanceId": "abcd-efgh", "status": "ready"}] # # FIXME: Get services in deployed state # aeros_client = ContinuumClient(self.base_url) # ngsild_params = 'type=Service&format=simplified&q=actionType=="DEPLOYED"' # if app_id: # ngsild_params += f'&q=service=="{app_id}"' # aeros_apps = aeros_client.query_entities(ngsild_params) # return [ # { # "appInstanceId": service["id"], # "status": # # scomponent["serviceComponentStatus"].split(":")[-1].lower() # service["actionType"], # } # for service in aeros_apps # ] # # return [{"appInstanceId": "abcd-efgh", "status": "ready"}] deployed = [] for stored_app_id, instance_ids in self._deployed_services.items(): for instance_id in instance_ids: deployed.append({"appId": stored_app_id, "appInstanceId": instance_id}) return deployed # def get_all_deployed_apps(self, # app_id: Optional[str] = None, Loading @@ -118,9 +259,31 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): # # return [{"appInstanceId": "abcd-efgh", "status": "ready"}] def undeploy_app(self, app_instance_id: str) -> None: # HLO-FE DELETE with app_id (service_id) # 1. Locate app_id corresponding to this instance found_app_id = None for app_id, instances in self._deployed_services.items(): if app_instance_id in instances: found_app_id = app_id break if not found_app_id: raise EdgeCloudPlatformError( f"No deployed app instance with ID '{app_instance_id}' found" ) # 2. Call the external undeploy_service aeros_client = ContinuumClient(self.base_url) _ = aeros_client.undeploy_service(app_instance_id) try: aeros_client.undeploy_service(app_instance_id) except Exception as e: raise EdgeCloudPlatformError( f"Failed to undeploy app instance '{app_instance_id}': {str(e)}" ) # 3. Clean up internal tracking self._deployed_services[found_app_id].remove(app_instance_id) if not self._deployed_services[found_app_id]: del self._deployed_services[found_app_id] def get_edge_cloud_zones( self, region: Optional[str] = None, status: Optional[str] = None Loading @@ -130,8 +293,9 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): aeros_domains = aeros_client.query_entities(ngsild_params) return [ { "edgeCloudZoneId": domain["id"], "zoneId": domain["id"], "status": domain["domainStatus"].split(":")[-1].lower(), "geographyDetails": "NOT_USED", } for domain in aeros_domains ] Loading
src/sunrise6g_opensdk/edgecloud/clients/i2edge/utils.py +0 −1 Changes for src/sunrise6g_opensdk/edgecloud/clients/i2edge/utils.py: 0 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ from typing import Optional, Union from uuid import UUID from src.edgecloud import logger from sunrise6g_opensdk.edgecloud.api.routers.lcm.schemas import RequiredResources from sunrise6g_opensdk.edgecloud.core import utils as core_utils Loading
tests/common/test_invoke_edgecloud_clients.py +4 −4 Changes for tests/common/test_invoke_edgecloud_clients.py: 4 added lines, 4 removed lines. Original line number Diff line number Diff line Loading @@ -13,11 +13,11 @@ EDGE_CLOUD_TEST_CASES = [ { "edgecloud": { "client_name": "aeros", "base_url": "http://test-aeros.url", "base_url": "https://ncsrd-mvp-domain.aeros-project.eu", # Additional parameters for aerOS client: "aerOS_API_URL": "http://fake.api.url", "aerOS_ACCESS_TOKEN": "fake-access", "aerOS_HLO_TOKEN": "fake-hlo", "aerOS_API_URL": "https://ncsrd-mvp-domain.aeros-project.eu", "aerOS_ACCESS_TOKEN": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJzaTcxSzNkUm11UFIxY2RhT2daNVFtbGpUVlR6U3JQM0cyYlZNdEVDeUVjIn0.eyJleHAiOjE4MTcwMzUwMTksImlhdCI6MTczMDcyMTQxOSwianRpIjoiODk2ODhlODktNTRmOS00MzFhLTliZTUtOTQ5MmMxYjE0NDZiIiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5jZi1tdnAtZG9tYWluLmFlcm9zLXByb2plY3QuZXUvYXV0aC9yZWFsbXMva2V5Y2xvYWNrLW9wZW5sZGFwIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImE5ZWY0ZTFiLTg5NTgtNGZkYS1hODQ5LTJlNjdlZmY3NjkzMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFlcm9zLXRlc3QiLCJzZXNzaW9uX3N0YXRlIjoiOGM2MTJjMDYtYTE5MS00MjBmLTlmNTItZGU5OWZiYzJkODI3IiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJDbG91ZEZlcnJvRG9tYWluIiwiZGVmYXVsdC1yb2xlcy1rZXljbG9hY2stb3BlbmxkYXAiLCJvZmZsaW5lX2FjY2VzcyIsIklvVCBzZXJ2aWNlIGRlcGxveWVyIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJzaWQiOiI4YzYxMmMwNi1hMTkxLTQyMGYtOWY1Mi1kZTk5ZmJjMmQ4MjciLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJJb1Qgc2VydmljZSBkZXBsb3llciAxIERlcGxveWVyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiaW90c2VydmljZWRlcGxveWVyMSIsImdpdmVuX25hbWUiOiJJb1Qgc2VydmljZSBkZXBsb3llciAxIiwiZmFtaWx5X25hbWUiOiJEZXBsb3llciJ9.XXM3HYVntCrSOsyJIKg-ATsqMigyQZhLMaeZtl9GqYPuISXfYl3AV0Hcs5w3n55J_-NOdlFnZdJgHlpEdB9LvxegagI4ZteoEZC72og9OdmzFV1ud4jPTrhGm7rbjCXs7bF-sGwGCKrLIs53PZPQiRcm1KxfN4RhBy3sL0Ff79QHkgvTbag-DQMrh5Y_NrTifrMrZ0i8JZD8AsRrHoi5zs7N2PXQ0zNv3n1dxxlWBKd46cWh3kutqNgTNV-s7YTde1FCSthKMcQLxe284qdFWAYlctzU5y4zLe-3VPxU7fH16jD7yAazTYdGVy4U0B5fPn_087ABjEf0oZmt40nuug", "aerOS_HLO_TOKEN": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJzaTcxSzNkUm11UFIxY2RhT2daNVFtbGpUVlR6U3JQM0cyYlZNdEVDeUVjIn0.eyJleHAiOjE4MTcwMzUwMTksImlhdCI6MTczMDcyMTQxOSwianRpIjoiODk2ODhlODktNTRmOS00MzFhLTliZTUtOTQ5MmMxYjE0NDZiIiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5jZi1tdnAtZG9tYWluLmFlcm9zLXByb2plY3QuZXUvYXV0aC9yZWFsbXMva2V5Y2xvYWNrLW9wZW5sZGFwIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImE5ZWY0ZTFiLTg5NTgtNGZkYS1hODQ5LTJlNjdlZmY3NjkzMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFlcm9zLXRlc3QiLCJzZXNzaW9uX3N0YXRlIjoiOGM2MTJjMDYtYTE5MS00MjBmLTlmNTItZGU5OWZiYzJkODI3IiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJDbG91ZEZlcnJvRG9tYWluIiwiZGVmYXVsdC1yb2xlcy1rZXljbG9hY2stb3BlbmxkYXAiLCJvZmZsaW5lX2FjY2VzcyIsIklvVCBzZXJ2aWNlIGRlcGxveWVyIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJzaWQiOiI4YzYxMmMwNi1hMTkxLTQyMGYtOWY1Mi1kZTk5ZmJjMmQ4MjciLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJJb1Qgc2VydmljZSBkZXBsb3llciAxIERlcGxveWVyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiaW90c2VydmljZWRlcGxveWVyMSIsImdpdmVuX25hbWUiOiJJb1Qgc2VydmljZSBkZXBsb3llciAxIiwiZmFtaWx5X25hbWUiOiJEZXBsb3llciJ9.XXM3HYVntCrSOsyJIKg-ATsqMigyQZhLMaeZtl9GqYPuISXfYl3AV0Hcs5w3n55J_-NOdlFnZdJgHlpEdB9LvxegagI4ZteoEZC72og9OdmzFV1ud4jPTrhGm7rbjCXs7bF-sGwGCKrLIs53PZPQiRcm1KxfN4RhBy3sL0Ff79QHkgvTbag-DQMrh5Y_NrTifrMrZ0i8JZD8AsRrHoi5zs7N2PXQ0zNv3n1dxxlWBKd46cWh3kutqNgTNV-s7YTde1FCSthKMcQLxe284qdFWAYlctzU5y4zLe-3VPxU7fH16jD7yAazTYdGVy4U0B5fPn_087ABjEf0oZmt40nuug", } }, # Uncomment once piedge import issues are fixed Loading
tests/edgecloud/test_config.py +100 −7 Changes for tests/edgecloud/test_config.py: 100 added lines, 7 removed lines. Original line number Diff line number Diff line Loading @@ -20,10 +20,10 @@ the EdgeCloud Platform integration across different clients. # i2Edge variables ###################### # EdgeCloud Zone ZONE_ID = "Omega" ZONE_ID = "urn:ngsi-ld:Domain:NCSRD" # Artefact ARTEFACT_ID = "i2edgechart-id-2" ARTEFACT_ID = "aeros-id-1" ARTEFACT_NAME = "i2edgechart" REPO_NAME = "github-cesar" REPO_TYPE = "PUBLICREPO" Loading @@ -32,13 +32,13 @@ REPO_URL = "https://cesarcajas.github.io/helm-charts-examples/" # Onboarding: CAMARA /app payload (only mandatory fields) APP_ONBOARD_MANIFEST = { "appId": ARTEFACT_ID, "name": "i2edge-app-SDK", "name": "aeros-SDK", "version": "1.0.0", "appProvider": "i2CAT", "appProvider": "ncsrd", "packageType": "CONTAINER", "appRepo": { "type": "PUBLICREPO", "imagePath": "https://example.com/my-app-image:1.0.0", "imagePath": "https://example.com/nginx:latest", }, "requiredResources": { "infraKind": "kubernetes", Loading @@ -58,7 +58,7 @@ APP_ONBOARD_MANIFEST = { }, "componentSpec": [ { "componentName": "my-component", "componentName": "aeros-comp", "networkInterfaces": [ { "interfaceId": "eth0", Loading Loading @@ -94,4 +94,97 @@ APP_ZONES = [ ###################### # aerOS variables ###################### # TODO AEROS_APP_ID = "urn:ngsi-ld:Service:sunriseapp2" AEROS_TOSCA_DESCRIPTOR = { "serviceId": AEROS_APP_ID, "tosca": """ 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:NCSRD:cebf2bd4d0ba" artifacts: influxdb-image: file: p4lik4ri/influxdb type: tosca.artifacts.Deployment.Image.Container.Docker repository: docker_hub interfaces: Standard: create: implementation: influxdb-image inputs: envVars: - INFLUXDB_BUCKET: some-bucket - INFLUXDB_ORG: NCSRD - INFLUXDB_USER: vpitsilis - INFLUXDB_USER_PASSWORD: mypassword """, } AEROS_ZONE_ID = "urn:ngsi-ld:Domain:NCSRD" AEROS_TOSCA_DESCRIPTOR_2 = """ tosca_definitions_version: tosca_simple_yaml_1_3 description: A test service for testing TOSCA generation node_templates: auto-component: artifacts: nginx-image: file: nginx type: tosca.artifacts.Deployment.Image.Container.Docker repository: docker_hub interfaces: Standard: create: implementation: application_image inputs: cliArgs: [] envVars: [] requirements: - network: properties: ports: port1: properties: protocol: - tcp source: 80 port2: properties: protocol: - tcp source: 443 exposePorts: false - host: node_filter: capabilities: - host: properties: cpu_arch: equal: x64 realtime: equal: false cpu_usage: less_or_equal: '0.4' mem_size: greater_or_equal: '1' energy_efficiency: greater_or_equal: '10' green: greater_or_equal: '10' properties: null type: tosca.nodes.Container.Application """
tests/edgecloud/test_e2e.py +41 −46 Changes for tests/edgecloud/test_e2e.py: 41 added lines, 46 removed lines. Original line number Diff line number Diff line Loading @@ -30,20 +30,12 @@ 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 ( EdgeApplicationManager as I2EdgeClient, ) from tests.edgecloud.test_cases import test_cases from tests.edgecloud.test_config import ( from tests.edgecloud.test_config import ( # ARTEFACT_ID,; ARTEFACT_NAME,; REPO_NAME,; REPO_TYPE,; REPO_URL,; ZONE_ID, AEROS_ZONE_ID, APP_ID, APP_ONBOARD_MANIFEST, APP_ZONES, ARTEFACT_ID, ARTEFACT_NAME, REPO_NAME, REPO_TYPE, REPO_URL, ZONE_ID, ) Loading Loading @@ -72,7 +64,7 @@ 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): def test_get_edge_cloud_zones_details(edgecloud_client, zone_id=AEROS_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. Loading @@ -94,22 +86,22 @@ def test_get_edge_cloud_zones_details(edgecloud_client, zone_id=ZONE_ID): pytest.fail(f"Missing expected key in response: {e}") @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) def test_create_artefact(edgecloud_client): if isinstance(edgecloud_client, I2EdgeClient): try: edgecloud_client._create_artefact( artefact_id=ARTEFACT_ID, artefact_name=ARTEFACT_NAME, repo_name=REPO_NAME, repo_type=REPO_TYPE, repo_url=REPO_URL, password=None, token=None, user_name=None, ) except EdgeCloudPlatformError as e: pytest.fail(f"Artefact creation failed unexpectedly: {e}") # @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) # def test_create_artefact(edgecloud_client): # if isinstance(edgecloud_client, I2EdgeClient): # try: # edgecloud_client._create_artefact( # artefact_id=ARTEFACT_ID, # artefact_name=ARTEFACT_NAME, # repo_name=REPO_NAME, # repo_type=REPO_TYPE, # repo_url=REPO_URL, # password=None, # token=None, # user_name=None, # ) # except EdgeCloudPlatformError as e: # pytest.fail(f"Artefact creation failed unexpectedly: {e}") @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) Loading @@ -120,14 +112,18 @@ def test_onboard_app(edgecloud_client): pytest.fail(f"App onboarding failed unexpectedly: {e}") # @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) # def test_timer_wait_15_seconds(edgecloud_client): # time.sleep(15) @pytest.fixture(scope="module") def app_instance_id(edgecloud_client): try: output = edgecloud_client.deploy_app(APP_ID, APP_ZONES) deployed_app = {"appInstanceId": output["deploy_name"]} assert "appInstanceId" in deployed_app assert deployed_app["appInstanceId"] is not None yield deployed_app["appInstanceId"] assert "appInstanceId" in output assert output["appInstanceId"] is not None yield output["appInstanceId"] finally: pass Loading @@ -150,18 +146,17 @@ def test_undeploy_app(edgecloud_client, app_instance_id): pytest.fail(f"App undeployment failed unexpectedly: {e}") @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) def test_delete_onboarded_app(edgecloud_client): try: edgecloud_client.delete_onboarded_app(app_id=APP_ONBOARD_MANIFEST["appId"]) except EdgeCloudPlatformError as e: pytest.fail(f"App onboarding deletion failed unexpectedly: {e}") @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) def test_delete_artefact(edgecloud_client): if isinstance(edgecloud_client, I2EdgeClient): try: edgecloud_client._delete_artefact(artefact_id=ARTEFACT_ID) except EdgeCloudPlatformError as e: pytest.fail(f"Artefact deletion failed unexpectedly: {e}") # @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) # def test_delete_onboarded_app(edgecloud_client): # try: # edgecloud_client.delete_onboarded_app(app_id=APP_ONBOARD_MANIFEST["appId"]) # except EdgeCloudPlatformError as e: # pytest.fail(f"App onboarding deletion failed unexpectedly: {e}") # @pytest.mark.parametrize("edgecloud_client", test_cases, ids=id_func, indirect=True) # def test_delete_artefact(edgecloud_client): # if isinstance(edgecloud_client, I2EdgeClient): # try: # edgecloud_client._delete_artefact(artefact_id=ARTEFACT_ID) # except EdgeCloudPlatformError as e: # pytest.fail(f"Artefact deletion failed unexpectedly: {e}")