Commit 749a6720 authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

fix: update standalone handling in resource requirements and catalog payload

parent 305146a0
Loading
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -227,7 +227,7 @@ def build_app_manifest(catalog: SRMCatalogPayload) -> AppManifest:
        required_resources = KubernetesResources(
            infraKind="kubernetes",
            applicationResources=CamaraApplicationResources.model_validate(app_res),
            isStandalone=compute.standalone if compute else False,
            isStandalone=unit.resource_requirements.standalone,
        )
    elif unit.runtime_kind == "container":
        millicores = compute.cpu_millicores if compute and compute.cpu_millicores is not None else 0
@@ -502,7 +502,6 @@ def build_catalog_payload(translation: AppRegistrationTranslation) -> SRMCatalog
    compute = SRMComputeResources(
        cpu_millicores=cpu_millicores,
        memory_mb=memory_mb,
        standalone=standalone,
        accelerator=accelerator,
        storage=storage,
    )
@@ -523,6 +522,7 @@ def build_catalog_payload(translation: AppRegistrationTranslation) -> SRMCatalog
        compute=compute,
        topology=topology,
        interfaces=interfaces or None,
        standalone=standalone,
    )

    repo = translation.app_repo
+2 −1
Original line number Diff line number Diff line
@@ -218,7 +218,8 @@ class EdgeApplicationManagementService:
        )
        catalog_payload = build_catalog_payload(translation)
        created = await self.srm_client.create_catalog_service_specification(
            payload=catalog_payload.model_dump(mode="json"), x_correlator=x_correlator
            payload=catalog_payload.model_dump(mode="json", exclude_none=True),
            x_correlator=x_correlator,
        )
        if created.id != translation.app_registration_id:
            raise DownstreamServiceException(
+1 −1
Original line number Diff line number Diff line
@@ -128,7 +128,6 @@ class SRMStorageVolume(BaseModel):
class SRMComputeResources(BaseModel):
    cpu_millicores: int | None = None
    memory_mb: int | None = None
    standalone: bool = False
    accelerator: SRMAccelerator | None = None
    storage: list[SRMStorageVolume] | None = None

@@ -153,6 +152,7 @@ class SRMComputeIntent(BaseModel):
    compute: SRMComputeResources | None = None
    topology: SRMTopologyConstraints | None = None
    interfaces: list[SRMNetworkInterface] | None = None
    standalone: bool = False


class SRMServiceSpecDescriptor(BaseModel):
+23 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ def _make_srm_catalog(
    cpu_millicores: int = 2000,
    memory_mb: int = 4096,
    interfaces: list[SRMNetworkInterface] | None = None,
    standalone: bool = False,
) -> SRMCatalogPayload:
    return SRMCatalogPayload(
        service_specification=SRMServiceSpecEntry(
@@ -94,6 +95,7 @@ def _make_srm_catalog(
                        min_node_memory_mb=1024,
                    ),
                    interfaces=interfaces,
                    standalone=standalone,
                ),
            )
        ],
@@ -274,6 +276,14 @@ class TestBuildAppManifest:
        assert result.componentSpec[0].componentName == "frontend"
        assert len(result.componentSpec[0].networkInterfaces) == 2

    def test_standalone_read_from_top_level_field(self) -> None:
        # standalone lives on resource_requirements itself, not nested under
        # resource_requirements.compute (srm/canonical-parameters-schema.md).
        catalog = _make_srm_catalog(standalone=True)
        result = build_app_manifest(catalog)
        assert isinstance(result.requiredResources, KubernetesResources)
        assert result.requiredResources.isStandalone is True

    def test_helm_topology_reconstructed(self) -> None:
        catalog = _make_srm_catalog()
        catalog.service_deployment_units[0].resource_requirements.topology = SRMTopologyConstraints(
@@ -576,6 +586,19 @@ class TestBuildCatalogPayload:
        assert compute.cpu_millicores == 2000
        assert compute.memory_mb == 4096

    def test_standalone_is_top_level_not_nested_in_compute(self) -> None:
        # SRM's srm.compute/v1 shape puts `standalone` as a sibling of `compute`,
        # not inside it (srm/canonical-parameters-schema.md); SRM rejects unknown
        # fields, so a nested `compute.standalone` fails app registration outright.
        manifest = _make_helm_manifest(standalone=True)
        translation = build_app_registration_translation(
            manifest, APP_ID, APP_REGISTRATION_ID, "t", "p"
        )
        catalog = build_catalog_payload(translation)
        resource_requirements = catalog.service_deployment_units[0].resource_requirements
        assert resource_requirements.standalone is True
        assert not hasattr(resource_requirements.compute, "standalone")

    def test_spec_ref_is_app_id(self) -> None:
        manifest = _make_helm_manifest()
        translation = build_app_registration_translation(
+20 −0
Original line number Diff line number Diff line
@@ -382,6 +382,26 @@ class TestSubmitApp:
        assert payload["service_specification"]["id"] == str(stored.app_registration_id)
        assert payload["service_specification"]["id"] != str(APP_ID)

    async def test_catalog_payload_omits_unset_fields_instead_of_sending_null(
        self,
        service: EdgeApplicationManagementService,
        srm_client: AsyncMock,
    ) -> None:
        # SRM rejects unknown/null fields outright; unset optional fields must be
        # absent from the JSON body, not present with a `null` value.
        await service.submit_app(
            manifest=_make_manifest(),
            app_id=APP_ID,
            tenant_id="tenant-1",
            app_provider_id="provider-1",
        )
        call_kwargs = srm_client.create_catalog_service_specification.call_args.kwargs
        payload = call_kwargs["payload"]
        resource_requirements = payload["service_deployment_units"][0]["resource_requirements"]
        assert "accelerator" not in resource_requirements["compute"]
        assert "standalone" in resource_requirements
        assert "standalone" not in resource_requirements["compute"]

    async def test_raises_when_srm_confirms_a_different_id(
        self, service: EdgeApplicationManagementService, srm_client: AsyncMock
    ) -> None: