Commit 34b0dab5 authored by Sergio Gimenez's avatar Sergio Gimenez
Browse files

fix: preserve zone identity in app instance responses

parent e5ed80e5
Loading
Loading
Loading
Loading
+80 −4
Original line number Diff line number Diff line
@@ -169,6 +169,38 @@ def _normalize_local_app_instance(instance):
    return normalized


def _enrich_instance_zone_from_catalog(instance):
    if not isinstance(instance, dict):
        return instance

    zone = instance.get("edgeCloudZone")
    if not isinstance(zone, dict):
        return instance

    zone_id = zone.get("edgeCloudZoneId")
    if not zone_id:
        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)
    if not isinstance(stored_zone, dict):
        return instance

    enriched = dict(instance)
    enriched_zone = dict(zone)
    for key in (
        "edgeCloudZoneId",
        "edgeCloudZoneName",
        "edgeCloudProvider",
        "edgeCloudZoneStatus",
        "edgeCloudRegion",
    ):
        if enriched_zone.get(key) in (None, "unknown") and stored_zone.get(key) is not None:
            enriched_zone[key] = stored_zone.get(key)
    enriched["edgeCloudZone"] = enriched_zone
    return enriched


def _normalize_federated_app_instances(fed_instances, zone_provider=None, region=None):
    normalized_instances = []
    if not isinstance(fed_instances, list):
@@ -204,15 +236,58 @@ def _normalize_federated_app_instances(fed_instances, zone_provider=None, region

def _dedupe_app_instances(instances):
    deduped = []
    seen_instance_ids = set()
    by_instance_id = {}

    def _zone_quality(instance):
        zone = instance.get("edgeCloudZone")
        if not isinstance(zone, dict):
            return 0

        score = 0
        if zone.get("edgeCloudProvider") and zone.get("edgeCloudProvider") != "unknown":
            score += 4
        if zone.get("edgeCloudZoneName") and zone.get("edgeCloudZoneName") != "unknown":
            score += 2
        if zone.get("edgeCloudZoneStatus") and zone.get("edgeCloudZoneStatus") != "unknown":
            score += 1
        return score

    def _merge_instances(existing, incoming):
        merged = dict(existing)

        for key, value in incoming.items():
            if key == "edgeCloudZone" and isinstance(value, dict):
                existing_zone = merged.get("edgeCloudZone")
                if not isinstance(existing_zone, dict) or _zone_quality(incoming) > _zone_quality(existing):
                    merged["edgeCloudZone"] = dict(value)
                else:
                    zone = dict(existing_zone)
                    for zone_key, zone_value in value.items():
                        if zone_key not in zone or zone.get(zone_key) in (None, "unknown"):
                            zone[zone_key] = zone_value
                    merged["edgeCloudZone"] = zone
                continue

            if key not in merged or merged.get(key) in (None, "unknown", []):
                merged[key] = value

        return merged

    for instance in instances:
        if not isinstance(instance, dict):
            continue
        app_instance_id = instance.get("appInstanceId")
        if app_instance_id and app_instance_id in seen_instance_ids:
            continue
        if app_instance_id:
            seen_instance_ids.add(app_instance_id)
            existing = by_instance_id.get(app_instance_id)
            if existing is not None:
                merged = _merge_instances(existing, instance)
                by_instance_id[app_instance_id] = merged
                for index, deduped_instance in enumerate(deduped):
                    if deduped_instance.get("appInstanceId") == app_instance_id:
                        deduped[index] = merged
                        break
                continue
            by_instance_id[app_instance_id] = instance
        deduped.append(instance)
    return deduped

@@ -908,6 +983,7 @@ def get_app_instance(app_id=None, appId=None, x_correlator=None, xCorrelator=Non
            ]

        instances = _dedupe_app_instances(instances)
        instances = [_enrich_instance_zone_from_catalog(instance) for instance in instances]

        return jsonify(instances), 200

+80 −1
Original line number Diff line number Diff line
@@ -126,6 +126,22 @@ def test_get_app_instance_dedupes_local_and_federated_results(

    assert status_code == 200
    assert response.get_json() == [{
        "appId": "app-123",
        "appInstanceId": "inst-1",
        "status": "ready",
        "edgeCloudZone": {
            "edgeCloudZoneId": "default",
            "edgeCloudZoneName": "unknown",
            "edgeCloudProvider": "Remote Operator",
            "edgeCloudZoneStatus": "unknown",
            "edgeCloudRegion": "unknown",
        },
    }]


def test_dedupe_app_instances_prefers_richer_zone_identity():
    deduped = app_controllers._dedupe_app_instances([
        {
            "appId": "app-123",
            "appInstanceId": "inst-1",
            "status": "ready",
@@ -136,9 +152,72 @@ def test_get_app_instance_dedupes_local_and_federated_results(
                "edgeCloudZoneStatus": "unknown",
                "edgeCloudRegion": "unknown",
            },
        },
        {
            "appId": "app-123",
            "appInstanceId": "inst-1",
            "status": "ready",
            "edgeCloudZone": {
                "edgeCloudZoneId": "default",
                "edgeCloudZoneName": "zone-default",
                "edgeCloudProvider": "Local Operator",
                "edgeCloudZoneStatus": "active",
                "edgeCloudRegion": "unknown",
            },
        },
    ])

    assert deduped == [{
        "appId": "app-123",
        "appInstanceId": "inst-1",
        "status": "ready",
        "edgeCloudZone": {
            "edgeCloudZoneId": "default",
            "edgeCloudZoneName": "zone-default",
            "edgeCloudProvider": "Local Operator",
            "edgeCloudZoneStatus": "active",
            "edgeCloudRegion": "unknown",
        },
    }]


@patch("edge_cloud_management_api.controllers.app_controllers.get_zone")
def test_enrich_instance_zone_from_catalog_uses_stored_provider_identity(mock_get_zone):
    mock_get_zone.return_value = {
        "edgeCloudZoneId": "default",
        "edgeCloudZoneName": "zone-default",
        "edgeCloudProvider": "Local Operator",
        "edgeCloudZoneStatus": "active",
        "edgeCloudRegion": "unknown",
    }

    enriched = app_controllers._enrich_instance_zone_from_catalog({
        "appId": "app-123",
        "appInstanceId": "inst-1",
        "status": "ready",
        "edgeCloudZone": {
            "edgeCloudZoneId": "default",
            "edgeCloudZoneName": "unknown",
            "edgeCloudProvider": "unknown",
            "edgeCloudZoneStatus": "unknown",
            "edgeCloudRegion": "unknown",
        },
    })

    assert enriched == {
        "appId": "app-123",
        "appInstanceId": "inst-1",
        "status": "ready",
        "edgeCloudZone": {
            "edgeCloudZoneId": "default",
            "edgeCloudZoneName": "zone-default",
            "edgeCloudProvider": "Local Operator",
            "edgeCloudZoneStatus": "active",
            "edgeCloudRegion": "unknown",
        },
    }


@patch("edge_cloud_management_api.controllers.app_controllers.get_all_feds", return_value=[])
@patch("edge_cloud_management_api.controllers.app_controllers.SRMAPIClientFactory")
def test_get_app_instance_returns_empty_list_when_no_instances(mock_factory_class, _mock_get_all_feds):