Commit d0603a20 authored by Sergio Gimenez's avatar Sergio Gimenez
Browse files

fix: align zone contracts and federated app cleanup

parent 481fc88e
Loading
Loading
Loading
Loading
+20 −21
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ from edge_cloud_management_api.controllers.app_partner_orchestration import reso
from edge_cloud_management_api.services.edge_cloud_services import SRMAPIClientFactory
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, get_all_feds
import json
import re
@@ -155,14 +154,7 @@ def delete_app(appId, x_correlator=None):
    try:
        srm_factory = SRMAPIClientFactory()
        api_client = srm_factory.create_srm_api_client()
        response = api_client.delete_app(appId=appId)
        if isinstance(response, dict) and int(response.get("status_code", 500)) >= 400:
            logger.info("SRM app delete failed, attempting federation cleanup")
        else:
            return response

        feds = get_all_feds()
        if feds:
        app_provider_id = None
        app_response = api_client.get_app(appId)
        if isinstance(app_response, dict):
@@ -171,6 +163,7 @@ def delete_app(appId, x_correlator=None):
            if isinstance(manifest, dict) and not app_provider_id:
                app_provider_id = manifest.get("appProvider") or manifest.get("appProviderId")

        if feds:
            cleanup_response = cleanup_federated_app(
                federation_client=federation_client,
                feds=feds,
@@ -180,8 +173,14 @@ def delete_app(appId, x_correlator=None):
                resolve_federated_app_identity=_resolve_federated_app_identity,
            )
            if cleanup_response is not None:
                cleanup_body, cleanup_status = cleanup_response
                if cleanup_status not in (200, 202, 204):
                    return cleanup_response

        response = api_client.delete_app(appId=appId)
        if isinstance(response, dict) and int(response.get("status_code", 500)) >= 400:
            return response

        return response

    except NotFound404Exception:
+20 −1
Original line number Diff line number Diff line
from edge_cloud_management_api.services.storage_service import get_zone
from edge_cloud_management_api.controllers.edge_cloud_controller import get_local_zones


def _find_local_zone(zone_id, zone_provider=None):
    for zone in get_local_zones():
        if not isinstance(zone, dict):
            continue
        if zone.get("edgeCloudZoneId") != zone_id:
            continue
        if zone_provider and zone.get("edgeCloudProvider") != zone_provider:
            continue
        return zone
    return None


def normalize_local_app_instance(instance):
@@ -54,7 +67,13 @@ def enrich_instance_zone_from_catalog(instance):
        return instance

    zone_provider = zone.get("edgeCloudProvider")
    stored_zone = get_zone(zone_id, zone_provider) if zone_provider and zone_provider != "unknown" else get_zone(zone_id)
    stored_zone = None
    if zone_provider and zone_provider != "unknown":
        stored_zone = get_zone(zone_id, zone_provider)
    else:
        stored_zone = _find_local_zone(zone_id)
        if not isinstance(stored_zone, dict):
            stored_zone = get_zone(zone_id)
    if not isinstance(stored_zone, dict):
        return instance

+17 −9
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ import json

from flask import jsonify

