Loading edge_cloud_management_api/controllers/app_controllers.py +339 −23 Original line number Diff line number Diff line Loading @@ -139,36 +139,27 @@ def create_app_instance(): artefact = { "artefactId": artefact_id, "artefactName": artefact_id, "appProviderId": appData.get("appProvider"), "artefactVersionInfo": "22.3.9", "artefactDescription": appData.get("description", ""), "artefactName": "library/nginx", "artefactVersionInfo": "latest", "artefactVirtType": "CONTAINER_TYPE", "artefactDescriptorType": "HELM", "artefactDescriptorTypeR": "HELM", "artefactFileName": f"{appData.get('name')}.tar", "artefactFileFormat": "TAR", "artefactDescriptorType": "COMPONENTSPEC", "repoType": "PUBLICREPO", "artefactRepoLocation": { "repoURL": "https://charts.bitnami.com/bitnami", "userName": "", "password": "", "token": "" "repoURL": "docker.io" }, "componentSpec": [ { "componentName": "nginx", "images": ["bitnami/nginx:1.29.4"], "images": ["nginx:latest"], "numOfInstances": 1, "restartPolicy": "RESTART_POLICY_ALWAYS", "computeResourceProfile": { "cpuArchType": "ISA_X86_64", "numCPU": "1", "memory": 1024, "diskStorage": 10240 "numCPU": "100m", "memory": 128 } } ] Loading @@ -182,11 +173,18 @@ def create_app_instance(): print(json.dumps(artefact, indent=2)) print("================================================\n") # ============================================================ # Step 3: Create artefact at Federation Manager # ============================================================ artefact_body, artefact_status = federation_client.create_artefact( artefact=artefact, federation_context_id=zone.get("fedContextId"), token=fed_token ) print(f"\n========== ARTEFACT CREATION RESPONSE ==========") print(f"Status: {artefact_status}") print(f"Response: {json.dumps(artefact_body, indent=2)}") print("================================================\n") # Idempotency: duplicate artefact = success if artefact_status == 422 and "duplicate key" in str(artefact_body): Loading @@ -199,6 +197,282 @@ def create_app_instance(): "fm_response": artefact_body }), artefact_status # ============================================================ # Step 4: Onboard application at partner OP (HARDCODED FOR TESTING) # ============================================================ fed_context_id = zone.get("fedContextId") logger.info(f"Federation Context ID from zone: {fed_context_id}") logger.info(f"Federation Manager URL: {federation_client.base_url}") print(f"\n========== FEDERATION CONTEXT DEBUG ==========") print(f"Using Federation Context ID: {fed_context_id}") print(f"Federation Manager Base URL: {federation_client.base_url}") print(f"Full Onboard URL: {federation_client.base_url}/{fed_context_id}/application/onboarding") print("===============================================\n") print("\n========== CHECKING FEDERATION IDS ==========") fed_ids_body, fed_ids_status = federation_client.get_federation_context_ids(token=fed_token) print(f"Status: {fed_ids_status}") print(f"Federation IDs: {json.dumps(fed_ids_body, indent=2)}") print(f"Looking for: {zone.get('fedContextId')}") print("=============================================\n") print(f"\n========== HEADERS DEBUG ==========") print(f"X-Partner-API-Root: {federation_client.partner_root}") print(f"Authorization: Bearer {fed_token[:20]}...") print("===================================\n") print ("DEBUG: About to check partner status...") try: print("\n========== CHECKING PARTNER STATUS ==========") partner_body, partner_status = federation_client.get_partner( federation_context_id=zone.get("fedContextId"), token=fed_token ) print(f"Partner Status: {partner_status}") print(f"Partner Info: {json.dumps(partner_body, indent=2)}") print("=============================================\n") except Exception as e: print(f"\n========== PARTNER CHECK ERROR ==========") print(f"Error getting partner status: {str(e)}") print("=========================================\n") #print("\n========== VERIFYING FEDERATION ==========") #fed_verify_body, fed_verify_status = federation_client.get_federation( # federation_context_id=zone.get("fedContextId"), # token=fed_token # ) # print(f"Federation Verification Status: {fed_verify_status}") # print(f"Federation Verification Response: {json.dumps(fed_verify_body, indent=2)}") # print("==========================================\n") #if fed_verify_status != 200: # return jsonify({ # "error": "Federation context not found or not accessible", # "federation_context_id": zone.get("fedContextId"), # "verification_response": fed_verify_body # }), fed_verify_status onboard_app = { "appId": "Zb8uaZ9vS5x", "appProviderId": "p7y0UqLRn0oMBWxLqxsZJEjfkA0JmHVW5", "appMetaData": { "appName": "ofPZpa02jYqebqPTgypFrH87jS3Kr", "version": "v1", "accessToken": "EpIhgCRuL83lyy7dOLQOcIOCSYHPOdSgwKk8l" }, "appQoSProfile": { "latencyConstraints": "NONE" }, "appComponentSpecs": [ { "artefactId": "dddd4444-eeee-5555-ffff-666666666666" } ], "appStatusCallbackLink": "" } print("\n========== OEG → FM ONBOARD PAYLOAD ==========") print(json.dumps(onboard_app, indent=2)) print("==============================================\n") onboard_app_body, onboard_app_status = federation_client.onboard_application( federation_context_id=zone.get("fedContextId"), body=onboard_app, token=fed_token ) print(f"\n========== ONBOARD RESPONSE DEBUG ==========") print(f"Status: {onboard_app_status}") print(f"Response Body: {json.dumps(onboard_app_body, indent=2)}") print("============================================\n") if onboard_app_status != 200: return jsonify({ "error": "Application onboarding failed", "fm_response": onboard_app_body }), onboard_app_status # ============================================================ # Step 5: Deploy application at partner OP (HARDCODED FOR TESTING) # ============================================================ deploy_app = { "appId": "Zb8uaZ9vS5x", "appProviderId": "p7y0UqLRn0oMBWxLqxsZJEjfkA0JmHVW5", "appVersion": "v1", "appInstCallbackLink": "", "zoneInfo": { "zoneId": zone.get("edgeCloudZoneId"), "flavourId": "string", "resPool": zone.get("resPool", "string"), "resourceConsumption": "RESERVED_RES_AVOID" } } print("\n========== OEG → FM DEPLOY PAYLOAD ==========") print(json.dumps(deploy_app, indent=2)) print("=============================================\n") deploy_app_body, deploy_app_status = federation_client.deploy_app_partner( federation_context_id=zone.get("fedContextId"), body=deploy_app, token=fed_token ) if deploy_app_status in (200, 201, 202): return jsonify({ "message": "Application deployed successfully at partner OP", "appId": app_id, "deployment_response": deploy_app_body }), deploy_app_status else: return jsonify({ "error": "Application deployment failed", "fm_response": deploy_app_body }), deploy_app_status # ============================================================ # 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( "SRM returned an error, deployment not completed" ) return jsonify({ "warning": "Deployment request accepted but not completed", "details": response }), 202 logger.info("Local deployment request successfully sent to SRM") return jsonify({ "message": "Application deployed locally", "appId": app_id, "response": response }), 202 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.exception("Unexpected error in create_app_instance") return jsonify({ "error": "Unexpected error", "details": str(e) }), 500 ''' 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() zone = get_zone( app_zones[0] .get("EdgeCloudZone", {}) .get("edgeCloudZoneId") ) # ============================================================ # PARTNER DEPLOYMENT (Federation path) # ============================================================ if zone.get("isLocal") == "false": # ============================================================ # Step 1: Retrieve application metadata from SRM # ============================================================ app_response = pi_edge_client.get_app(appId=app_id) appData = app_response.get("appManifest") if not appData: return jsonify({ "error": "Application manifest not found", "appId": app_id }), 404 # ============================================================ # Step 2: Compose GSMA artefact payload # artefactId == appId (INTENTIONAL) # ============================================================ artefact_id = app_id artefact = { "artefactId": artefact_id, "appProviderId": appData.get("appProvider"), "artefactName": "library/nginx", "artefactVersionInfo": "latest", "artefactVirtType": "CONTAINER_TYPE", "artefactDescriptorType": "COMPONENTSPEC", "repoType": "PUBLICREPO", "artefactRepoLocation": { "repoURL": "docker.io" }, "componentSpec": [ { "componentName": "nginx", "images": ["nginx:latest"], "numOfInstances": 1, "restartPolicy": "RESTART_POLICY_ALWAYS", "computeResourceProfile": { "cpuArchType": "ISA_X86_64", "numCPU": "100m", "memory": 128 } } ] } fed_token = get_fed( zone.get("fedContextId") ).get("token") print("\n========== OEG → FM ARTEFACT PAYLOAD ==========") print(json.dumps(artefact, indent=2)) print("================================================\n") # ============================================================ # Step 3: Create artefact at Federation Manager # ============================================================ artefact_body, artefact_status = federation_client.create_artefact( artefact=artefact, federation_context_id=zone.get("fedContextId"), token=fed_token ) # 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 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 Loading Loading @@ -245,17 +519,59 @@ def create_app_instance(): "appStatusCallbackLink": "http://oeg/api/status" } federation_client.onboard_application( print("\n========== OEG → FM ONBOARD PAYLOAD ==========") print(json.dumps(onboard_app, indent=2)) print("==============================================\n") onboard_app_body, onboard_app_status = federation_client.onboard_application( federation_context_id=zone.get("fedContextId"), body=onboard_app, token=fed_token ) # Step 5 intentionally skipped if onboard_app_status != 200: return jsonify({ "message": "Application onboarded successfully (partner OP)", "appId": app_id }), 202 "error": "Application onboarding failed", "fm_response": onboard_app_body }), onboard_app_status # ============================================================ # Step 5: Deploy application at partner OP # ============================================================ deploy_app = { "appId": app_id, "appVersion": appData.get("version") or "1.0.0", "appProviderId": appData.get("appProvider"), "appInstCallbackLink": "http://oeg/api/status", "zoneInfo": { "zoneId": zone.get("edgeCloudZoneId"), "flavourId": "string", "resPool": zone.get("resPool", "string"), "resourceConsumption": "RESERVED_RES_AVOID" } } print("\n========== OEG → FM DEPLOYMENT PAYLOAD ==========") print(json.dumps(deploy_app, indent=2)) print("==================================================\n") deploy_app_body, deploy_app_status = federation_client.deploy_app_partner( federation_context_id=zone.get("fedContextId"), body=deploy_app, token=fed_token ) if deploy_app_status in (200, 201, 202): return jsonify({ "message": "Application deployed successfully at partner OP", "appId": app_id, "deployment_response": deploy_app_body }), deploy_app_status else: return jsonify({ "error": "Application deployment failed", "fm_response": deploy_app_body }), deploy_app_status # ============================================================ # LOCAL DEPLOYMENT (SRM path) Loading Loading @@ -296,7 +612,7 @@ def create_app_instance(): "details": str(e) }), 500 ''' def get_app_instance(app_id=None, x_correlator=None, app_instance_id=None, region=None): """ Retrieve application instances from the database. Loading edge_cloud_management_api/services/federation_services.py +68 −16 Original line number Diff line number Diff line Loading @@ -87,6 +87,7 @@ class FederationManagerClient: logger.error(f"DELETE /{id}/partner unexpected error: {e}") return {"error": str(e)}, 500 def get_federation_context_ids(self, token: str): url = f"{self.base_url}/fed-context-id" try: Loading @@ -106,26 +107,62 @@ class FederationManagerClient: logger.error(f"GET /fed-context-id unexpected error: {e}") return {"error": str(e)}, 500 def get_federation(self, federation_context_id: str, token: str): """Verify that a federation context exists""" url = f"{self.base_url}/{federation_context_id}" try: response = requests.get( url, headers=self._get_headers(token), timeout=10 ) try: response_body = response.json() except ValueError: response_body = response.text return response_body, response.status_code except Timeout: logger.error(f"GET /{federation_context_id} timed out") return {"error": "Request timed out"}, 408 except ConnectionError: logger.error(f"GET /{federation_context_id} connection error") return {"error": "Connection error"}, 503 except requests.exceptions.HTTPError as http_err: logger.error(f"GET /{federation_context_id} HTTP error: {http_err}") return {"error": str(http_err)}, response.status_code except Exception as e: logger.error(f"GET /{federation_context_id} unexpected error: {e}") return {"error": str(e)}, 500 '''---PARTNER APP ONBOARDING---''' def onboard_application(self, federation_context_id: str, body: dict, token: str): url = f"{self.base_url}/{federation_context_id}/application/onboarding" try: response = requests.post(url, headers=self._get_headers(token), json=body, timeout=10) response.raise_for_status() return response.json() response = requests.post( url, headers=self._get_headers(token), json=body, timeout=10 ) try: response_body = response.json() except ValueError: response_body = response.text return response_body, response.status_code except Timeout: logger.error("POST /application/onboarding timed out") return {"error": "Request timed out"} return {"error": "Request timed out"}, 408 except ConnectionError: logger.error("POST /application/onboarding connection error") return {"error": "Connection error"} return {"error": "Connection error"}, 503 except requests.exceptions.HTTPError as http_err: logger.error(f"POST /application/onboarding HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} return {"error": str(http_err)}, response.status_code except Exception as e: logger.error(f"POST /application/onboarding unexpected error: {e}") return {"error": str(e)} return {"error": str(e)}, 500 def get_onboarded_app(self, federation_context_id: str, app_id: str, token: str): Loading Loading @@ -171,11 +208,29 @@ class FederationManagerClient: def deploy_app_partner(self, federation_context_id: str, body: dict, token: str): url = f"{self.base_url}/{federation_context_id}/application/lcm" try: response = requests.post(url, headers=self._get_headers(token), json=body, timeout=10) return response response = requests.post( url, headers=self._get_headers(token), json=body, timeout=10 ) try: response_body = response.json() except ValueError: response_body = response.text return response_body, response.status_code except Timeout: logger.error("POST /application/lcm timed out") return {"error": "Request timed out"}, 408 except ConnectionError: logger.error("POST /application/lcm connection error") return {"error": "Connection error"}, 503 except requests.exceptions.HTTPError as http_err: logger.error(f"POST /application/lcm HTTP error: {http_err}") return {"error": str(http_err)}, response.status_code except Exception as e: logger.error(f"DELETE onboarding app unexpected error: {e}") return {"error": str(e), "status_code": 500} logger.error(f"POST /application/lcm unexpected error: {e}") return {"error": str(e)}, 500 '''---AVAILABILITY ZONE INFO SYNCHRONIZATION---''' Loading Loading @@ -247,14 +302,11 @@ class FederationManagerClient: 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)}, 500 Loading Loading
edge_cloud_management_api/controllers/app_controllers.py +339 −23 Original line number Diff line number Diff line Loading @@ -139,36 +139,27 @@ def create_app_instance(): artefact = { "artefactId": artefact_id, "artefactName": artefact_id, "appProviderId": appData.get("appProvider"), "artefactVersionInfo": "22.3.9", "artefactDescription": appData.get("description", ""), "artefactName": "library/nginx", "artefactVersionInfo": "latest", "artefactVirtType": "CONTAINER_TYPE", "artefactDescriptorType": "HELM", "artefactDescriptorTypeR": "HELM", "artefactFileName": f"{appData.get('name')}.tar", "artefactFileFormat": "TAR", "artefactDescriptorType": "COMPONENTSPEC", "repoType": "PUBLICREPO", "artefactRepoLocation": { "repoURL": "https://charts.bitnami.com/bitnami", "userName": "", "password": "", "token": "" "repoURL": "docker.io" }, "componentSpec": [ { "componentName": "nginx", "images": ["bitnami/nginx:1.29.4"], "images": ["nginx:latest"], "numOfInstances": 1, "restartPolicy": "RESTART_POLICY_ALWAYS", "computeResourceProfile": { "cpuArchType": "ISA_X86_64", "numCPU": "1", "memory": 1024, "diskStorage": 10240 "numCPU": "100m", "memory": 128 } } ] Loading @@ -182,11 +173,18 @@ def create_app_instance(): print(json.dumps(artefact, indent=2)) print("================================================\n") # ============================================================ # Step 3: Create artefact at Federation Manager # ============================================================ artefact_body, artefact_status = federation_client.create_artefact( artefact=artefact, federation_context_id=zone.get("fedContextId"), token=fed_token ) print(f"\n========== ARTEFACT CREATION RESPONSE ==========") print(f"Status: {artefact_status}") print(f"Response: {json.dumps(artefact_body, indent=2)}") print("================================================\n") # Idempotency: duplicate artefact = success if artefact_status == 422 and "duplicate key" in str(artefact_body): Loading @@ -199,6 +197,282 @@ def create_app_instance(): "fm_response": artefact_body }), artefact_status # ============================================================ # Step 4: Onboard application at partner OP (HARDCODED FOR TESTING) # ============================================================ fed_context_id = zone.get("fedContextId") logger.info(f"Federation Context ID from zone: {fed_context_id}") logger.info(f"Federation Manager URL: {federation_client.base_url}") print(f"\n========== FEDERATION CONTEXT DEBUG ==========") print(f"Using Federation Context ID: {fed_context_id}") print(f"Federation Manager Base URL: {federation_client.base_url}") print(f"Full Onboard URL: {federation_client.base_url}/{fed_context_id}/application/onboarding") print("===============================================\n") print("\n========== CHECKING FEDERATION IDS ==========") fed_ids_body, fed_ids_status = federation_client.get_federation_context_ids(token=fed_token) print(f"Status: {fed_ids_status}") print(f"Federation IDs: {json.dumps(fed_ids_body, indent=2)}") print(f"Looking for: {zone.get('fedContextId')}") print("=============================================\n") print(f"\n========== HEADERS DEBUG ==========") print(f"X-Partner-API-Root: {federation_client.partner_root}") print(f"Authorization: Bearer {fed_token[:20]}...") print("===================================\n") print ("DEBUG: About to check partner status...") try: print("\n========== CHECKING PARTNER STATUS ==========") partner_body, partner_status = federation_client.get_partner( federation_context_id=zone.get("fedContextId"), token=fed_token ) print(f"Partner Status: {partner_status}") print(f"Partner Info: {json.dumps(partner_body, indent=2)}") print("=============================================\n") except Exception as e: print(f"\n========== PARTNER CHECK ERROR ==========") print(f"Error getting partner status: {str(e)}") print("=========================================\n") #print("\n========== VERIFYING FEDERATION ==========") #fed_verify_body, fed_verify_status = federation_client.get_federation( # federation_context_id=zone.get("fedContextId"), # token=fed_token # ) # print(f"Federation Verification Status: {fed_verify_status}") # print(f"Federation Verification Response: {json.dumps(fed_verify_body, indent=2)}") # print("==========================================\n") #if fed_verify_status != 200: # return jsonify({ # "error": "Federation context not found or not accessible", # "federation_context_id": zone.get("fedContextId"), # "verification_response": fed_verify_body # }), fed_verify_status onboard_app = { "appId": "Zb8uaZ9vS5x", "appProviderId": "p7y0UqLRn0oMBWxLqxsZJEjfkA0JmHVW5", "appMetaData": { "appName": "ofPZpa02jYqebqPTgypFrH87jS3Kr", "version": "v1", "accessToken": "EpIhgCRuL83lyy7dOLQOcIOCSYHPOdSgwKk8l" }, "appQoSProfile": { "latencyConstraints": "NONE" }, "appComponentSpecs": [ { "artefactId": "dddd4444-eeee-5555-ffff-666666666666" } ], "appStatusCallbackLink": "" } print("\n========== OEG → FM ONBOARD PAYLOAD ==========") print(json.dumps(onboard_app, indent=2)) print("==============================================\n") onboard_app_body, onboard_app_status = federation_client.onboard_application( federation_context_id=zone.get("fedContextId"), body=onboard_app, token=fed_token ) print(f"\n========== ONBOARD RESPONSE DEBUG ==========") print(f"Status: {onboard_app_status}") print(f"Response Body: {json.dumps(onboard_app_body, indent=2)}") print("============================================\n") if onboard_app_status != 200: return jsonify({ "error": "Application onboarding failed", "fm_response": onboard_app_body }), onboard_app_status # ============================================================ # Step 5: Deploy application at partner OP (HARDCODED FOR TESTING) # ============================================================ deploy_app = { "appId": "Zb8uaZ9vS5x", "appProviderId": "p7y0UqLRn0oMBWxLqxsZJEjfkA0JmHVW5", "appVersion": "v1", "appInstCallbackLink": "", "zoneInfo": { "zoneId": zone.get("edgeCloudZoneId"), "flavourId": "string", "resPool": zone.get("resPool", "string"), "resourceConsumption": "RESERVED_RES_AVOID" } } print("\n========== OEG → FM DEPLOY PAYLOAD ==========") print(json.dumps(deploy_app, indent=2)) print("=============================================\n") deploy_app_body, deploy_app_status = federation_client.deploy_app_partner( federation_context_id=zone.get("fedContextId"), body=deploy_app, token=fed_token ) if deploy_app_status in (200, 201, 202): return jsonify({ "message": "Application deployed successfully at partner OP", "appId": app_id, "deployment_response": deploy_app_body }), deploy_app_status else: return jsonify({ "error": "Application deployment failed", "fm_response": deploy_app_body }), deploy_app_status # ============================================================ # 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( "SRM returned an error, deployment not completed" ) return jsonify({ "warning": "Deployment request accepted but not completed", "details": response }), 202 logger.info("Local deployment request successfully sent to SRM") return jsonify({ "message": "Application deployed locally", "appId": app_id, "response": response }), 202 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.exception("Unexpected error in create_app_instance") return jsonify({ "error": "Unexpected error", "details": str(e) }), 500 ''' 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() zone = get_zone( app_zones[0] .get("EdgeCloudZone", {}) .get("edgeCloudZoneId") ) # ============================================================ # PARTNER DEPLOYMENT (Federation path) # ============================================================ if zone.get("isLocal") == "false": # ============================================================ # Step 1: Retrieve application metadata from SRM # ============================================================ app_response = pi_edge_client.get_app(appId=app_id) appData = app_response.get("appManifest") if not appData: return jsonify({ "error": "Application manifest not found", "appId": app_id }), 404 # ============================================================ # Step 2: Compose GSMA artefact payload # artefactId == appId (INTENTIONAL) # ============================================================ artefact_id = app_id artefact = { "artefactId": artefact_id, "appProviderId": appData.get("appProvider"), "artefactName": "library/nginx", "artefactVersionInfo": "latest", "artefactVirtType": "CONTAINER_TYPE", "artefactDescriptorType": "COMPONENTSPEC", "repoType": "PUBLICREPO", "artefactRepoLocation": { "repoURL": "docker.io" }, "componentSpec": [ { "componentName": "nginx", "images": ["nginx:latest"], "numOfInstances": 1, "restartPolicy": "RESTART_POLICY_ALWAYS", "computeResourceProfile": { "cpuArchType": "ISA_X86_64", "numCPU": "100m", "memory": 128 } } ] } fed_token = get_fed( zone.get("fedContextId") ).get("token") print("\n========== OEG → FM ARTEFACT PAYLOAD ==========") print(json.dumps(artefact, indent=2)) print("================================================\n") # ============================================================ # Step 3: Create artefact at Federation Manager # ============================================================ artefact_body, artefact_status = federation_client.create_artefact( artefact=artefact, federation_context_id=zone.get("fedContextId"), token=fed_token ) # 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 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 Loading Loading @@ -245,17 +519,59 @@ def create_app_instance(): "appStatusCallbackLink": "http://oeg/api/status" } federation_client.onboard_application( print("\n========== OEG → FM ONBOARD PAYLOAD ==========") print(json.dumps(onboard_app, indent=2)) print("==============================================\n") onboard_app_body, onboard_app_status = federation_client.onboard_application( federation_context_id=zone.get("fedContextId"), body=onboard_app, token=fed_token ) # Step 5 intentionally skipped if onboard_app_status != 200: return jsonify({ "message": "Application onboarded successfully (partner OP)", "appId": app_id }), 202 "error": "Application onboarding failed", "fm_response": onboard_app_body }), onboard_app_status # ============================================================ # Step 5: Deploy application at partner OP # ============================================================ deploy_app = { "appId": app_id, "appVersion": appData.get("version") or "1.0.0", "appProviderId": appData.get("appProvider"), "appInstCallbackLink": "http://oeg/api/status", "zoneInfo": { "zoneId": zone.get("edgeCloudZoneId"), "flavourId": "string", "resPool": zone.get("resPool", "string"), "resourceConsumption": "RESERVED_RES_AVOID" } } print("\n========== OEG → FM DEPLOYMENT PAYLOAD ==========") print(json.dumps(deploy_app, indent=2)) print("==================================================\n") deploy_app_body, deploy_app_status = federation_client.deploy_app_partner( federation_context_id=zone.get("fedContextId"), body=deploy_app, token=fed_token ) if deploy_app_status in (200, 201, 202): return jsonify({ "message": "Application deployed successfully at partner OP", "appId": app_id, "deployment_response": deploy_app_body }), deploy_app_status else: return jsonify({ "error": "Application deployment failed", "fm_response": deploy_app_body }), deploy_app_status # ============================================================ # LOCAL DEPLOYMENT (SRM path) Loading Loading @@ -296,7 +612,7 @@ def create_app_instance(): "details": str(e) }), 500 ''' def get_app_instance(app_id=None, x_correlator=None, app_instance_id=None, region=None): """ Retrieve application instances from the database. Loading
edge_cloud_management_api/services/federation_services.py +68 −16 Original line number Diff line number Diff line Loading @@ -87,6 +87,7 @@ class FederationManagerClient: logger.error(f"DELETE /{id}/partner unexpected error: {e}") return {"error": str(e)}, 500 def get_federation_context_ids(self, token: str): url = f"{self.base_url}/fed-context-id" try: Loading @@ -106,26 +107,62 @@ class FederationManagerClient: logger.error(f"GET /fed-context-id unexpected error: {e}") return {"error": str(e)}, 500 def get_federation(self, federation_context_id: str, token: str): """Verify that a federation context exists""" url = f"{self.base_url}/{federation_context_id}" try: response = requests.get( url, headers=self._get_headers(token), timeout=10 ) try: response_body = response.json() except ValueError: response_body = response.text return response_body, response.status_code except Timeout: logger.error(f"GET /{federation_context_id} timed out") return {"error": "Request timed out"}, 408 except ConnectionError: logger.error(f"GET /{federation_context_id} connection error") return {"error": "Connection error"}, 503 except requests.exceptions.HTTPError as http_err: logger.error(f"GET /{federation_context_id} HTTP error: {http_err}") return {"error": str(http_err)}, response.status_code except Exception as e: logger.error(f"GET /{federation_context_id} unexpected error: {e}") return {"error": str(e)}, 500 '''---PARTNER APP ONBOARDING---''' def onboard_application(self, federation_context_id: str, body: dict, token: str): url = f"{self.base_url}/{federation_context_id}/application/onboarding" try: response = requests.post(url, headers=self._get_headers(token), json=body, timeout=10) response.raise_for_status() return response.json() response = requests.post( url, headers=self._get_headers(token), json=body, timeout=10 ) try: response_body = response.json() except ValueError: response_body = response.text return response_body, response.status_code except Timeout: logger.error("POST /application/onboarding timed out") return {"error": "Request timed out"} return {"error": "Request timed out"}, 408 except ConnectionError: logger.error("POST /application/onboarding connection error") return {"error": "Connection error"} return {"error": "Connection error"}, 503 except requests.exceptions.HTTPError as http_err: logger.error(f"POST /application/onboarding HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} return {"error": str(http_err)}, response.status_code except Exception as e: logger.error(f"POST /application/onboarding unexpected error: {e}") return {"error": str(e)} return {"error": str(e)}, 500 def get_onboarded_app(self, federation_context_id: str, app_id: str, token: str): Loading Loading @@ -171,11 +208,29 @@ class FederationManagerClient: def deploy_app_partner(self, federation_context_id: str, body: dict, token: str): url = f"{self.base_url}/{federation_context_id}/application/lcm" try: response = requests.post(url, headers=self._get_headers(token), json=body, timeout=10) return response response = requests.post( url, headers=self._get_headers(token), json=body, timeout=10 ) try: response_body = response.json() except ValueError: response_body = response.text return response_body, response.status_code except Timeout: logger.error("POST /application/lcm timed out") return {"error": "Request timed out"}, 408 except ConnectionError: logger.error("POST /application/lcm connection error") return {"error": "Connection error"}, 503 except requests.exceptions.HTTPError as http_err: logger.error(f"POST /application/lcm HTTP error: {http_err}") return {"error": str(http_err)}, response.status_code except Exception as e: logger.error(f"DELETE onboarding app unexpected error: {e}") return {"error": str(e), "status_code": 500} logger.error(f"POST /application/lcm unexpected error: {e}") return {"error": str(e)}, 500 '''---AVAILABILITY ZONE INFO SYNCHRONIZATION---''' Loading Loading @@ -247,14 +302,11 @@ class FederationManagerClient: 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)}, 500 Loading