Commit 9607e885 authored by Konstantinos Togias's avatar Konstantinos Togias
Browse files

Merge current develop into SDK consumer qualification

parents 0156d75e 8fdb12a5
Loading
Loading
Loading
Loading
Loading
+3 −0
Changes for .env.example: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -15,3 +15,6 @@ NATS_SETTINGS__DRAIN_TIMEOUT = 30
FEDERATION_MANAGER_SETTINGS__BASE_URL = "http://localhost:8082"
FEDERATION_MANAGER_SETTINGS__TIMEOUT = 0.5
FEDERATION_MANAGER_SETTINGS__ENABLED = true

# One complete SDK bootstrap; leave unset for an empty topology/health-only startup.
# BOOTSTRAP_TOPOLOGY_PATH=/etc/srm/topology.yaml
+1 −0
Changes for .pre-commit-config.yaml: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -35,3 +35,4 @@ repos:
        - "sqlalchemy>=2.0.48"
        - "structlog>=25.5.0"
        - "testcontainers[postgres]>=4.13.2"
        - "types-PyYAML>=6.0.12"
+30 −0
Changes for README.md: 30 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -4,3 +4,33 @@ A Python, FastAPI-based microservice to work as the brains of ETSI SDG OpenOP.

## WIP
WIP


## Release 2 control-path bootstrap

Set `BOOTSTRAP_TOPOLOGY_PATH` to one mounted, complete SDK bootstrap document.
SRM loads it once through `BootstrapTopology`, builds the runtime registry from
its operational entries, and passes the same object through the existing four-
method discovery bridge. The SDK owns parsing and adapter-kind construction.
SRM keeps topology persistence, selection and placement.

Declare identity once in `control_paths[].ref`. Registry construction derives
`config["control_path_ref"]` from that key on a copied config. SDK execution
methods reject another target with `INVALID_TARGET_REF` before credentials or
backend calls. Duplicate registry refs and conflicting config identities fail
before any instance is constructed.

Without `BOOTSTRAP_TOPOLOGY_PATH`, the existing empty-topology health startup
remains available. Existing create-missing topology seeding is unchanged;
restarting does not reconcile edits to existing database records.

Use SDK 2.0.0rc3 with the matching chart/configuration migration. Kubernetes
paths require explicit kubeconfig/context/namespace or explicit in-cluster mode
and namespace. Deployment tooling owns protected credential mounts and the
writable SDK runtime directory. See `tests/fixtures/tf_sdk_bootstrap_example.yaml`.
SDK status observation and SRM termination behavior remain unchanged. Broader
UNKNOWN handling remains a separate follow-up.

The SDK artifact and matching component revisions must be available before
merging/deploying this change. Upgrade or roll back SDK, SRM and deployment
configuration together.
+1 −1
Changes for pyproject.toml: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ dependencies = [
    "sqlalchemy>=2.0.48",
    "asyncpg>=0.31.0",
    "nats-py>=2.10.0",
    "openop-tfsdk==2.0.0rc2",
    "openop-tfsdk==2.0.0rc4",
    "apscheduler<4.0.0",
]

+22 −0
Changes for src/srm/adapters/database/repos/catalog.py: 22 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -74,6 +74,28 @@ class SqlServiceSpecificationRepository(ServiceSpecificationRepository):
        row = await self._session.scalar(stmt)
        return ServiceSpecificationMapper.to_domain(row) if row is not None else None

    async def get_by_ref(self, app_provider_id: str, ref: str) -> ServiceSpecification | None:
        stmt = (
            select(ServiceSpecificationRow)
            .options(
                selectinload(ServiceSpecificationRow.deployment_units),
                selectinload(ServiceSpecificationRow.capability_requirements),
            )
            .where(
                ServiceSpecificationRow.app_provider_id == app_provider_id,
                ServiceSpecificationRow.ref == ref,
                ServiceSpecificationRow.state == ServiceSpecificationState.ACTIVE,
            )
            .order_by(
                ServiceSpecificationRow.created_at.desc(),
                ServiceSpecificationRow.version.desc(),
                ServiceSpecificationRow.id.desc(),
            )
            .limit(1)
        )
        row = await self._session.scalar(stmt)
        return ServiceSpecificationMapper.to_domain(row) if row is not None else None

    async def list_by_app_provider_id(self, app_provider_id: str) -> list[ServiceSpecification]:
        stmt = (
            select(ServiceSpecificationRow)
Loading