Commit 72186148 authored by George Papathanail's avatar George Papathanail
Browse files

app controller and federation services changes

parent 6e372353
Loading
Loading
Loading
Loading
+187 −39
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ from edge_cloud_management_api.services.edge_cloud_services import PiEdgeAPIClie
from edge_cloud_management_api.services.federation_services import FederationManagerClientFactory
from edge_cloud_management_api.services.storage_service import get_zone
from edge_cloud_management_api.services.storage_service import get_fed
import json

factory = FederationManagerClientFactory()
federation_client = factory.create_federation_client()
@@ -91,62 +92,209 @@ def delete_app(appId, x_correlator=None):

def create_app_instance():
    logger.info("Received request to create app instance")

    try:
        body = request.get_json()
        logger.debug(f"Request body: {body}")

        app_id = body.get("appId")
        app_zones = body.get("appZones")

        if not app_id or not app_zones:
            return jsonify({
                "error": "Missing required fields: appId, appZones"
            }), 400

        pi_edge_client_factory = PiEdgeAPIClientFactory()
        pi_edge_client = pi_edge_client_factory.create_pi_edge_api_client()

        if not app_id or not app_zones:
            return jsonify({"error": "Missing required fields: appId, edgeCloudZoneId, or kubernetesCLusterRef"}), 400
        zone = get_zone(
            app_zones[0]
            .get("EdgeCloudZone", {})
            .get("edgeCloudZoneId")
        )

        logger.info(f"Attempting to get zone for: {app_zones[0].get('EdgeCloudZone').get('edgeCloudZoneId')}")
        zone = get_zone(app_zones[0].get('EdgeCloudZone').get('edgeCloudZoneId'))
        logger.info(f"Retrieved zone: {zone}")
        # ============================================================
        # PARTNER DEPLOYMENT (Federation path)
        # ============================================================
        if zone.get("isLocal") == "false":

        if zone is None:
            logger.error("get_zone returned None!")
            return jsonify({"error": "Zone not found"}), 404
            # ============================================================
            # Step 1: Retrieve application metadata from SRM
            # ============================================================
            app_response = pi_edge_client.get_app(appId=app_id)
            appData = app_response.get("appManifest")

        is_local = zone.get('isLocal')
        logger.info(f"Zone isLocal: {is_local}")
            if not appData:
                return jsonify({
                    "error": "Application manifest not found",
                    "appId": app_id
                }), 404

        if is_local == 'false':
            # Step 1: retrieve app metadata
            appData = pi_edge_client.get_app(appId=app_id).get('appManifest')
            # ... rest of federation logic ...
            return deploy_app_response
            # ============================================================
            # Step 2: Compose GSMA artefact payload
            # artefactId == appId (INTENTIONAL)
            # ============================================================
            artefact_id = app_id

            artefact = {
                "artefactId": artefact_id,
                "artefactName": artefact_id,
                "appProviderId": appData.get("appProvider"),
                "artefactVersionInfo": "22.3.9",
                "artefactDescription": appData.get("description", ""),

                "artefactVirtType": "CONTAINER_TYPE",
                "artefactDescriptorType": "HELM",
                "artefactDescriptorTypeR": "HELM",
                "artefactFileName": f"{appData.get('name')}.tar",
                "artefactFileFormat": "TAR",

                "repoType": "PUBLICREPO",
                "artefactRepoLocation": {
                    "repoURL": "https://charts.bitnami.com/bitnami",
                    "userName": "",
                    "password": "",
                    "token": ""
                },

                "componentSpec": [
                    {
                        "componentName": "nginx",
                        "images": ["bitnami/nginx:1.29.4"],
                        "numOfInstances": 1,
                        "restartPolicy": "RESTART_POLICY_ALWAYS",
                        "computeResourceProfile": {
                            "cpuArchType": "ISA_X86_64",
                            "numCPU": "1",
                            "memory": 1024,
                            "diskStorage": 10240
                        }
                    }
                ]
            }

            fed_token = get_fed(
                zone.get("fedContextId")
            ).get("token")

            print("\n========== OEG → FM ARTEFACT PAYLOAD ==========")
            print(json.dumps(artefact, indent=2))
            print("================================================\n")

            artefact_body, artefact_status = federation_client.create_artefact(
                artefact=artefact,
                federation_context_id=zone.get("fedContextId"),
                token=fed_token
            )

        logger.info(f"Preparing to send deployment request to SRM for appId={app_id}")
            # Idempotency: duplicate artefact = success
            if artefact_status == 422 and "duplicate key" in str(artefact_body):
                logger.info("Artefact already exists in FM, continuing")
                artefact_status = 200

        response = pi_edge_client.deploy_service_function(data=body)
        logger.info(f"Type of response from SRM: {type(response)}")
        logger.info(f"Response from SRM: {response}")
            if artefact_status not in (200, 409):
                return jsonify({
                    "error": "Artefact creation failed",
                    "fm_response": artefact_body
                }), artefact_status


            # ============================================================
            # Step 4: Onboard application at partner OP
            # ============================================================
            onboard_app = {
                "appId": app_id,
                "appProviderId": appData.get("appProvider"),

                "appDeploymentZones": [
                    {
                        "edgeCloudZoneId": zone.get("edgeCloudZoneId"),
                        "edgeCloudProvider": zone.get("edgeCloudProvider")
                    }
                ],

                "appMetaData": {
                    "appName": appData.get("name"),
                    "version": appData.get("version") or "1.0.0",
                    "appDescription": appData.get(
                        "description", "Federated application"
                    ),
                    "mobilitySupport": False,
                    "accessToken": "dummy-access-token",
                    "category": "IOT"
                },

                "appQoSProfile": {
                    "latencyConstraints": "NONE",
                    "bandwidthRequired": 1,
                    "multiUserClients": "APP_TYPE_SINGLE_USER",
                    "noOfUsersPerAppInst": 1,
                    "appProvisioning": True
                },

                "appComponentSpecs": [
                    {
                        "serviceNameNB": appData.get("name"),
                        "serviceNameEW": appData.get("name"),
                        "componentName": appData.get("name"),
                        "artefactId": artefact_id
                    }
                ],

                "appStatusCallbackLink": "http://oeg/api/status"
            }

            federation_client.onboard_application(
                federation_context_id=zone.get("fedContextId"),
                body=onboard_app,
                token=fed_token
            )

        if response is None:
            logger.error("SRM returned None!")
            return jsonify({"error": "SRM returned no response"}), 500
            # Step 5 intentionally skipped
            return jsonify({
                "message": "Application onboarded successfully (partner OP)",
                "appId": app_id
            }), 202

        # ============================================================
        # LOCAL DEPLOYMENT (SRM path)
        # ============================================================
        logger.info(f"Proceeding with LOCAL deployment for appId={app_id}")

        try:
            logger.debug("Sending deployment request to SRM")
            response = pi_edge_client.deploy_service_function(data=body)

            if isinstance(response, dict) and "error" in response:
            logger.warning(f"Failed to deploy service function: {response}")
                logger.warning(
                    "SRM returned an error, deployment not completed"
                )
                return jsonify({
                "warning": "Deployment not completed (SRM service unreachable)",
                    "warning": "Deployment request accepted but not completed",
                    "details": response
                }), 202

        logger.info(f"Deployment response from SRM: {response}")
        return response
            logger.info("Local deployment request successfully sent to SRM")
            return jsonify({
                "message": "Application deployed locally",
                "appId": app_id,
                "response": response
            }), 202

    except ValidationError as e:
        logger.error(f"Validation error: {str(e)}")
        return jsonify({"error": "Validation error", "details": str(e)}), 400
        except Exception as e:
            logger.error(f"SRM deployment failed: {str(e)}")
            return jsonify({
                "warning": "SRM backend unavailable",
                "details": str(e)
            }), 202

    except Exception as e:
        logger.error(f"Unexpected error in create_app_instance:{str(e)}")
        return jsonify({"error": "An unexpected error occurred", "details": str(e)}), 500
        logger.exception("Unexpected error in create_app_instance")
        return jsonify({
            "error": "Unexpected error",
            "details": str(e)
        }), 500
   

def get_app_instance(app_id=None, x_correlator=None, app_instance_id=None, region=None):
+16 −4
Original line number Diff line number Diff line
@@ -238,14 +238,26 @@ class FederationManagerClient:

    '''---ARTEFACT API---'''

    def create_artefact(self, artefact: dict, federation_context_id, token: str):
    def create_artefact(self, artefact: dict, federation_context_id: str, token: str):
        url = f"{self.base_url}/{federation_context_id}/artefact"
        try:
            response = requests.post(url, headers=self._get_headers(token), json=artefact, timeout=10)
            return response
            response = requests.post(
                url,
                headers=self._get_headers(token),
                json=artefact,
                timeout=120
            )

            try:
                body = response.json()
            except ValueError:
                body = response.text

            return body, response.status_code

        except Exception as e:
            logger.error(f"Create artefact unexpected error: {e}")
            return {"error": str(e), "status_code": 500}
            return {"error": str(e)}, 500

class FederationManagerClientFactory:
    def __init__(self):