Commit 0ff8c2be authored by Sergio Gimenez's avatar Sergio Gimenez
Browse files

feat(fm): expose our federation identity on GET /internal/identity

The portal must send partnerStatusLink in CreateFederation, but FM
rejects any value other than its own configured one. Serve the identity
FM already builds from config (federation id, MCC/MNC, platform caps,
callback links) so OEG can relay it and the portal can fill the field
instead of asking the operator.
parent b4a13313
Loading
Loading
Loading
Loading
Loading
+39 −0
Changes for src/federation_manager/api/internal/identity.py: 39 added lines, 0 removed lines.
Original line number Diff line number Diff line
from typing import Annotated

from fastapi import APIRouter, Depends
from pydantic import BaseModel

from federation_manager.application.federation import LocalOperator
from federation_manager.dependencies import get_local_operator

router = APIRouter(prefix="/internal/identity", tags=["internal-identity"])


class MobileNetworkCodes(BaseModel):
    mcc: str
    mncs: list[str]


class Identity(BaseModel):
    """What this OP sends every partner in CreateFederation; read from config, never stored."""

    federation_id: str
    country_code: str
    mobile_network_codes: MobileNetworkCodes
    platform_caps: list[str]
    partner_status_link: str
    instance_status_link: str | None
    avail_zone_notif_link: str | None


@router.get("")
async def get_identity(local: Annotated[LocalOperator, Depends(get_local_operator)]) -> Identity:
    return Identity(
        federation_id=local.federation_id,
        country_code=local.country_code,
        mobile_network_codes=MobileNetworkCodes(mcc=local.mcc, mncs=list(local.mncs)),
        platform_caps=list(local.platform_caps),
        partner_status_link=local.partner_status_link,
        instance_status_link=local.instance_status_link,
        avail_zone_notif_link=local.avail_zone_notif_link,
    )
+2 −0
Changes for src/federation_manager/main.py: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ from federation_manager.api.ewbi.v1.onboarding import router as ewbi_onboarding_
from federation_manager.api.ewbi.v1.service import router as ewbi_service_router
from federation_manager.api.ewbi.v1.zones import router as ewbi_zones_router
from federation_manager.api.internal.federation import router as internal_federation_router
from federation_manager.api.internal.identity import router as internal_identity_router
from federation_manager.api.internal.partner_federations import (
    router as internal_partner_federations_router,
)
@@ -206,6 +207,7 @@ def create_app(lifespan: Lifespan[FastAPI] | None = None) -> FastAPI:
    app.include_router(ewbi_zones_router)
    app.include_router(ewbi_onboarding_router)
    app.include_router(internal_federation_router)
    app.include_router(internal_identity_router)
    app.include_router(internal_partner_federations_router)
    app.include_router(internal_partners_router)
    app.include_router(internal_zones_router)
+55 −0
Changes for tests/test_internal_identity.py: 55 added lines, 0 removed lines.
Original line number Diff line number Diff line
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

from fastapi import FastAPI
from fastapi.testclient import TestClient

from federation_manager.application.federation import LocalOperator
from federation_manager.dependencies import get_local_operator
from federation_manager.main import create_app

IDENTITY = "/internal/identity"


@asynccontextmanager
async def _no_infra(app: FastAPI) -> AsyncIterator[None]:
    yield


def _client(local: LocalOperator) -> TestClient:
    app = create_app(lifespan=_no_infra)
    app.dependency_overrides[get_local_operator] = lambda: local
    return TestClient(app)


def test_returns_local_operator_identity_from_config() -> None:
    local = LocalOperator(
        federation_id="oop-i2cat",
        country_code="ES",
        mcc="214",
        mncs=("07", "01"),
        partner_status_link="https://fm.example/operatorplatform/federation/v1/callbacks/partner-status",
        instance_status_link="https://fm.example/operatorplatform/federation/v1/callbacks/instance-status",
    )

    response = _client(local).get(IDENTITY)

    assert response.status_code == 200
    assert response.json() == {
        "federation_id": "oop-i2cat",
        "country_code": "ES",
        "mobile_network_codes": {"mcc": "214", "mncs": ["07", "01"]},
        "platform_caps": ["serviceAPIs"],
        "partner_status_link": local.partner_status_link,
        "instance_status_link": local.instance_status_link,
        "avail_zone_notif_link": None,
    }


def test_default_config_identity_is_served() -> None:
    app = create_app(lifespan=_no_infra)

    body = TestClient(app).get(IDENTITY).json()

    assert body["federation_id"] == "oop-local"
    assert body["partner_status_link"].startswith("http")