Loading edge_cloud_management_api/configs/env_config.py +1 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ class Configuration(BaseSettings): PI_EDGE_USERNAME: str = os.getenv("PI_EDGE_USERNAME") PI_EDGE_PASSWORD: str = os.getenv("PI_EDGE_PASSWORD") HTTP_PROXY: str = os.getenv("HTTP_PROXY") FEDERATION_MANAGER_HOST=os.getenv("FEDERATION_MANAGER_HOST") config = Configuration() edge_cloud_management_api/controllers/app_controllers.py +96 −43 Original line number Diff line number Diff line Loading @@ -124,26 +124,26 @@ def delete_app(appId, x_correlator=None): # noqa: E501 ) def create_app_instance(): logger.info("Received request to create app instance") #def create_app_instance(): # logger.info("Received request to create app instance") try: # try: # Step 1: Get request body body = request.get_json() logger.debug(f"Request body: {body}") # body = request.get_json() # logger.debug(f"Request body: {body}") # Step 2: Validate body format app_id = body.get('appId') app_zones = body.get('appZones') # 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 or appZones"}), 400 # if not app_id or not app_zones: # return jsonify({"error": "Missing required fields: appId or appZones"}), 400 # Step 3: Connect to Mongo and check if app exists # with MongoManager() as mongo_manager: # app_data = mongo_manager.find_document("apps", {"_id": app_id}) pi_edge_client_factory = PiEdgeAPIClientFactory() pi_edge_client = pi_edge_client_factory.create_pi_edge_api_client() # pi_edge_client_factory = PiEdgeAPIClientFactory() # pi_edge_client = pi_edge_client_factory.create_pi_edge_api_client() # app_data = pi_edge_client.get_app(app_id) # if len(app_data)<1: Loading @@ -155,42 +155,95 @@ def create_app_instance(): # Step 4: Deploy app instance using Pi-Edge client logger.info(f"Preparing to send deployment request to SRM for appId={app_id}") #logger.info(f"Preparing to send deployment request to SRM for appId={app_id}") deployment_payload = { "appId": app_id, "appZones": app_zones } # deployment_payload = { # "appId": app_id, # "appZones": app_zones #} #Print everything before sending # print("\n=== Preparing Deployment Request ===") # print(f"Endpoint: {pi_edge_client.base_url}/deployedServiceFunction") # print(f"Headers: {pi_edge_client._get_headers()}") # print(f"Payload: {deployment_payload}") # print("=== End of Deployment Request ===\n") #Try sending to Pi-Edge, catch connection errors separately # try: # response = pi_edge_client.deploy_service_function(data=deployment_payload) # 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)", # "details": response # }), 202 # Still accept the request but warn # 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.", # "details": str(inner_error) # }), 202 # Still accept it (because your backend worked) # 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 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") edge_zone_id = body.get("edgeCloudZoneId") k8s_ref = body.get("kubernetesClusterRef") if not app_id or not edge_zone_id or not k8s_ref: return jsonify({"error": "Missing required fields: appId, edgeCloudZoneId, or kubernetesCLusterRef"}), 400 logger.info(f"Preparing to send deployment request to SRM for appId={app_id}") pi_edge_client_factory = PiEdgeAPICLientFactory() pi_edge_client = pi_edge_client_factory.create_pi_edge_api_client() print("\n === Preparing Deployment Request ===") print(f" Endpoint: {pi_edge_client.base_url}/deployedServiceFunction") print(f" Headers: {pi_edge_client._get_headers()}") print(f"Payload: {deployment_payload}") print(f"Payload: {body}") print("=== End of Deployment Request ===\n") #Try sending to Pi-Edge, catch connection errors separately try: response = pi_edge_client.deploy_service_function(data=deployment_payload) 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)", "details": response }), 202 # Still accept the request but warn logger.info(f"Deployment response from SRM: {response}") }), 202 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.", "details": str(inner_error) }), 202 # Still accept it (because your backend worked) }),202 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 Loading edge_cloud_management_api/controllers/federation_manager_controller.py 0 → 100644 +53 −0 Original line number Diff line number Diff line from flask import request, jsonify from edge_cloud_management_api.services.federation_services import FederationManagerClientFactory factory = FederationManagerClientFactory() federation_client = factory.create_federation_client() def create_federation(): """ POST /partner Forwards the federation creation request to Federation Manager. """ try: body = request.get_json() result = federation_client.post_partner(body) return jsonify(result), 200 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400 def get_federation(federationContextId): """ GET /{federationContextId}/partner Forwards the GET federation info request. """ try: result = federation_client.get_partner(federationContextId) return jsonify(result), 200 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400 def delete_federation(federationContextId): """ DELETE /{federationContextId}/partner Forwards the DELETE federation request. """ try: result = federation_client.delete_partner(federationContextId) return jsonify(result), 200 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400 def get_federation_context_ids(): """ GET /fed-context-id Forwards the request to fetch federation context IDs. """ try: result = federation_client.get_federation_context_ids() return jsonify(result), 200 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400 edge_cloud_management_api/models/federation_manager_models.py 0 → 100644 +52 −0 Original line number Diff line number Diff line from pydantic import BaseModel, Field from typing import List, Optional class MobileNetworkIds(BaseModel): mncs: List[str] mcc: str class FixedNetworkIds(BaseModel): __root__: List[str] class CallbackCredentials(BaseModel): tokenUrl: str clientId: str clientSecret: str class ServiceEndpoint(BaseModel): ipv4Addresses: Optional[List[str]] = None ipv6Addresses: Optional[List[str]] = None port: Optional[int] = None fqdn: Optional[str] = None class ZoneDetails(BaseModel): geographyDetails: str zoneId: str geolocation: str class FederationRequestData(BaseModel): origOPFederationId: str origOPCountryCode: Optional[str] origOPMobileNetworkCodes: Optional[MobileNetworkIds] origOPFixedNetworkCodes: Optional[List[str]] initialDate: str partnerStatusLink: str partnerCallbackCredentials: Optional[CallbackCredentials] class FederationResponseData(BaseModel): federationContextId: str partnerOPFederationId: str partnerOPCountryCode: Optional[str] partnerOPMobileNetworkCodes: Optional[MobileNetworkIds] partnerOPFixedNetworkCodes: Optional[List[str]] offeredAvailabilityZones: Optional[List[ZoneDetails]] platformCaps: List[str] edgeDiscoveryServiceEndPoint: Optional[ServiceEndpoint] lcmServiceEndPoint: Optional[ServiceEndpoint] edge_cloud_management_api/services/federation_services.py 0 → 100644 +108 −0 Original line number Diff line number Diff line import requests from requests.exceptions import Timeout, ConnectionError from edge_cloud_management_api.configs.env_config import config from edge_cloud_management_api.managers.log_manager import logger class FederationManagerClient: def __init__(self, base_url=None): self.base_url = base_url or config.FEDERATION_MANAGER_HOST def _get_headers(self): return { "Content-Type": "application/json", "Accept": "application/json" } def post_partner(self, data: dict): url = f"{self.base_url}/partner" try: response = requests.post(url, json=data, headers=self._get_headers(), timeout=10) response.raise_for_status() return response.json() except Timeout: logger.error("POST /partner timed out") return {"error": "Request timed out"} except ConnectionError: logger.error("POST /partner connection error") return {"error": "Connection error"} except requests.exceptions.HTTPError as http_err: logger.error(f"POST /partner HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} except Exception as e: logger.error(f"POST /partner unexpected error: {e}") return {"error": str(e)} def get_partner(self, federation_context_id: str): url = f"{self.base_url}/{federation_context_id}/partner" try: response = requests.get(url, headers=self._get_headers(), timeout=10) response.raise_for_status() return response.json() except Timeout: logger.error("GET /{id}/partner timed out") return {"error": "Request timed out"} except ConnectionError: logger.error("GET /{id}/partner connection error") return {"error": "Connection error"} except requests.exceptions.HTTPError as http_err: logger.error(f"GET /{id}/partner HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} except Exception as e: logger.error(f"GET /{id}/partner unexpected error: {e}") return {"error": str(e)} def delete_partner(self, federation_context_id: str): url = f"{self.base_url}/{federation_context_id}/partner" try: response = requests.delete(url, headers=self._get_headers(), timeout=10) if response.content: return response.json() return {"status": response.status_code} except Timeout: logger.error("DELETE /{id}/partner timed out") return {"error": "Request timed out"} except ConnectionError: logger.error("DELETE /{id}/partner connection error") return {"error": "Connection error"} except requests.exceptions.HTTPError as http_err: logger.error(f"DELETE /{id}/partner HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} except Exception as e: logger.error(f"DELETE /{id}/partner unexpected error: {e}") return {"error": str(e)} def get_federation_context_ids(self): url = f"{self.base_url}/fed-context-id" try: response = requests.get(url, headers=self._get_headers(), timeout=10) response.raise_for_status() return response.json() except Timeout: logger.error("GET /fed-context-id timed out") return {"error": "Request timed out"} except ConnectionError: logger.error("GET /fed-context-id connection error") return {"error": "Connection error"} except requests.exceptions.HTTPError as http_err: logger.error(f"GET /fed-context-id HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} except Exception as e: logger.error(f"GET /fed-context-id unexpected error: {e}") return {"error": str(e)} class FederationManagerClientFactory: def __init__(self): self.default_base_url = config.FEDERATION_MANAGER_HOST def create_federation_client(self, base_url=None): base_url = base_url or self.default_base_url return FederationManagerClient(base_url=base_url) if __name__ == "__main__": factory = FederationManagerClientFactory() client = factory.create_federation_client() result = client.get_federation_context_ids() logger.info("Federation Context IDs: %s", result) Loading
edge_cloud_management_api/configs/env_config.py +1 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ class Configuration(BaseSettings): PI_EDGE_USERNAME: str = os.getenv("PI_EDGE_USERNAME") PI_EDGE_PASSWORD: str = os.getenv("PI_EDGE_PASSWORD") HTTP_PROXY: str = os.getenv("HTTP_PROXY") FEDERATION_MANAGER_HOST=os.getenv("FEDERATION_MANAGER_HOST") config = Configuration()
edge_cloud_management_api/controllers/app_controllers.py +96 −43 Original line number Diff line number Diff line Loading @@ -124,26 +124,26 @@ def delete_app(appId, x_correlator=None): # noqa: E501 ) def create_app_instance(): logger.info("Received request to create app instance") #def create_app_instance(): # logger.info("Received request to create app instance") try: # try: # Step 1: Get request body body = request.get_json() logger.debug(f"Request body: {body}") # body = request.get_json() # logger.debug(f"Request body: {body}") # Step 2: Validate body format app_id = body.get('appId') app_zones = body.get('appZones') # 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 or appZones"}), 400 # if not app_id or not app_zones: # return jsonify({"error": "Missing required fields: appId or appZones"}), 400 # Step 3: Connect to Mongo and check if app exists # with MongoManager() as mongo_manager: # app_data = mongo_manager.find_document("apps", {"_id": app_id}) pi_edge_client_factory = PiEdgeAPIClientFactory() pi_edge_client = pi_edge_client_factory.create_pi_edge_api_client() # pi_edge_client_factory = PiEdgeAPIClientFactory() # pi_edge_client = pi_edge_client_factory.create_pi_edge_api_client() # app_data = pi_edge_client.get_app(app_id) # if len(app_data)<1: Loading @@ -155,42 +155,95 @@ def create_app_instance(): # Step 4: Deploy app instance using Pi-Edge client logger.info(f"Preparing to send deployment request to SRM for appId={app_id}") #logger.info(f"Preparing to send deployment request to SRM for appId={app_id}") deployment_payload = { "appId": app_id, "appZones": app_zones } # deployment_payload = { # "appId": app_id, # "appZones": app_zones #} #Print everything before sending # print("\n=== Preparing Deployment Request ===") # print(f"Endpoint: {pi_edge_client.base_url}/deployedServiceFunction") # print(f"Headers: {pi_edge_client._get_headers()}") # print(f"Payload: {deployment_payload}") # print("=== End of Deployment Request ===\n") #Try sending to Pi-Edge, catch connection errors separately # try: # response = pi_edge_client.deploy_service_function(data=deployment_payload) # 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)", # "details": response # }), 202 # Still accept the request but warn # 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.", # "details": str(inner_error) # }), 202 # Still accept it (because your backend worked) # 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 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") edge_zone_id = body.get("edgeCloudZoneId") k8s_ref = body.get("kubernetesClusterRef") if not app_id or not edge_zone_id or not k8s_ref: return jsonify({"error": "Missing required fields: appId, edgeCloudZoneId, or kubernetesCLusterRef"}), 400 logger.info(f"Preparing to send deployment request to SRM for appId={app_id}") pi_edge_client_factory = PiEdgeAPICLientFactory() pi_edge_client = pi_edge_client_factory.create_pi_edge_api_client() print("\n === Preparing Deployment Request ===") print(f" Endpoint: {pi_edge_client.base_url}/deployedServiceFunction") print(f" Headers: {pi_edge_client._get_headers()}") print(f"Payload: {deployment_payload}") print(f"Payload: {body}") print("=== End of Deployment Request ===\n") #Try sending to Pi-Edge, catch connection errors separately try: response = pi_edge_client.deploy_service_function(data=deployment_payload) 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)", "details": response }), 202 # Still accept the request but warn logger.info(f"Deployment response from SRM: {response}") }), 202 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.", "details": str(inner_error) }), 202 # Still accept it (because your backend worked) }),202 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 Loading
edge_cloud_management_api/controllers/federation_manager_controller.py 0 → 100644 +53 −0 Original line number Diff line number Diff line from flask import request, jsonify from edge_cloud_management_api.services.federation_services import FederationManagerClientFactory factory = FederationManagerClientFactory() federation_client = factory.create_federation_client() def create_federation(): """ POST /partner Forwards the federation creation request to Federation Manager. """ try: body = request.get_json() result = federation_client.post_partner(body) return jsonify(result), 200 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400 def get_federation(federationContextId): """ GET /{federationContextId}/partner Forwards the GET federation info request. """ try: result = federation_client.get_partner(federationContextId) return jsonify(result), 200 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400 def delete_federation(federationContextId): """ DELETE /{federationContextId}/partner Forwards the DELETE federation request. """ try: result = federation_client.delete_partner(federationContextId) return jsonify(result), 200 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400 def get_federation_context_ids(): """ GET /fed-context-id Forwards the request to fetch federation context IDs. """ try: result = federation_client.get_federation_context_ids() return jsonify(result), 200 if "error" not in result else 502 except Exception as e: return jsonify({"error": str(e)}), 400
edge_cloud_management_api/models/federation_manager_models.py 0 → 100644 +52 −0 Original line number Diff line number Diff line from pydantic import BaseModel, Field from typing import List, Optional class MobileNetworkIds(BaseModel): mncs: List[str] mcc: str class FixedNetworkIds(BaseModel): __root__: List[str] class CallbackCredentials(BaseModel): tokenUrl: str clientId: str clientSecret: str class ServiceEndpoint(BaseModel): ipv4Addresses: Optional[List[str]] = None ipv6Addresses: Optional[List[str]] = None port: Optional[int] = None fqdn: Optional[str] = None class ZoneDetails(BaseModel): geographyDetails: str zoneId: str geolocation: str class FederationRequestData(BaseModel): origOPFederationId: str origOPCountryCode: Optional[str] origOPMobileNetworkCodes: Optional[MobileNetworkIds] origOPFixedNetworkCodes: Optional[List[str]] initialDate: str partnerStatusLink: str partnerCallbackCredentials: Optional[CallbackCredentials] class FederationResponseData(BaseModel): federationContextId: str partnerOPFederationId: str partnerOPCountryCode: Optional[str] partnerOPMobileNetworkCodes: Optional[MobileNetworkIds] partnerOPFixedNetworkCodes: Optional[List[str]] offeredAvailabilityZones: Optional[List[ZoneDetails]] platformCaps: List[str] edgeDiscoveryServiceEndPoint: Optional[ServiceEndpoint] lcmServiceEndPoint: Optional[ServiceEndpoint]
edge_cloud_management_api/services/federation_services.py 0 → 100644 +108 −0 Original line number Diff line number Diff line import requests from requests.exceptions import Timeout, ConnectionError from edge_cloud_management_api.configs.env_config import config from edge_cloud_management_api.managers.log_manager import logger class FederationManagerClient: def __init__(self, base_url=None): self.base_url = base_url or config.FEDERATION_MANAGER_HOST def _get_headers(self): return { "Content-Type": "application/json", "Accept": "application/json" } def post_partner(self, data: dict): url = f"{self.base_url}/partner" try: response = requests.post(url, json=data, headers=self._get_headers(), timeout=10) response.raise_for_status() return response.json() except Timeout: logger.error("POST /partner timed out") return {"error": "Request timed out"} except ConnectionError: logger.error("POST /partner connection error") return {"error": "Connection error"} except requests.exceptions.HTTPError as http_err: logger.error(f"POST /partner HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} except Exception as e: logger.error(f"POST /partner unexpected error: {e}") return {"error": str(e)} def get_partner(self, federation_context_id: str): url = f"{self.base_url}/{federation_context_id}/partner" try: response = requests.get(url, headers=self._get_headers(), timeout=10) response.raise_for_status() return response.json() except Timeout: logger.error("GET /{id}/partner timed out") return {"error": "Request timed out"} except ConnectionError: logger.error("GET /{id}/partner connection error") return {"error": "Connection error"} except requests.exceptions.HTTPError as http_err: logger.error(f"GET /{id}/partner HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} except Exception as e: logger.error(f"GET /{id}/partner unexpected error: {e}") return {"error": str(e)} def delete_partner(self, federation_context_id: str): url = f"{self.base_url}/{federation_context_id}/partner" try: response = requests.delete(url, headers=self._get_headers(), timeout=10) if response.content: return response.json() return {"status": response.status_code} except Timeout: logger.error("DELETE /{id}/partner timed out") return {"error": "Request timed out"} except ConnectionError: logger.error("DELETE /{id}/partner connection error") return {"error": "Connection error"} except requests.exceptions.HTTPError as http_err: logger.error(f"DELETE /{id}/partner HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} except Exception as e: logger.error(f"DELETE /{id}/partner unexpected error: {e}") return {"error": str(e)} def get_federation_context_ids(self): url = f"{self.base_url}/fed-context-id" try: response = requests.get(url, headers=self._get_headers(), timeout=10) response.raise_for_status() return response.json() except Timeout: logger.error("GET /fed-context-id timed out") return {"error": "Request timed out"} except ConnectionError: logger.error("GET /fed-context-id connection error") return {"error": "Connection error"} except requests.exceptions.HTTPError as http_err: logger.error(f"GET /fed-context-id HTTP error: {http_err}") return {"error": str(http_err), "status_code": response.status_code} except Exception as e: logger.error(f"GET /fed-context-id unexpected error: {e}") return {"error": str(e)} class FederationManagerClientFactory: def __init__(self): self.default_base_url = config.FEDERATION_MANAGER_HOST def create_federation_client(self, base_url=None): base_url = base_url or self.default_base_url return FederationManagerClient(base_url=base_url) if __name__ == "__main__": factory = FederationManagerClientFactory() client = factory.create_federation_client() result = client.get_federation_context_ids() logger.info("Federation Context IDs: %s", result)