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

fix: recover from stale federated state

Prune stale partner onboarding and deployment records when runtime state is gone, treat deboarding as idempotent on runtime 404, and let originating FM recreate partner onboarding after rebuild-driven state loss.
parent 2f6ebeb2
Loading
Loading
Loading
Loading
+15 −16
Original line number Diff line number Diff line
@@ -137,10 +137,9 @@ def onboard_application(body, federation_context_id, bearer_token, partner_api_r
                error_message = response_get["error"]
                raise APIError(status_code, f"Partner API error: {error_message}")
            # 404 means application doesn't exist at partner, continue with onboarding logic
            if find_application_onboarding_at_originating_op(federation_context_id, body.app_id):
                raise APIError(409, "Application onboarding exist in originating operator but not exist at partner operator")
            else:
                # Create application profile at partner
            originating_ao_objects = find_application_onboarding_at_originating_op(federation_context_id, body.app_id)

            # Recreate partner onboarding if partner runtime/bookkeeping was lost after a rebuild.
            response_data = fm_client.create_profile(originating_op_instance.partner_federation_id, body, bearer_token,
                                                     partner_api_root)

@@ -150,7 +149,7 @@ def onboard_application(body, federation_context_id, bearer_token, partner_api_r
                error_message = response_data["error"]
                raise APIError(status_code, f"Partner API error: {error_message}")
            elif "accepted" in response_data:
                    # Create application onboarding in originating
                if not originating_ao_objects:
                    create_application_onboarding_originating_op(federation_context_id,
                                                                 originating_op_instance.partner_federation_id, body)
                return response_data, 202
+25 −1
Original line number Diff line number Diff line
@@ -26,6 +26,20 @@ from adapters.error import APIError
from clients import srm


def _delete_stale_app_version_records(originating_ad_version_objects, app_id):
    for deployment in originating_ad_version_objects:
        try:
            response = srm.get_app_by_zone_app_instance_id(
                app_id,
                deployment.orig_ad_instance_id,
                deployment.orig_ad_zone_info_zone_id,
            )
            if response.status_code == 404:
                deployment.delete()
        except Exception:
            continue


def get_all_app_instances(federation_context_id, app_id, app_provider_id, bearer_token=None, partner_api_root=None):  # noqa: E501
    """Retrieves all application instance of partner OP

@@ -234,6 +248,13 @@ def install_app(federation_context_id, body, bearer_token=None, partner_api_root
        orig_ad_app_id=body.app_id,
        orig_ad_app_version=body.app_version
    )
    if originating_ad_version_objects:
        _delete_stale_app_version_records(originating_ad_version_objects, body.app_id)
        originating_ad_version_objects = OriginatingApplicationDeploymentManagement.objects(
            orig_ad_federation_context_id=federation_context_id,
            orig_ad_app_id=body.app_id,
            orig_ad_app_version=body.app_version
        )
    if originating_ad_version_objects:
        raise APIError(409, "App Version already exists for the App Id in the Application Deployment Management")

@@ -342,11 +363,14 @@ def remove_app(federation_context_id, app_id, app_instance_id, zone_id, bearer_t

    # Check if exist instance id at Edge Cloud Platform and delete
    response = srm.get_app_by_zone_app_instance_id(app_id, app_instance_id, zone_id)
    if response.status_code == 404:
        originating_ad_objects.delete()
        return 'Application instance termination request accepted', 200
    if response.status_code == 200 or response.status_code == 503:
        # Delete Application command at Edge Cloud Platform
        try:
            response = srm.delete_app(app_id, app_instance_id, zone_id)
            if response.status_code == 200:
            if response.status_code == 200 or response.status_code == 404:
                # Delete Application Deployment
                originating_ad_objects.delete()
            else:
+40 −11
Original line number Diff line number Diff line
@@ -27,6 +27,34 @@ from adapters.error import APIError
from clients import srm


def _delete_onboarding_updates(originating_ao_objects):
    obj_onboarding = originating_ao_objects.get()
    id_onboarding = obj_onboarding.id
    originating_ao_update_objects = OriginatingApplicationOnboardingManagementUpdate.objects()
    for o in originating_ao_update_objects:
        try:
            if o.federation_context_app_id.pk == id_onboarding:
                o.delete()
        except Exception as error:
            print(f"Unable to delete onboarding updates. Error: {error}")


def _prune_stale_onboarding_record(federation_context_id, app_id):
    originating_ao_objects = OriginatingApplicationOnboardingManagement.objects(
        orig_ao_federation_context_id=federation_context_id,
        orig_ao_app_id=app_id)
    if not originating_ao_objects or check_child_onboarding(federation_context_id, app_id):
        return

    try:
        response = srm.get_onboarding(app_id)
        if response.status_code == 404:
            _delete_onboarding_updates(originating_ao_objects)
            originating_ao_objects.delete()
    except Exception:
        return


def delete_app(federation_context_id, app_id, bearer_token=None, partner_api_root=None):  # noqa: E501
    """Deboards the application from any zones, if any, and deletes the App.

@@ -66,18 +94,9 @@ def delete_app(federation_context_id, app_id, bearer_token=None, partner_api_roo
    # Delete onboarding at edgecloud_client
    try:
        response = srm.delete_onboarding(app_id)
        if response.status_code == 200:
        if response.status_code == 200 or response.status_code == 404:
            # Delete all the onboarding updates related to onboarding application
            obj_onboarding = originating_ao_objects.get()
            id_onboarding = obj_onboarding.id
            originating_ao_update_objects = OriginatingApplicationOnboardingManagementUpdate.objects()
            for o in originating_ao_update_objects:
                try:
                    if o.federation_context_app_id.pk == id_onboarding:
                        o.delete()
                except Exception as error:
                    print(f"Unable to delete onboarding updates. Error: {error}")

            _delete_onboarding_updates(originating_ao_objects)
            # Delete Application Onboarding
            originating_ao_objects.delete()
        else:
@@ -118,6 +137,11 @@ def onboard_application(body, federation_context_id, bearer_token=None, partner_
    originating_ao_objects = OriginatingApplicationOnboardingManagement.objects(
        orig_ao_federation_context_id=federation_context_id,
        orig_ao_app_id=body.app_id)
    if originating_ao_objects:
        _prune_stale_onboarding_record(federation_context_id, body.app_id)
        originating_ao_objects = OriginatingApplicationOnboardingManagement.objects(
            orig_ao_federation_context_id=federation_context_id,
            orig_ao_app_id=body.app_id)
    if originating_ao_objects:
        raise APIError(409, "Federation Context and App Id already exists at Application Onboarding Management")

@@ -268,6 +292,11 @@ def view_application(federation_context_id, app_id, bearer_token=None, partner_a
    originating_ao_objects = OriginatingApplicationOnboardingManagement.objects(
        orig_ao_federation_context_id=federation_context_id,
        orig_ao_app_id=app_id)
    if originating_ao_objects:
        _prune_stale_onboarding_record(federation_context_id, app_id)
        originating_ao_objects = OriginatingApplicationOnboardingManagement.objects(
            orig_ao_federation_context_id=federation_context_id,
            orig_ao_app_id=app_id)
    if not originating_ao_objects:
        raise APIError(404, "Federation Context and App Id not found at Application Onboarding Management")