Commit a4fa85dd authored by Paris Stentoumis's avatar Paris Stentoumis
Browse files

Merge branch 'fix/single-bootstrap-control-paths' into 'develop'

Align control-path bootstrap with TF-SDK for Release 2.0.0

See merge request !43
parents d3c0221b 8c31964a
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.0rc3",
    "apscheduler<4.0.0",
]

+16 −2
Changes for src/srm/adapters/transformation_functions/registry.py: 16 added lines, 2 removed lines.
Original line number Diff line number Diff line
from collections.abc import Mapping
from copy import deepcopy

import structlog

@@ -35,7 +36,7 @@ def build_control_path_registry(
    settings: ControlPathSettings,
    factory: TransformationFunctionAdapterFactory | None,
) -> ConfiguredControlPathRegistry:
    logger.info("building_cpr", entries=settings.entries)
    logger.info("building_cpr", entry_count=len(settings.entries))
    if not settings.entries:
        return ConfiguredControlPathRegistry({})
    if factory is None:
@@ -43,9 +44,22 @@ def build_control_path_registry(
            "control paths are configured but no TF-SDK adapter factory is installed: "
            + ", ".join(entry.control_path_ref for entry in settings.entries)
        )
    refs: set[str] = set()
    for entry in settings.entries:
        if not entry.control_path_ref.strip() or entry.control_path_ref in refs:
            raise ValueError("Control-path refs must be nonempty and unique")
        refs.add(entry.control_path_ref)
        if (
            "control_path_ref" in entry.config
            and entry.config["control_path_ref"] != entry.control_path_ref
        ):
            raise ValueError("Control-path config identity conflicts with its registry key")
    return ConfiguredControlPathRegistry(
        {
            entry.control_path_ref: factory.create_adapter(entry.adapter, entry.config)
            entry.control_path_ref: factory.create_adapter(
                entry.adapter,
                {**deepcopy(entry.config), "control_path_ref": entry.control_path_ref},
            )
            for entry in settings.entries
        }
    )
Loading