from edge_cloud_management_api.controllers.edge_cloud_controller import get_local_zones
from edge_cloud_management_api.managers.log_manager import logger
from edge_cloud_management_api.services.storage_service import get_fed
from edge_cloud_management_api.services.storage_service import get_zone
@@ -12,7 +13,7 @@ def resolve_target_zone(srm_client, edge_cloud_zone_id, edge_cloud_provider, zon
    zone = get_zone(edge_cloud_zone_id, edge_cloud_provider) if edge_cloud_zone_id else None
    if not zone and edge_cloud_zone_id:
        try:
            zones = srm_client.edge_cloud_zones()
            zones = get_local_zones()
            if isinstance(zones, list):
                for candidate_zone in zones:
                    if not isinstance(candidate_zone, dict):
@@ -22,18 +23,14 @@ def resolve_target_zone(srm_client, edge_cloud_zone_id, edge_cloud_provider, zon
                    if edge_cloud_provider and candidate_zone.get("edgeCloudProvider") != edge_cloud_provider:
                        continue
                    if candidate_zone.get("edgeCloudProvider") == edge_cloud_provider or not edge_cloud_provider:
                        candidate_zone["isLocal"] = "true"
                        insert_zones([candidate_zone])
                        zone = candidate_zone
                        break
        except Exception as exc:
            logger.info(f"Failed to refresh zones from SRM: {exc}")

    if not zone and edge_cloud_zone_id and isinstance(zone_payload, dict):
        zone_payload = dict(zone_payload)
        zone_payload.setdefault("isLocal", "true")
        insert_zones([zone_payload])
        zone = get_zone(edge_cloud_zone_id, edge_cloud_provider) or zone_payload
        zone = dict(zone_payload)
        zone.setdefault("isLocal", "true")

    return zone

@@ -42,6 +39,7 @@ def cleanup_federated_app(federation_client, feds, app_id, app_provider_id, norm
    if not feds:
        return None

    cleanup_performed = False
    for fed in feds:
        fed_token = fed.get("token")
        federation_context_id = fed.get("_id")
@@ -56,6 +54,7 @@ def cleanup_federated_app(federation_client, feds, app_id, app_provider_id, norm
                token=fed_token,
            )
            if fed_code == 200 and isinstance(fed_instances, list):
                cleanup_performed = True
                for zone_info in fed_instances:
                    if not isinstance(zone_info, dict):
                        continue
@@ -76,15 +75,24 @@ def cleanup_federated_app(federation_client, feds, app_id, app_provider_id, norm
                            zone_id=zone_id,
                            token=fed_token,
                        )
            elif fed_code not in (404, 422):
                return jsonify(fed_instances), fed_code

        remove_response, remove_status = federation_client.delete_onboarded_app(
        remove_response = federation_client.delete_onboarded_app(
            federation_context_id,
            normalize_federated_app_id(app_id),
            fed_token,
        )
        remove_status = int(remove_response.get("status_code", 500)) if isinstance(remove_response, dict) else 500
        if remove_status in (200, 202, 204):
            cleanup_performed = True
            continue
        if remove_status == 404:
            continue
        return jsonify(remove_response), remove_status

    if cleanup_performed:
        return "", 204
    return None


+16 −43
Original line number Diff line number Diff line
@@ -4,20 +4,10 @@ from typing import List
from edge_cloud_management_api.configs.env_config import config
from edge_cloud_management_api.managers.log_manager import logger
from edge_cloud_management_api.services.edge_cloud_services import SRMAPIClientFactory
from edge_cloud_management_api.services.storage_service import insert_zones, get_zones
from edge_cloud_management_api.services.storage_service import get_zones
from edge_cloud_management_api.services.federation_services import FederationManagerClientFactory


try:
    srm_factory = SRMAPIClientFactory()
    api_client = srm_factory.create_srm_api_client()
    zones = api_client.edge_cloud_zones()
    for zone in zones:
        zone['isLocal'] = 'true'
    insert_zones(zones)
except Exception as e:
    logger.error(e.args)

factory = FederationManagerClientFactory()
federation_client = factory.create_federation_client()

@@ -68,43 +58,22 @@ def get_federated_zones() -> List[EdgeCloudZone]:
    """get partner/federated Operator Platform available zones from Federation Manager"""
    return []

def get_cached_zones() -> list[dict]:
    """Retrieve cached zones and merge with local SRM zones."""
    cached = []
def get_partner_zones() -> list[dict]:
    """Retrieve persisted partner zones only."""
    try:
        cached = get_zones()
        zones = get_zones()
    except Exception as e:
        logger.warning("Failed to read cached zones: %s", e)

    merged = []
    existing_zone_keys = set()
    for zone in cached or []:
        if not isinstance(zone, dict):
            continue
        zone_key = (zone.get("edgeCloudProvider"), zone.get("edgeCloudZoneId"))
        if zone_key in existing_zone_keys:
            continue
        merged.append(zone)
        existing_zone_keys.add(zone_key)
    for zone in get_local_zones():
        zone_key = None
        if isinstance(zone, dict):
            zone_key = (zone.get("edgeCloudProvider"), zone.get("edgeCloudZoneId"))
        if zone_key and zone_key not in existing_zone_keys:
            merged.append(zone)
            existing_zone_keys.add(zone_key)
    return merged
        logger.warning("Failed to read partner zones: %s", e)
        return []
    return [
        zone for zone in (zones or [])
        if isinstance(zone, dict) and zone.get("isLocal") == "false"
    ]

def get_all_cloud_zones() -> List[EdgeCloudZone]:
    """Get all available zones from local and federated Operator Platforms"""

    # Convert dicts to EdgeCloudZone
    # local_zones = [EdgeCloudZone(**z) for z in get_local_zones()]

    # Federated zones are already EdgeCloudZone instances
    # federated_zones = get_federated_zones()
    # return local_zones + federated_zones
    return get_local_zones() + get_federated_zones()
    return get_local_zones() + get_partner_zones() + get_federated_zones()

def get_edge_cloud_zones(x_correlator: str | None = None, region=None, status=None):  # noqa: E501
    """Retrieve a list of the operators Edge Cloud Zones and their status
@@ -136,7 +105,11 @@ def get_edge_cloud_zones(x_correlator: str | None = None, region=None, status=No
        def query_status_matches(zone: EdgeCloudZone) -> bool:
            return query_params.status is None or zone.edgeCloudZoneStatus == query_params.status

        response = [EdgeCloudZone(**zone).model_dump() for zone in get_cached_zones()]
        response = [
            zone.model_dump()
            for zone in (EdgeCloudZone(**zone_dict) for zone_dict in get_all_cloud_zones())
            if query_region_matches(zone) and query_status_matches(zone)
        ]
        return jsonify(response), 200

    except ValidationError as e:
+11 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ from flask import request, jsonify
import logging
import connexion
from requests.exceptions import Timeout, ConnectionError
from pydantic import ValidationError
from edge_cloud_management_api.managers.log_manager import logger
import requests
from edge_cloud_management_api.configs.env_config import config
@@ -9,6 +10,8 @@ from edge_cloud_management_api.services.storage_service import insert_zones
from edge_cloud_management_api.services.storage_service import insert_federation, get_fed, get_all_feds

from edge_cloud_management_api.services.federation_services import FederationManagerClientFactory
from edge_cloud_management_api.models.federation_manager_models import FederationRequestData
from edge_cloud_management_api.models.federation_manager_models import ZoneRegistrationRequestData

token_headers = {'Authorization': 'Basic b3JpZ2luYXRpbmctb3AtMTpkZDd2TndGcWpOcFl3YWdobEV3TWJ3MTBnMGtsV0RIYg==', 
                 'Content-Type': 'application/x-www-form-urlencoded'
@@ -50,6 +53,10 @@ def create_federation():
    """POST /partner - Create federation with partner OP."""

    body = request.get_json()
    try:
        FederationRequestData(**body)
    except ValidationError as error:
        return jsonify({"error": "Invalid input", "details": error.errors()}), 400
    token = __get_token()
    if not token:
        return jsonify({"error": "Unable to obtain access token"}), 500
@@ -126,6 +133,10 @@ def request_zone_synch(federationContextId):
        body = {}
    if not body.get("availZoneNotifLink"):
        body["availZoneNotifLink"] = config.AVAIL_ZONE_NOTIF_LINK
    try:
        ZoneRegistrationRequestData(**body)
    except ValidationError as error:
        return jsonify({"error": "Invalid input", "details": error.errors()}), 400
    response, code = federation_client.request_zone_sync(
        federation_context_id=federationContextId, body=body, token=token
    )
Loading