Loading src/open_exposure_gateway/application/mappers/edge_application_mapper.py +6 −1 Changes for src/open_exposure_gateway/application/mappers/edge_application_mapper.py: 6 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -101,6 +101,10 @@ _CALLBACK_EVENT_SOURCE = "https://api.example.com/edge-application-management/v1 _VISIBILITY_REVERSE_MAP: dict[str, str] = {v: k for k, v in _VISIBILITY_MAP.items()} # Returned as `appProvider` for apps registered before the submitted name was stored in the # spec descriptor. Must itself satisfy CAMARA's AppProvider pattern. UNKNOWN_APP_PROVIDER = "unknown_provider" _SRM_STATE_TO_APP_INSTANCE_STATUS: dict[str, AppInstanceStatus] = { "creating": AppInstanceStatus.INSTANTIATING, "active": AppInstanceStatus.READY, Loading Loading @@ -358,7 +362,7 @@ def build_app_manifest(catalog: SRMCatalogPayload) -> AppManifest: return AppManifest( appId=app_id, name=spec.name, appProvider=spec.app_provider_id, appProvider=spec.descriptor.app_provider or UNKNOWN_APP_PROVIDER, version=spec.version, packageType=package_type, # type: ignore[arg-type] operatingSystem=None, Loading Loading @@ -689,6 +693,7 @@ def build_catalog_payload(translation: AppRegistrationTranslation) -> SRMCatalog app_provider_id=translation.app_provider_id, descriptor=SRMServiceSpecDescriptor( artifact_type=runtime_kind, app_provider=translation.app_provider or None, ), ), service_deployment_units=[deployment_unit], Loading src/open_exposure_gateway/domain/edge_application_management.py +3 −0 Changes for src/open_exposure_gateway/domain/edge_application_management.py: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -179,6 +179,9 @@ class SRMComputeIntent(BaseModel): class SRMServiceSpecDescriptor(BaseModel): artifact_type: str | None = None source_api: str = "edge-application-management" # The CAMARA `appProvider` name submitted on POST /apps. Kept here because the spec's # app_provider_id is the caller's identity (token `sub`), not this display name. app_provider: str | None = None class SRMServiceSpecEntry(BaseModel): Loading tests/unit/test_eam_mapper.py +37 −2 Changes for tests/unit/test_eam_mapper.py: 37 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ from open_exposure_gateway.api.camara.edge_application_management.v0_1_0_alpha_1 VmResources, ) from open_exposure_gateway.application.mappers.edge_application_mapper import ( UNKNOWN_APP_PROVIDER, build_app_deployment_info, build_app_deployment_translation, build_app_instance_info, Loading Loading @@ -66,6 +67,8 @@ INSTANCE_ID = UUID("cccccccc-cccc-cccc-cccc-cccccccccccc") OP_ID = UUID("dddddddd-dddd-dddd-dddd-dddddddddddd") APP_REGISTRATION_ID = UUID("ffffffff-ffff-ffff-ffff-ffffffffffff") DEPLOYMENT_ID = UUID("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee") # The caller's Keycloak `sub`: what OEG stores as the spec's app_provider_id. CALLER_SUB = "393d5cd6-0a8a-47cd-8c13-33eaa04201d1" def _make_srm_catalog( Loading @@ -76,6 +79,7 @@ def _make_srm_catalog( memory_mb: int = 4096, interfaces: list[SRMNetworkInterface] | None = None, standalone: bool = False, app_provider: str | None = "VideoAppsCo", ) -> SRMCatalogPayload: return SRMCatalogPayload( service_specification=SRMServiceSpecEntry( Loading @@ -83,8 +87,10 @@ def _make_srm_catalog( ref=str(APP_ID), name="myvideoapp", version="1.0.0", app_provider_id="VideoAppsCo", descriptor=SRMServiceSpecDescriptor(artifact_type=runtime_kind), app_provider_id=CALLER_SUB, descriptor=SRMServiceSpecDescriptor( artifact_type=runtime_kind, app_provider=app_provider ), ), service_deployment_units=[ SRMDeploymentUnit( Loading Loading @@ -242,6 +248,16 @@ class TestBuildAppManifest: assert result.appProvider == "VideoAppsCo" assert result.packageType == "HELM" def test_app_provider_is_the_submitted_name_not_the_caller_id(self) -> None: # the caller's `sub` is a UUID, which CAMARA's AppProvider pattern rejects result = build_app_manifest(_make_srm_catalog()) assert result.appProvider == "VideoAppsCo" assert result.appProvider != CALLER_SUB def test_app_provider_falls_back_when_spec_predates_the_stored_name(self) -> None: result = build_app_manifest(_make_srm_catalog(app_provider=None)) assert result.appProvider == UNKNOWN_APP_PROVIDER def test_helm_produces_kubernetes_resources(self) -> None: catalog = _make_srm_catalog(cpu_millicores=2000, memory_mb=4096) result = build_app_manifest(catalog) Loading Loading @@ -652,6 +668,25 @@ class TestBuildAppRegistrationTranslation: class TestBuildCatalogPayload: def test_submitted_app_provider_stored_in_descriptor(self) -> None: manifest = _make_helm_manifest() translation = build_app_registration_translation( manifest, APP_ID, APP_REGISTRATION_ID, "t", CALLER_SUB ) spec = build_catalog_payload(translation).service_specification assert spec.descriptor.app_provider == manifest.appProvider assert spec.app_provider_id == CALLER_SUB def test_app_provider_round_trips_through_catalog(self) -> None: manifest = _make_helm_manifest() translation = build_app_registration_translation( manifest, APP_ID, APP_REGISTRATION_ID, "t", CALLER_SUB ) assert ( build_app_manifest(build_catalog_payload(translation)).appProvider == manifest.appProvider ) def test_runtime_kind_from_package_type(self) -> None: manifest = _make_helm_manifest() translation = build_app_registration_translation( Loading Loading
src/open_exposure_gateway/application/mappers/edge_application_mapper.py +6 −1 Changes for src/open_exposure_gateway/application/mappers/edge_application_mapper.py: 6 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -101,6 +101,10 @@ _CALLBACK_EVENT_SOURCE = "https://api.example.com/edge-application-management/v1 _VISIBILITY_REVERSE_MAP: dict[str, str] = {v: k for k, v in _VISIBILITY_MAP.items()} # Returned as `appProvider` for apps registered before the submitted name was stored in the # spec descriptor. Must itself satisfy CAMARA's AppProvider pattern. UNKNOWN_APP_PROVIDER = "unknown_provider" _SRM_STATE_TO_APP_INSTANCE_STATUS: dict[str, AppInstanceStatus] = { "creating": AppInstanceStatus.INSTANTIATING, "active": AppInstanceStatus.READY, Loading Loading @@ -358,7 +362,7 @@ def build_app_manifest(catalog: SRMCatalogPayload) -> AppManifest: return AppManifest( appId=app_id, name=spec.name, appProvider=spec.app_provider_id, appProvider=spec.descriptor.app_provider or UNKNOWN_APP_PROVIDER, version=spec.version, packageType=package_type, # type: ignore[arg-type] operatingSystem=None, Loading Loading @@ -689,6 +693,7 @@ def build_catalog_payload(translation: AppRegistrationTranslation) -> SRMCatalog app_provider_id=translation.app_provider_id, descriptor=SRMServiceSpecDescriptor( artifact_type=runtime_kind, app_provider=translation.app_provider or None, ), ), service_deployment_units=[deployment_unit], Loading
src/open_exposure_gateway/domain/edge_application_management.py +3 −0 Changes for src/open_exposure_gateway/domain/edge_application_management.py: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -179,6 +179,9 @@ class SRMComputeIntent(BaseModel): class SRMServiceSpecDescriptor(BaseModel): artifact_type: str | None = None source_api: str = "edge-application-management" # The CAMARA `appProvider` name submitted on POST /apps. Kept here because the spec's # app_provider_id is the caller's identity (token `sub`), not this display name. app_provider: str | None = None class SRMServiceSpecEntry(BaseModel): Loading
tests/unit/test_eam_mapper.py +37 −2 Changes for tests/unit/test_eam_mapper.py: 37 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ from open_exposure_gateway.api.camara.edge_application_management.v0_1_0_alpha_1 VmResources, ) from open_exposure_gateway.application.mappers.edge_application_mapper import ( UNKNOWN_APP_PROVIDER, build_app_deployment_info, build_app_deployment_translation, build_app_instance_info, Loading Loading @@ -66,6 +67,8 @@ INSTANCE_ID = UUID("cccccccc-cccc-cccc-cccc-cccccccccccc") OP_ID = UUID("dddddddd-dddd-dddd-dddd-dddddddddddd") APP_REGISTRATION_ID = UUID("ffffffff-ffff-ffff-ffff-ffffffffffff") DEPLOYMENT_ID = UUID("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee") # The caller's Keycloak `sub`: what OEG stores as the spec's app_provider_id. CALLER_SUB = "393d5cd6-0a8a-47cd-8c13-33eaa04201d1" def _make_srm_catalog( Loading @@ -76,6 +79,7 @@ def _make_srm_catalog( memory_mb: int = 4096, interfaces: list[SRMNetworkInterface] | None = None, standalone: bool = False, app_provider: str | None = "VideoAppsCo", ) -> SRMCatalogPayload: return SRMCatalogPayload( service_specification=SRMServiceSpecEntry( Loading @@ -83,8 +87,10 @@ def _make_srm_catalog( ref=str(APP_ID), name="myvideoapp", version="1.0.0", app_provider_id="VideoAppsCo", descriptor=SRMServiceSpecDescriptor(artifact_type=runtime_kind), app_provider_id=CALLER_SUB, descriptor=SRMServiceSpecDescriptor( artifact_type=runtime_kind, app_provider=app_provider ), ), service_deployment_units=[ SRMDeploymentUnit( Loading Loading @@ -242,6 +248,16 @@ class TestBuildAppManifest: assert result.appProvider == "VideoAppsCo" assert result.packageType == "HELM" def test_app_provider_is_the_submitted_name_not_the_caller_id(self) -> None: # the caller's `sub` is a UUID, which CAMARA's AppProvider pattern rejects result = build_app_manifest(_make_srm_catalog()) assert result.appProvider == "VideoAppsCo" assert result.appProvider != CALLER_SUB def test_app_provider_falls_back_when_spec_predates_the_stored_name(self) -> None: result = build_app_manifest(_make_srm_catalog(app_provider=None)) assert result.appProvider == UNKNOWN_APP_PROVIDER def test_helm_produces_kubernetes_resources(self) -> None: catalog = _make_srm_catalog(cpu_millicores=2000, memory_mb=4096) result = build_app_manifest(catalog) Loading Loading @@ -652,6 +668,25 @@ class TestBuildAppRegistrationTranslation: class TestBuildCatalogPayload: def test_submitted_app_provider_stored_in_descriptor(self) -> None: manifest = _make_helm_manifest() translation = build_app_registration_translation( manifest, APP_ID, APP_REGISTRATION_ID, "t", CALLER_SUB ) spec = build_catalog_payload(translation).service_specification assert spec.descriptor.app_provider == manifest.appProvider assert spec.app_provider_id == CALLER_SUB def test_app_provider_round_trips_through_catalog(self) -> None: manifest = _make_helm_manifest() translation = build_app_registration_translation( manifest, APP_ID, APP_REGISTRATION_ID, "t", CALLER_SUB ) assert ( build_app_manifest(build_catalog_payload(translation)).appProvider == manifest.appProvider ) def test_runtime_kind_from_package_type(self) -> None: manifest = _make_helm_manifest() translation = build_app_registration_translation( Loading