Commit 9cc6e698 authored by Sergio Gimenez's avatar Sergio Gimenez
Browse files

aggregate app instances across federations

parent 299bbeb1
Loading
Loading
Loading
Loading
+87 −15
Original line number Diff line number Diff line
@@ -5,7 +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 insert_zones
from edge_cloud_management_api.services.storage_service import get_fed
from edge_cloud_management_api.services.storage_service import get_fed, get_all_feds
import json
import re
import uuid
@@ -821,12 +821,84 @@ def get_app_instance(app_id=None, x_correlator=None, app_instance_id=None, regio
    Supports filtering by app_id, app_instance_id, and region.
    """
    try:
        instances = None
        instances = []
        pi_edge_client_factory = PiEdgeAPIClientFactory()
        pi_edge_client = pi_edge_client_factory.create_pi_edge_api_client()

        if app_id is None and app_instance_id is None:
            instances = pi_edge_client.get_app_instances()
        if app_instance_id is None:
            local_instances = pi_edge_client.get_app_instances()
            if isinstance(local_instances, list):
                instances.extend(local_instances)

            def resolve_app_provider(app_id_value, app_payload=None):
                if isinstance(app_payload, dict):
                    provider = app_payload.get("appProvider") or app_payload.get("appProviderId")
                    if provider:
                        return provider
                    manifest = app_payload.get("appManifest")
                    if isinstance(manifest, dict):
                        provider = manifest.get("appProvider") or manifest.get("appProviderId")
                        if provider:
                            return provider
                app_response = pi_edge_client.get_app(app_id_value)
                if isinstance(app_response, dict):
                    manifest = app_response.get("appManifest")
                    if isinstance(manifest, dict):
                        provider = manifest.get("appProvider") or manifest.get("appProviderId")
                        if provider:
                            return provider
                    provider = app_response.get("appProvider") or app_response.get("appProviderId")
                    if provider:
                        return provider
                return None

            feds = get_all_feds()
            if app_id:
                app_provider_id = resolve_app_provider(app_id)
                if app_provider_id:
                    for fed in feds:
                        fed_token = fed.get("token")
                        federation_context_id = fed.get("_id")
                        if not federation_context_id or not fed_token:
                            continue
                        fed_instances, fed_code = federation_client.get_all_app_instances(
                            federation_context_id=federation_context_id,
                            app_id=app_id,
                            app_provider_id=app_provider_id,
                            token=fed_token,
                        )
                        if fed_code == 200 and isinstance(fed_instances, list):
                            instances.extend(fed_instances)
                else:
                    logger.info("Skipping federated lookup; no appProviderId for appId=%s", app_id)
            else:
                apps = pi_edge_client.get_service_functions_catalogue()
                if isinstance(apps, list):
                    app_provider_map = {}
                    for app in apps:
                        if not isinstance(app, dict):
                            continue
                        app_id_value = app.get("appId") or app.get("id")
                        if not app_id_value:
                            continue
                        provider = resolve_app_provider(app_id_value, app_payload=app)
                        if provider:
                            app_provider_map[app_id_value] = provider

                    for app_id_value, app_provider_id in app_provider_map.items():
                        for fed in feds:
                            fed_token = fed.get("token")
                            federation_context_id = fed.get("_id")
                            if not federation_context_id or not fed_token:
                                continue
                            fed_instances, fed_code = federation_client.get_all_app_instances(
                                federation_context_id=federation_context_id,
                                app_id=app_id_value,
                                app_provider_id=app_provider_id,
                                token=fed_token,
                            )
                            if fed_code == 200 and isinstance(fed_instances, list):
                                instances.extend(fed_instances)

        if not instances:
            return jsonify({
+31 −0
Original line number Diff line number Diff line
@@ -239,6 +239,37 @@ class FederationManagerClient:
            logger.error(f"POST /application/lcm unexpected error: {e}")
            return {"error": str(e)}, 500

    def get_all_app_instances(self, federation_context_id: str, app_id: str, app_provider_id: str, token: str):
        url = (
            f"{self.base_url}/{federation_context_id}/application/lcm/app/{app_id}"
            f"/appProvider/{app_provider_id}"
        )
        try:
            response = requests.get(url, headers=self._get_headers(token), timeout=10)
            response.raise_for_status()
            return response.json(), response.status_code
        except Timeout:
            logger.error("GET /application/lcm/app/{appId}/appProvider/{appProviderId} timed out")
            return {"error": "Request timed out"}, 408
        except ConnectionError:
            logger.error("GET /application/lcm/app/{appId}/appProvider/{appProviderId} connection error")
            return {"error": "Connection error"}, 503
        except requests.exceptions.HTTPError as http_err:
            logger.error(f"GET /application/lcm/app/{app_id}/appProvider/{app_provider_id} HTTP error: {http_err}")
            try:
                body = http_err.response.json()
            except ValueError:
                body = http_err.response.text
            return {"error": body}, http_err.response.status_code
        except Exception as e:
            logger.error(
                "GET /application/lcm/app/%s/appProvider/%s unexpected error: %s",
                app_id,
                app_provider_id,
                e,
            )
            return {"error": str(e)}, 500

    '''---AVAILABILITY ZONE INFO SYNCHRONIZATION---'''

    def request_zone_sync(self, federation_context_id: str, body: dict, token: str):