Loading src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/client.py +61 −10 Original line number Diff line number Diff line # Mocked API for testing purposes import logging import json from typing import Dict, List, Optional from kubernetes.client import V1Deployment Loading @@ -9,6 +10,7 @@ from sunrise6g_opensdk.edgecloud.core import gsma_schemas from sunrise6g_opensdk.edgecloud.adapters.kubernetes.lib.core.piedge_encoder import ( deploy_service_function, ) from sunrise6g_opensdk.edgecloud.adapters.kubernetes.lib.models.ArtefactOnboarding import ArtefactOnboarding from sunrise6g_opensdk.edgecloud.adapters.kubernetes.lib.models.app_manifest import ( AppManifest, ) Loading Loading @@ -442,11 +444,12 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): zone = {} zone["zoneId"] = node.get("uid") zone["geographyDetails"] = node.get("location") zone["geolocation"] = node.get("geolocation") zone_list.append(zone) validated_data = gsma_schemas.ZonesList.model_validate(zone_list) return build_custom_http_response( status_code=200, content=[zone.model_dump_json() for zone in validated_data.root], content=[zone.model_dump() for zone in validated_data.root], headers={"Content-Type": 'application/json'}, encoding="utf-8", url=None, Loading Loading @@ -499,7 +502,7 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): validated_data = gsma_schemas.ZoneRegisteredData.model_validate(gsma_zone_details) return build_custom_http_response( status_code=200, content=validated_data, content=validated_data.model_dump(), headers={"Content-Type": "application/json"}, encoding="utf-8", url=None, Loading @@ -517,6 +520,28 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): :param request_body: Payload with artefact information. :return: """ repo_data = request_body["artefactRepoLocation"] artefact = ArtefactOnboarding( artefact_id=request_body["artefactId"], name=request_body["artefactName"], repo_name=repo_data.get("repoName", ""), repo_type=request_body.get("repoType"), repo_url=repo_data["repoURL"], repo_user_name=repo_data.get("userName"), repo_password=repo_data.get("password"), repo_token=repo_data.get("token"), ) self.connector_db.insert_document_artefact(artefact) return build_custom_http_response( status_code=200, content=None, headers={"Content-Type": "application/json"}, encoding="utf-8", url=None, request=None, ) pass def get_artefact_gsma(self, artefact_id: str) -> Dict: Loading Loading @@ -606,13 +631,17 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): repo_url = artefact.get("orig_am_artefact_repo_location_repo_url") image_name = artefact.get("orig_am_artefact_name") image_tag = artefact.get("orig_am_artefact_version_info") or "latest" component_spec = json.loads(artefact.get("orig_am_component_spec")) port = [] exposed_interface = component_spec[0].get("orig_ce_component_spec_exposed_interfaces")[0] port.append(exposed_interface.get("orig_ei_comm_port")) insert_doc = ServiceFunctionRegistrationRequest( service_function_id=app_id, service_function_image=repo_url + "/" + image_name + ":" + image_tag, service_function_name=app_name, service_function_type="package_type", application_ports= [], application_ports= port, required_resources= RequiredResources(), app_provider=app_provider_id, version=version, Loading Loading @@ -760,7 +789,7 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): "appInstIdentifier": deployment_uid, } validated = gsma_schemas.AppInstanceCreatedResponse.model_validate(response) validated = gsma_schemas.AppInstance.model_validate(response) return build_custom_http_response( status_code=202, Loading Loading @@ -899,6 +928,14 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): } return build_custom_http_response(500, error) def __map_k8s_arch_gsma(self, arch: str): mapping_set = { "amd64": "ISA_X86_64", "arm64": "ISA_ARM_64", "386": "ISA_X86" } return mapping_set[arch] def __get_zone_details_gsma(self, node_details): gsma_details = {} labels = node_details.get("metadata").get("labels") Loading @@ -906,24 +943,38 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): arch_type = labels.get("beta.kubernetes.io/arch") computeResourceQuotaLimits = [ { "cpuArchType": arch_type, "cpuArchType": self.__map_k8s_arch_gsma(arch_type), "numCPU": status.get("capacity").get("cpu"), "memory": status.get("capacity").get("memory"), "memory": status.get("capacity").get("memory")[:-2], # "memory": int(status.get("capacity").get("memory")) / (1024 * 1024), } ] reservedComputeResources = [ { "cpuArchType": arch_type, "cpuArchType": self.__map_k8s_arch_gsma(arch_type), "numCPU": status.get("allocatable").get("cpu"), "memory": status.get("allocatable").get("memory"), "memory": status.get("allocatable").get("memory")[:-2], # "memory": int(status.get("allocatable").get("memory")) / (1024 * 1024), } ] flavoursSupported = [] flavoursSupported = [ { "flavourId": "default", "cpuArchType": self.__map_k8s_arch_gsma(arch_type), "supportedOSTypes": [{ "architecture": "x86_64", "distribution": "UBUNTU", "version": "OS_VERSION_UBUNTU_2204_LTS", "license": "NOT_SPECIFIED" }], "numCPU": status.get("capacity").get("cpu"), "memorySize": status.get("capacity").get("memory")[:-2], "storageSize": 0, } ] gsma_details["computeResourceQuotaLimits"] = computeResourceQuotaLimits gsma_details["reservedComputeResources"] = reservedComputeResources gsma_details["flavoursSupported"] = flavoursSupported gsma_details["networkResources"] = {"egressBandWidth": 0, "dedicatedNIC": 0, "supportSriov": False,"supportDPDK": False} gsma_details["zoneServiceLevelObjsInfo"] = {"latencyRanges": {"minLatency": 0,"maxLatency": 0}, "jitterRanges": {"minJitter": 0,"maxJitter": 0}, "throughputRanges": {"minThroughput": 0, "maxThroughput": 0}} gsma_details["zoneServiceLevelObjsInfo"] = {"latencyRanges": {"minLatency": 1,"maxLatency": 1}, "jitterRanges": {"minJitter": 1,"maxJitter": 1}, "throughputRanges": {"minThroughput": 1, "maxThroughput": 1}} return gsma_details src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/lib/models/ArtefactOnboarding.py 0 → 100644 +20 −0 Original line number Diff line number Diff line from enum import Enum from pydantic import BaseModel, ConfigDict from typing import Optional class RepoType(str, Enum): UPLOAD = "UPLOAD" PUBLICREPO = "PUBLICREPO" PRIVATEREPO = "PRIVATEREPO" class ArtefactOnboarding(BaseModel): artefact_id: str name: str # chart: Optional[bytes] = Field(default=None) # XXX AFAIK not supported by CAMARA. repo_password: Optional[str] = None repo_name: Optional[str] = None repo_type: RepoType repo_url: Optional[str] = None repo_token: Optional[str] = None repo_user_name: Optional[str] = None model_config = ConfigDict(use_enum_values=True) No newline at end of file src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/lib/utils/connector_db.py +17 −0 Original line number Diff line number Diff line Loading @@ -251,6 +251,23 @@ class ConnectorDB: except Exception as ce_: raise Exception("An exception occurred :", ce_) def insert_document_artefact(self, document=None, _id=None): collection = "artefacts" myclient = pymongo.MongoClient(self._storage_url) mydbmongo = myclient[self.mydb_mongo] mycol = mydbmongo[collection] myquery = {"artefact_id": document.artefact_id} mydoc = mycol.find_one(myquery) # keeps the last record (contains registrationStatus) if mydoc is not None: return ("Already Registered: Artefact id", document.artefact_id) try: mycol.insert_one(document.model_dump()) except Exception as ce_: raise Exception("An exception occurred :", ce_) def get_documents_from_collection( self, collection_input, input_type=None, input_value=None ) -> List[dict]: Loading src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/lib/utils/kubernetes_connector.py +1 −0 Original line number Diff line number Diff line Loading @@ -192,6 +192,7 @@ class KubernetesConnector: pop_["name"] = node.metadata.name pop_["uid"] = node.metadata.uid pop_["location"] = node.metadata.labels.get("location") or "" pop_["geolocation"] = node.metadata.labels.get("geolocation") or "" pop_["serial"] = node.status.addresses[0].address pop_["node_type"] = node.metadata.labels.get("node_type") or "" pop_["status"] = ( Loading Loading
src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/client.py +61 −10 Original line number Diff line number Diff line # Mocked API for testing purposes import logging import json from typing import Dict, List, Optional from kubernetes.client import V1Deployment Loading @@ -9,6 +10,7 @@ from sunrise6g_opensdk.edgecloud.core import gsma_schemas from sunrise6g_opensdk.edgecloud.adapters.kubernetes.lib.core.piedge_encoder import ( deploy_service_function, ) from sunrise6g_opensdk.edgecloud.adapters.kubernetes.lib.models.ArtefactOnboarding import ArtefactOnboarding from sunrise6g_opensdk.edgecloud.adapters.kubernetes.lib.models.app_manifest import ( AppManifest, ) Loading Loading @@ -442,11 +444,12 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): zone = {} zone["zoneId"] = node.get("uid") zone["geographyDetails"] = node.get("location") zone["geolocation"] = node.get("geolocation") zone_list.append(zone) validated_data = gsma_schemas.ZonesList.model_validate(zone_list) return build_custom_http_response( status_code=200, content=[zone.model_dump_json() for zone in validated_data.root], content=[zone.model_dump() for zone in validated_data.root], headers={"Content-Type": 'application/json'}, encoding="utf-8", url=None, Loading Loading @@ -499,7 +502,7 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): validated_data = gsma_schemas.ZoneRegisteredData.model_validate(gsma_zone_details) return build_custom_http_response( status_code=200, content=validated_data, content=validated_data.model_dump(), headers={"Content-Type": "application/json"}, encoding="utf-8", url=None, Loading @@ -517,6 +520,28 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): :param request_body: Payload with artefact information. :return: """ repo_data = request_body["artefactRepoLocation"] artefact = ArtefactOnboarding( artefact_id=request_body["artefactId"], name=request_body["artefactName"], repo_name=repo_data.get("repoName", ""), repo_type=request_body.get("repoType"), repo_url=repo_data["repoURL"], repo_user_name=repo_data.get("userName"), repo_password=repo_data.get("password"), repo_token=repo_data.get("token"), ) self.connector_db.insert_document_artefact(artefact) return build_custom_http_response( status_code=200, content=None, headers={"Content-Type": "application/json"}, encoding="utf-8", url=None, request=None, ) pass def get_artefact_gsma(self, artefact_id: str) -> Dict: Loading Loading @@ -606,13 +631,17 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): repo_url = artefact.get("orig_am_artefact_repo_location_repo_url") image_name = artefact.get("orig_am_artefact_name") image_tag = artefact.get("orig_am_artefact_version_info") or "latest" component_spec = json.loads(artefact.get("orig_am_component_spec")) port = [] exposed_interface = component_spec[0].get("orig_ce_component_spec_exposed_interfaces")[0] port.append(exposed_interface.get("orig_ei_comm_port")) insert_doc = ServiceFunctionRegistrationRequest( service_function_id=app_id, service_function_image=repo_url + "/" + image_name + ":" + image_tag, service_function_name=app_name, service_function_type="package_type", application_ports= [], application_ports= port, required_resources= RequiredResources(), app_provider=app_provider_id, version=version, Loading Loading @@ -760,7 +789,7 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): "appInstIdentifier": deployment_uid, } validated = gsma_schemas.AppInstanceCreatedResponse.model_validate(response) validated = gsma_schemas.AppInstance.model_validate(response) return build_custom_http_response( status_code=202, Loading Loading @@ -899,6 +928,14 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): } return build_custom_http_response(500, error) def __map_k8s_arch_gsma(self, arch: str): mapping_set = { "amd64": "ISA_X86_64", "arm64": "ISA_ARM_64", "386": "ISA_X86" } return mapping_set[arch] def __get_zone_details_gsma(self, node_details): gsma_details = {} labels = node_details.get("metadata").get("labels") Loading @@ -906,24 +943,38 @@ class EdgeApplicationManager(EdgeCloudManagementInterface): arch_type = labels.get("beta.kubernetes.io/arch") computeResourceQuotaLimits = [ { "cpuArchType": arch_type, "cpuArchType": self.__map_k8s_arch_gsma(arch_type), "numCPU": status.get("capacity").get("cpu"), "memory": status.get("capacity").get("memory"), "memory": status.get("capacity").get("memory")[:-2], # "memory": int(status.get("capacity").get("memory")) / (1024 * 1024), } ] reservedComputeResources = [ { "cpuArchType": arch_type, "cpuArchType": self.__map_k8s_arch_gsma(arch_type), "numCPU": status.get("allocatable").get("cpu"), "memory": status.get("allocatable").get("memory"), "memory": status.get("allocatable").get("memory")[:-2], # "memory": int(status.get("allocatable").get("memory")) / (1024 * 1024), } ] flavoursSupported = [] flavoursSupported = [ { "flavourId": "default", "cpuArchType": self.__map_k8s_arch_gsma(arch_type), "supportedOSTypes": [{ "architecture": "x86_64", "distribution": "UBUNTU", "version": "OS_VERSION_UBUNTU_2204_LTS", "license": "NOT_SPECIFIED" }], "numCPU": status.get("capacity").get("cpu"), "memorySize": status.get("capacity").get("memory")[:-2], "storageSize": 0, } ] gsma_details["computeResourceQuotaLimits"] = computeResourceQuotaLimits gsma_details["reservedComputeResources"] = reservedComputeResources gsma_details["flavoursSupported"] = flavoursSupported gsma_details["networkResources"] = {"egressBandWidth": 0, "dedicatedNIC": 0, "supportSriov": False,"supportDPDK": False} gsma_details["zoneServiceLevelObjsInfo"] = {"latencyRanges": {"minLatency": 0,"maxLatency": 0}, "jitterRanges": {"minJitter": 0,"maxJitter": 0}, "throughputRanges": {"minThroughput": 0, "maxThroughput": 0}} gsma_details["zoneServiceLevelObjsInfo"] = {"latencyRanges": {"minLatency": 1,"maxLatency": 1}, "jitterRanges": {"minJitter": 1,"maxJitter": 1}, "throughputRanges": {"minThroughput": 1, "maxThroughput": 1}} return gsma_details
src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/lib/models/ArtefactOnboarding.py 0 → 100644 +20 −0 Original line number Diff line number Diff line from enum import Enum from pydantic import BaseModel, ConfigDict from typing import Optional class RepoType(str, Enum): UPLOAD = "UPLOAD" PUBLICREPO = "PUBLICREPO" PRIVATEREPO = "PRIVATEREPO" class ArtefactOnboarding(BaseModel): artefact_id: str name: str # chart: Optional[bytes] = Field(default=None) # XXX AFAIK not supported by CAMARA. repo_password: Optional[str] = None repo_name: Optional[str] = None repo_type: RepoType repo_url: Optional[str] = None repo_token: Optional[str] = None repo_user_name: Optional[str] = None model_config = ConfigDict(use_enum_values=True) No newline at end of file
src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/lib/utils/connector_db.py +17 −0 Original line number Diff line number Diff line Loading @@ -251,6 +251,23 @@ class ConnectorDB: except Exception as ce_: raise Exception("An exception occurred :", ce_) def insert_document_artefact(self, document=None, _id=None): collection = "artefacts" myclient = pymongo.MongoClient(self._storage_url) mydbmongo = myclient[self.mydb_mongo] mycol = mydbmongo[collection] myquery = {"artefact_id": document.artefact_id} mydoc = mycol.find_one(myquery) # keeps the last record (contains registrationStatus) if mydoc is not None: return ("Already Registered: Artefact id", document.artefact_id) try: mycol.insert_one(document.model_dump()) except Exception as ce_: raise Exception("An exception occurred :", ce_) def get_documents_from_collection( self, collection_input, input_type=None, input_value=None ) -> List[dict]: Loading
src/sunrise6g_opensdk/edgecloud/adapters/kubernetes/lib/utils/kubernetes_connector.py +1 −0 Original line number Diff line number Diff line Loading @@ -192,6 +192,7 @@ class KubernetesConnector: pop_["name"] = node.metadata.name pop_["uid"] = node.metadata.uid pop_["location"] = node.metadata.labels.get("location") or "" pop_["geolocation"] = node.metadata.labels.get("geolocation") or "" pop_["serial"] = node.status.addresses[0].address pop_["node_type"] = node.metadata.labels.get("node_type") or "" pop_["status"] = ( Loading