Loading edge_cloud_management_api/controllers/app_controllers.py +193 −103 Original line number Diff line number Diff line Loading @@ -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 ===") Loading @@ -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): """ Loading Loading
edge_cloud_management_api/controllers/app_controllers.py +193 −103 Original line number Diff line number Diff line Loading @@ -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 ===") Loading @@ -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): """ Loading