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

Fix app instance creation logic

parent 1aa166a5
Loading
Loading
Loading
Loading
+193 −103
Original line number Diff line number Diff line
@@ -96,79 +96,173 @@ def create_app_instance():
       
        app_id = body.get("appId")
        app_zones = body.get("appZones")

        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
            return jsonify({"error": "Missing required fields: appId, appZones"}), 400
       
        zone = get_zone(app_zones[0].get('EdgeCloudZone').get('edgeCloudZoneId'))

        # ----------------------------------------------------------------------
        # PARTNER DEPLOYMENT (Federation path)
        # ----------------------------------------------------------------------
        if zone.get('isLocal') == 'false':
           # Step 1: retrieve app metadata

            # Step 1: retrieve app metadata from SRM
            appData = pi_edge_client.get_app(appId=app_id).get('appManifest')
           #Step 2: compose GSMA artefact payload

            # ------------------------------------------------------------------
            # Step 2: Build GSMA Artefact Payload (DIRTY PATCHED VERSION)
            # ------------------------------------------------------------------
            artefact = {}
            artefact['artefactId'] = app_id
           artefact['appProviderId'] = appData.get('appProvider')
           artefact['artefactName'] = appData.get('name')
           artefact['artefactVersionInfo'] = appData.get('version')
           artefact['artefactDescription'] = ''
           repoInfo = appData.get('appRepo')
           artefact['repoType'] = repoInfo.get('type')
           artefact['artefactRepoLocation'] = {'repoURL': repoInfo.get('imagePath'), 'userName': repoInfo.get('userName'), 'password': repoInfo.get('credentials'), 'token': ''}
            artefact['appProviderId'] = appData.get('appProvider') or "dummy-provider"

            artefact['artefactName'] = appData.get('name') or "unnamed-app"
            artefact['artefactVersionInfo'] = appData.get('version') or "1.0.0"
            artefact['artefactDescription'] = ""

            # Mandatory GSMA fields (missing in your original code)
            artefact['artefactDescriptorType'] = "HELM"
            artefact['artefactVirtType'] = "CONTAINER_TYPE"

            repoInfo = appData.get('appRepo') or {}

            artefact['repoType'] = repoInfo.get('type') or "PRIVATEREPO"

            # Dirty patch for repo credentials
            artefact['artefactRepoLocation'] = {
                'repoURL': repoInfo.get('imagePath') or "",
                'userName': repoInfo.get('userName') or "dummy-user",
                'password': repoInfo.get('credentials') or "dummy-password",
                'token': ""
            }

            # Extract interfaces
            exposedInterfaces = []
           networkInterfaces = appData.get('componentSpec')[0].get('networkInterfaces')
            componentSpec = appData.get('componentSpec') or [{}]
            networkInterfaces = componentSpec[0].get('networkInterfaces') or []
            
            interface_counter = 1 

            for ni in networkInterfaces:
               interface = {'interfaceId': '', 'commProtocol': ni.get('protocol'), 'commPort': ni.get('port'), 'visibilityType': ni.get('visibilityType'), 'network': '', 'InterfaceName': ''}
            
                interface_id = f"ifc_{ni.get('port', 0)}_{ni.get('protocol', 'TCP')}_{interface_counter}"
                interface_id = interface_id.replace("-", "_")
                interface_counter += 1
                
                network_name = f"net_{ni.get('port', 0)}_{ni.get('protocol', 'TCP')}"
                network_name = network_name.replace("-", "_")
                
                
                if len(network_name) < 8:
                    network_name = network_name + "_net"
                
                interface = {
                    'interfaceId': 'interface_id',
                    'commProtocol': ni.get('protocol') or 'TCP',
                    'commPort': ni.get('port') or 80,
                    'visibilityType': ni.get('visibilityType') or 'VISIBILITY_EXTERNAL',
                    'network': network_name,
                    'InterfaceName': network_name
                }
                exposedInterfaces.append(interface)

            artefact['componentSpec'] = [
                {
                   'componentName': appData.get('name'), 
                    'componentName': appData.get('name') or "component",
                    'numOfInstances': 0,
                    'images': [app_id],
                    'restartPolicy': 'RESTART_POLICY_ALWAYS',
                    'exposedInterfaces': exposedInterfaces,
                    'compEnvParams': [],
                   'persistentVolumes': []
                    'persistentVolumes': [],
                    'computeResourceProfile': {
                        "cpuArchType": "ISA_X86_64",
                        "numCPU": {
                 
                            "whole":{"value":1}

                },
                        "memory": 256,
                        "diskStorage":0,
                        "gpu": [],
                        "vpu": 0,
                        "fpga": 0,
                        "hugepages": [],
                        "cpuExclusivity": False
               }
              }
           ]
           # Step 3: Send artefact to local fed manager
            # ------------------------------------------------------------------
            # Step 3: Upload artefact to Federation Manager
            # ------------------------------------------------------------------
            fed_token = get_fed(zone.get('fedContextId')).get('token')
           create_artefact_response = federation_client.create_artefact(artefact=artefact, federation_context_id=zone.get('fedContextId'), token=fed_token)
           # Step 4: Onboard app
           if create_artefact_response.status_code == 200 or create_artefact_response.status_code ==409:
                # Step 5: Create GSM onboard app payload
                onboard_app = {}
                onboard_app['appId'] = app_id
                onboard_app['appProviderId'] = appData.get('appProvider')
                onboard_app['appDeploymentZones'] = []
                appMetaData = {}
                appMetaData['appName'] = appData.get('name')
                appMetaData['version'] = appData.get('version')
                onboard_app['appMetaData'] = appMetaData
                onboard_app['appComponentSpecs'] = [{'serviceNameNB': appData.get('name'),
                                                     'serviceNameEW': appData.get('name'),
                                                     'componentName': appData.get('name'),
                                                     'artefactId': app_id

            create_artefact_response = federation_client.create_artefact(
                artefact=artefact,
                federation_context_id=zone.get('fedContextId'),
                token=fed_token
            )

            # ------------------------------------------------------------------
            # Step 4: If artefact OK, start onboarding
            # ------------------------------------------------------------------
            if create_artefact_response.status_code in [200, 409]:

                onboard_app = {
                    "appId": app_id,
                    "appProviderId": appData.get("appProvider") or "dummy-provider",
                    "appDeploymentZones": [],
                    "appMetaData": {
                        "appName": appData.get('name') or "unnamed-app",
                        "version": appData.get('version') or "1.0.0"
                    },
                    "appComponentSpecs": [
                        {
                            "serviceNameNB": appData.get("name"),
                            "serviceNameEW": appData.get("name"),
                            "componentName": appData.get("name"),
                            "artefactId": app_id
                        }
                    ]
                # Step 6: Onboard app at partner
                onboard_app_response = federation_client.onboard_application(federation_context_id=zone.get('fedContextId'), body=onboard_app, token=fed_token)
                }

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

                # ------------------------------------------------------------------
                # Step 5: Deploy at partner OP
                # ------------------------------------------------------------------
                if onboard_app_response.status_code == 200:
                    # Step 7: Construct GSMA deployment payload
                    deploy_app = {}
                    deploy_app['appId'] = app_id
                    deploy_app['appVersion'] = appData.get('version')
                    deploy_app['appProviderId'] = appData.get('appProvider')
                    deploy_app['zoneInfo'] = {'zoneId': zone.get('edgeCloudZoneId')}
                    # Step 8: Deploy app at partner
                    deploy_app_response = federation_client.deploy_app_partner(federation_context_id=zone.get('fedContextId'), body=deploy_app, token = fed_token)

                    deploy_app = {
                        "appId": app_id,
                        "appVersion": appData.get("version") or "1.0.0",
                        "appProviderId": appData.get("appProvider") or "dummy-provider",
                        "zoneInfo": {"zoneId": zone.get('edgeCloudZoneId')}
                    }

                    deploy_app_response = federation_client.deploy_app_partner(
                        federation_context_id=zone.get('fedContextId'),
                        body=deploy_app,
                        token=fed_token
                    )

                    return deploy_app_response
                else:

                return onboard_app_response
           else:
               return create_artefact_response 

            return create_artefact_response

        # ----------------------------------------------------------------------
        # LOCAL DEPLOYMENT (via SRM)
        # ----------------------------------------------------------------------
        logger.info(f"Preparing to send deployment request to SRM for appId={app_id}")

        print("\n=== Preparing Deployment Request ===")
@@ -179,30 +273,26 @@ def create_app_instance():

        try:
            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}")
                return jsonify({
                  "warning": "Deployment not completed (SRM service unreachable)",
                    "warning": "Deployment not completed (SRM not reachable)",
                    "details": response
                  
                }), 202
            return response

          logger.info(f"Deployment response from SRM: {response}")
        except Exception as inner_error:
           logger.error(f"Exception while trying to deploy to SRM: {inner_error}")
            return jsonify({
               "warning": "SRM backend unavailable. Deployment request was built correctly.",
                "warning": "SRM backend unreachable",
                "details": str(inner_error)
            }), 202
       return response   
    #    return jsonify({"message": f"Application {app_id} instantiation accepted"}), 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"Unexpected error in create_app_instance: {str(e)}")
        return jsonify({"error": "An unexpected error occurred", "details": str(e)}), 500   
        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):
    """