Loading pyproject.toml +4 −0 Changes for pyproject.toml: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ dependencies = [ "sqlalchemy>=2.0.48", "asyncpg>=0.31.0", "nats-py>=2.10.0", "openop-tfsdk", ] [project.optional-dependencies] Loading @@ -37,6 +38,9 @@ dev = [ "ruff>=0.15.6", ] [tool.uv.sources] openop-tfsdk = { path = "../tf-sdk", editable = true } [tool.ruff] line-length = 100 target-version = "py312" Loading src/srm/adapters/transformation_functions/tfsdk_execution.py 0 → 100644 +188 −0 Changes for src/srm/adapters/transformation_functions/tfsdk_execution.py: 188 added lines, 0 removed lines. Original line number Diff line number Diff line """TF-SDK execution adapter factory and SRM execution-port bridge. TF-SDK owns construction by adapter kind (`build_adapter`). SRM owns the `control_path_ref` → instance map. This module bridges the short TF-SDK action vocabulary to SRM's longer execution-port method names. """ from __future__ import annotations from collections.abc import Mapping from typing import Any from openop_tfsdk.contract import execution_models as tfsdk_models from openop_tfsdk.contract.adapters import build_adapter from openop_tfsdk.contract.errors import UnknownAdapterKind as TfSdkUnknownAdapterKind from srm.domain.models.runtime_inventory import CapabilityInstanceState from srm.domain.models.topology import CapabilityKind from srm.domain.ports.transformation_functions import ( CapabilityLifecycleRequest, CapabilityLifecycleResult, CapabilityQueryRequest, CapabilityQueryResult, CapabilityRuntimeState, CapabilityRuntimeStateRequest, TransformationFunctionAdapterFactory, TransformationFunctionExecutionPort, UnknownAdapterKind, UnsupportedAction, ) _LIFECYCLE_STATE_MAP: dict[str, CapabilityInstanceState] = { "provisioning": CapabilityInstanceState.CREATING, "active": CapabilityInstanceState.ACTIVE, "updating": CapabilityInstanceState.UPDATING, "failed": CapabilityInstanceState.FAILED, "deactivating": CapabilityInstanceState.TERMINATING, "deactivated": CapabilityInstanceState.TERMINATED, } _RUNTIME_STATE_MAP: dict[str, CapabilityInstanceState] = { "active": CapabilityInstanceState.ACTIVE, "degraded": CapabilityInstanceState.DEGRADED, "failed": CapabilityInstanceState.FAILED, "deactivated": CapabilityInstanceState.TERMINATED, "unknown": CapabilityInstanceState.UNKNOWN, } def _map_lifecycle_state(value: str) -> CapabilityInstanceState: try: return _LIFECYCLE_STATE_MAP[value] except KeyError: return CapabilityInstanceState.UNKNOWN def _map_runtime_state(value: str) -> CapabilityInstanceState: try: return _RUNTIME_STATE_MAP[value] except KeyError: return CapabilityInstanceState.UNKNOWN def _to_tfsdk_lifecycle_request( request: CapabilityLifecycleRequest, ) -> tfsdk_models.CapabilityLifecycleRequest: return tfsdk_models.CapabilityLifecycleRequest.model_validate(request.model_dump(mode="json")) def _to_tfsdk_runtime_request( request: CapabilityRuntimeStateRequest, ) -> tfsdk_models.CapabilityRuntimeStateRequest: return tfsdk_models.CapabilityRuntimeStateRequest.model_validate( request.model_dump(mode="json") ) def _capability_kind(value: str, fallback: CapabilityKind) -> CapabilityKind: try: return CapabilityKind(value) except ValueError: return fallback class TfSdkExecutionBridge(TransformationFunctionExecutionPort): """Adapts a TF-SDK concrete adapter to SRM's execution port.""" def __init__(self, adapter: Any) -> None: self._adapter = adapter def activate_capability( self, request: CapabilityLifecycleRequest, ) -> CapabilityLifecycleResult: result = self._adapter.activate(_to_tfsdk_lifecycle_request(request)) return self._map_lifecycle_result(result, request.capability_kind) def update_capability( self, request: CapabilityLifecycleRequest, ) -> CapabilityLifecycleResult: result = self._adapter.update(_to_tfsdk_lifecycle_request(request)) return self._map_lifecycle_result(result, request.capability_kind) def deactivate_capability( self, request: CapabilityLifecycleRequest, ) -> CapabilityLifecycleResult: result = self._adapter.terminate(_to_tfsdk_lifecycle_request(request)) return self._map_lifecycle_result(result, request.capability_kind) def query_capability( self, request: CapabilityQueryRequest, ) -> CapabilityQueryResult: query = getattr(self._adapter, "query", None) if query is None or not callable(query): raise UnsupportedAction( error_code="unsupported_action", message=f"adapter {type(self._adapter).__name__} does not support query", details={"action": "query"}, ) raise UnsupportedAction( error_code="unsupported_action", message=( f"adapter {type(self._adapter).__name__} exposes query but SRM has no " "TF-SDK query result mapping yet" ), details={"action": "query"}, ) def get_capability_runtime_state( self, request: CapabilityRuntimeStateRequest, ) -> CapabilityRuntimeState: result = self._adapter.read_runtime_state(_to_tfsdk_runtime_request(request)) return self._map_runtime_state_result(result, request.capability_kind) def _map_lifecycle_result( self, result: tfsdk_models.CapabilityLifecycleResult, fallback_kind: CapabilityKind, ) -> CapabilityLifecycleResult: payload = result.model_dump(mode="json") state = payload.pop("state") kind = payload.pop("capability_kind") endpoints = payload.pop("endpoints") or [] details = payload.pop("details") or {} return CapabilityLifecycleResult( **payload, capability_kind=_capability_kind(kind, fallback_kind), state=_map_lifecycle_state(state), endpoints=endpoints, details=details, ) def _map_runtime_state_result( self, result: tfsdk_models.CapabilityRuntimeState, fallback_kind: CapabilityKind, ) -> CapabilityRuntimeState: payload = result.model_dump(mode="json") state = payload.pop("state") kind = payload.pop("capability_kind") endpoints = payload.pop("endpoints") or [] details = payload.pop("details") or {} return CapabilityRuntimeState( **payload, capability_kind=_capability_kind(kind, fallback_kind), state=_map_runtime_state(state), endpoints=endpoints, details=details, ) class OpenOpTfSdkAdapterFactory(TransformationFunctionAdapterFactory): """SRM factory that delegates construction to TF-SDK `build_adapter`.""" def create_adapter( self, kind: str, config: Mapping[str, Any], ) -> TransformationFunctionExecutionPort: try: adapter = build_adapter(kind, dict(config)) except TfSdkUnknownAdapterKind as exc: raise UnknownAdapterKind(kind) from exc return TfSdkExecutionBridge(adapter) src/srm/adapters/transformation_functions/tfsdk_topology.py 0 → 100644 +193 −0 Changes for src/srm/adapters/transformation_functions/tfsdk_topology.py: 193 added lines, 0 removed lines. Original line number Diff line number Diff line """TF-SDK topology discovery bridge for SRM's TopologyDiscoveryPort. Discovery is answered by TF-SDK's TopologyDiscoveryAdapter (BootstrapTopology today). Execution adapters are unrelated (ADR-0055). """ from __future__ import annotations from typing import Any from openop_tfsdk.contract.interfaces import TopologyDiscoveryAdapter from openop_tfsdk.contract.topology import BootstrapTopology from srm.domain.models.catalog import RuntimeKind from srm.domain.models.topology import ( CapabilityKind, CapabilityState, ControlPathBindingState, DomainKind, DomainState, ZoneKind, ZoneState, ) from srm.domain.ports.transformation_functions import ( TopologyDiscoveryPort, TransformationFunctionCapability, TransformationFunctionControlPathBinding, TransformationFunctionDomain, TransformationFunctionZone, ) # TF-SDK zone state uses "offline"; SRM ZoneState uses "inactive". _ZONE_STATE_MAP: dict[str, ZoneState] = { "active": ZoneState.ACTIVE, "offline": ZoneState.INACTIVE, "inactive": ZoneState.INACTIVE, "unknown": ZoneState.UNKNOWN, } def _enum_or_default[T](enum_type: type[T], value: str | None, default: T) -> T: if value is None: return default try: return enum_type(value) # type: ignore[call-arg] except ValueError: return default def _zone_state(value: str | None) -> ZoneState: if value is None: return ZoneState.UNKNOWN return _ZONE_STATE_MAP.get(value, ZoneState.UNKNOWN) def _capability_kind(value: str) -> CapabilityKind | None: try: return CapabilityKind(value) except ValueError: return None def _runtime_kinds(values: list[Any] | None) -> list[RuntimeKind]: kinds: list[RuntimeKind] = [] for value in values or []: raw = value.value if hasattr(value, "value") else str(value) try: kinds.append(RuntimeKind(raw)) except ValueError: continue return kinds def _supported_actions(values: list[Any] | None) -> list[str]: actions: list[str] = [] for value in values or []: actions.append(value.value if hasattr(value, "value") else str(value)) return actions def _map_zone(zone: Any) -> TransformationFunctionZone: payload = zone.model_dump(mode="json") return TransformationFunctionZone( ref=payload["ref"], name=payload["name"], kind=_enum_or_default(ZoneKind, payload.get("kind"), ZoneKind.CUSTOM), state=_zone_state(payload.get("state")), location=payload.get("location") or {}, jurisdiction=payload.get("jurisdiction") or {}, legal_entity=payload.get("legal_entity"), federates_zone_refs=payload.get("federates_zone_refs") or [], metadata=payload.get("metadata") or {}, ) def _map_domain(domain: Any) -> TransformationFunctionDomain: payload = domain.model_dump(mode="json") return TransformationFunctionDomain( ref=payload["ref"], name=payload["name"], kind=_enum_or_default(DomainKind, payload.get("kind"), DomainKind.CUSTOM), domain_type=payload.get("domain_type"), adapter_type=payload.get("adapter_type"), state=_enum_or_default(DomainState, payload.get("state"), DomainState.UNKNOWN), federation_role=payload.get("federation_role"), federates_domain_refs=payload.get("federates_domain_refs") or [], details=payload.get("details") or {}, ) def _map_capability(capability: Any) -> TransformationFunctionCapability | None: payload = capability.model_dump(mode="json") kind = _capability_kind(payload["kind"]) if kind is None: return None return TransformationFunctionCapability( ref=payload["ref"], name=payload["name"], kind=kind, state=_enum_or_default(CapabilityState, payload.get("state"), CapabilityState.UNKNOWN), metadata=payload.get("metadata") or {}, ) def _map_binding(binding: Any) -> TransformationFunctionControlPathBinding: payload = binding.model_dump(mode="json") return TransformationFunctionControlPathBinding( ref=payload["ref"], control_path_ref=payload["control_path_ref"], supported_runtime_kinds=_runtime_kinds(payload.get("supported_runtime_kinds")), supported_actions=_supported_actions(payload.get("supported_actions")), priority=payload.get("priority", 100), is_default=payload.get("is_default", False), state=_enum_or_default( ControlPathBindingState, payload.get("state"), ControlPathBindingState.UNKNOWN, ), metadata=payload.get("metadata") or {}, ) class TfSdkTopologyDiscoveryBridge(TopologyDiscoveryPort): """Adapts a TF-SDK TopologyDiscoveryAdapter to SRM's TopologyDiscoveryPort.""" def __init__(self, adapter: TopologyDiscoveryAdapter) -> None: self._adapter = adapter def get_zones(self, kind: ZoneKind | None = None) -> list[TransformationFunctionZone]: kind_filter = kind.value if kind is not None else None return [_map_zone(zone) for zone in self._adapter.get_zones(kind=kind_filter)] def get_domains( self, zone_ref: str | None = None, kind: DomainKind | None = None, ) -> list[TransformationFunctionDomain]: kind_filter = kind.value if kind is not None else None return [ _map_domain(domain) for domain in self._adapter.get_domains(zone_ref=zone_ref, kind=kind_filter) ] def get_capabilities( self, domain_ref: str | None = None, kind: CapabilityKind | None = None, ) -> list[TransformationFunctionCapability]: kind_filter = kind.value if kind is not None else None mapped: list[TransformationFunctionCapability] = [] for capability in self._adapter.get_capabilities(domain_ref=domain_ref, kind=kind_filter): converted = _map_capability(capability) if converted is None: continue if kind is not None and converted.kind != kind: continue mapped.append(converted) return mapped def get_control_path_bindings( self, capability_ref: str | None = None, ) -> list[TransformationFunctionControlPathBinding]: return [ _map_binding(binding) for binding in self._adapter.get_control_path_bindings(capability_ref=capability_ref) ] def build_topology_discovery(bootstrap_path: str | None) -> TopologyDiscoveryPort | None: if not bootstrap_path: return None return TfSdkTopologyDiscoveryBridge(BootstrapTopology.from_file(bootstrap_path)) src/srm/app_state.py +2 −0 Changes for src/srm/app_state.py: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from srm.adapters.databus.nats_publisher import NatsPublisher from srm.adapters.transformation_functions.registry import ConfiguredControlPathRegistry from srm.api.databus.nats_subscriber import NatsSubscriber from srm.domain.ports.federation_manager.ports import FederationManagerPort from srm.domain.ports.transformation_functions import TopologyDiscoveryPort class AppState(Protocol): Loading @@ -15,5 +16,6 @@ class AppState(Protocol): databus_connection_manager: NatsConnectionManager databus_subscribers: list[NatsSubscriber] control_path_registry: ConfiguredControlPathRegistry topology_discovery: TopologyDiscoveryPort | None publisher: NatsPublisher fm_client: FederationManagerPort src/srm/application/use_cases/deploy_service.py +1 −1 Changes for src/srm/application/use_cases/deploy_service.py: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -428,7 +428,7 @@ class DeployServiceUseCase: deploy_material: list[tuple[ServiceCapabilityRequirement, RuntimeKind]], ) -> None: # TODO: TF-SDK CapabilityExecutionAdapter.activate_capability(...) call using # capability_kind="deploy_workload" and placement.control_path_ref. # capability_kind="workload" and placement.control_path_ref. requirements_by_id = {requirement.id: requirement for requirement, _ in deploy_material} for requirement_placement in target_placement.requirements: requirement = requirements_by_id[requirement_placement.requirement_id] Loading Loading
pyproject.toml +4 −0 Changes for pyproject.toml: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ dependencies = [ "sqlalchemy>=2.0.48", "asyncpg>=0.31.0", "nats-py>=2.10.0", "openop-tfsdk", ] [project.optional-dependencies] Loading @@ -37,6 +38,9 @@ dev = [ "ruff>=0.15.6", ] [tool.uv.sources] openop-tfsdk = { path = "../tf-sdk", editable = true } [tool.ruff] line-length = 100 target-version = "py312" Loading
src/srm/adapters/transformation_functions/tfsdk_execution.py 0 → 100644 +188 −0 Changes for src/srm/adapters/transformation_functions/tfsdk_execution.py: 188 added lines, 0 removed lines. Original line number Diff line number Diff line """TF-SDK execution adapter factory and SRM execution-port bridge. TF-SDK owns construction by adapter kind (`build_adapter`). SRM owns the `control_path_ref` → instance map. This module bridges the short TF-SDK action vocabulary to SRM's longer execution-port method names. """ from __future__ import annotations from collections.abc import Mapping from typing import Any from openop_tfsdk.contract import execution_models as tfsdk_models from openop_tfsdk.contract.adapters import build_adapter from openop_tfsdk.contract.errors import UnknownAdapterKind as TfSdkUnknownAdapterKind from srm.domain.models.runtime_inventory import CapabilityInstanceState from srm.domain.models.topology import CapabilityKind from srm.domain.ports.transformation_functions import ( CapabilityLifecycleRequest, CapabilityLifecycleResult, CapabilityQueryRequest, CapabilityQueryResult, CapabilityRuntimeState, CapabilityRuntimeStateRequest, TransformationFunctionAdapterFactory, TransformationFunctionExecutionPort, UnknownAdapterKind, UnsupportedAction, ) _LIFECYCLE_STATE_MAP: dict[str, CapabilityInstanceState] = { "provisioning": CapabilityInstanceState.CREATING, "active": CapabilityInstanceState.ACTIVE, "updating": CapabilityInstanceState.UPDATING, "failed": CapabilityInstanceState.FAILED, "deactivating": CapabilityInstanceState.TERMINATING, "deactivated": CapabilityInstanceState.TERMINATED, } _RUNTIME_STATE_MAP: dict[str, CapabilityInstanceState] = { "active": CapabilityInstanceState.ACTIVE, "degraded": CapabilityInstanceState.DEGRADED, "failed": CapabilityInstanceState.FAILED, "deactivated": CapabilityInstanceState.TERMINATED, "unknown": CapabilityInstanceState.UNKNOWN, } def _map_lifecycle_state(value: str) -> CapabilityInstanceState: try: return _LIFECYCLE_STATE_MAP[value] except KeyError: return CapabilityInstanceState.UNKNOWN def _map_runtime_state(value: str) -> CapabilityInstanceState: try: return _RUNTIME_STATE_MAP[value] except KeyError: return CapabilityInstanceState.UNKNOWN def _to_tfsdk_lifecycle_request( request: CapabilityLifecycleRequest, ) -> tfsdk_models.CapabilityLifecycleRequest: return tfsdk_models.CapabilityLifecycleRequest.model_validate(request.model_dump(mode="json")) def _to_tfsdk_runtime_request( request: CapabilityRuntimeStateRequest, ) -> tfsdk_models.CapabilityRuntimeStateRequest: return tfsdk_models.CapabilityRuntimeStateRequest.model_validate( request.model_dump(mode="json") ) def _capability_kind(value: str, fallback: CapabilityKind) -> CapabilityKind: try: return CapabilityKind(value) except ValueError: return fallback class TfSdkExecutionBridge(TransformationFunctionExecutionPort): """Adapts a TF-SDK concrete adapter to SRM's execution port.""" def __init__(self, adapter: Any) -> None: self._adapter = adapter def activate_capability( self, request: CapabilityLifecycleRequest, ) -> CapabilityLifecycleResult: result = self._adapter.activate(_to_tfsdk_lifecycle_request(request)) return self._map_lifecycle_result(result, request.capability_kind) def update_capability( self, request: CapabilityLifecycleRequest, ) -> CapabilityLifecycleResult: result = self._adapter.update(_to_tfsdk_lifecycle_request(request)) return self._map_lifecycle_result(result, request.capability_kind) def deactivate_capability( self, request: CapabilityLifecycleRequest, ) -> CapabilityLifecycleResult: result = self._adapter.terminate(_to_tfsdk_lifecycle_request(request)) return self._map_lifecycle_result(result, request.capability_kind) def query_capability( self, request: CapabilityQueryRequest, ) -> CapabilityQueryResult: query = getattr(self._adapter, "query", None) if query is None or not callable(query): raise UnsupportedAction( error_code="unsupported_action", message=f"adapter {type(self._adapter).__name__} does not support query", details={"action": "query"}, ) raise UnsupportedAction( error_code="unsupported_action", message=( f"adapter {type(self._adapter).__name__} exposes query but SRM has no " "TF-SDK query result mapping yet" ), details={"action": "query"}, ) def get_capability_runtime_state( self, request: CapabilityRuntimeStateRequest, ) -> CapabilityRuntimeState: result = self._adapter.read_runtime_state(_to_tfsdk_runtime_request(request)) return self._map_runtime_state_result(result, request.capability_kind) def _map_lifecycle_result( self, result: tfsdk_models.CapabilityLifecycleResult, fallback_kind: CapabilityKind, ) -> CapabilityLifecycleResult: payload = result.model_dump(mode="json") state = payload.pop("state") kind = payload.pop("capability_kind") endpoints = payload.pop("endpoints") or [] details = payload.pop("details") or {} return CapabilityLifecycleResult( **payload, capability_kind=_capability_kind(kind, fallback_kind), state=_map_lifecycle_state(state), endpoints=endpoints, details=details, ) def _map_runtime_state_result( self, result: tfsdk_models.CapabilityRuntimeState, fallback_kind: CapabilityKind, ) -> CapabilityRuntimeState: payload = result.model_dump(mode="json") state = payload.pop("state") kind = payload.pop("capability_kind") endpoints = payload.pop("endpoints") or [] details = payload.pop("details") or {} return CapabilityRuntimeState( **payload, capability_kind=_capability_kind(kind, fallback_kind), state=_map_runtime_state(state), endpoints=endpoints, details=details, ) class OpenOpTfSdkAdapterFactory(TransformationFunctionAdapterFactory): """SRM factory that delegates construction to TF-SDK `build_adapter`.""" def create_adapter( self, kind: str, config: Mapping[str, Any], ) -> TransformationFunctionExecutionPort: try: adapter = build_adapter(kind, dict(config)) except TfSdkUnknownAdapterKind as exc: raise UnknownAdapterKind(kind) from exc return TfSdkExecutionBridge(adapter)
src/srm/adapters/transformation_functions/tfsdk_topology.py 0 → 100644 +193 −0 Changes for src/srm/adapters/transformation_functions/tfsdk_topology.py: 193 added lines, 0 removed lines. Original line number Diff line number Diff line """TF-SDK topology discovery bridge for SRM's TopologyDiscoveryPort. Discovery is answered by TF-SDK's TopologyDiscoveryAdapter (BootstrapTopology today). Execution adapters are unrelated (ADR-0055). """ from __future__ import annotations from typing import Any from openop_tfsdk.contract.interfaces import TopologyDiscoveryAdapter from openop_tfsdk.contract.topology import BootstrapTopology from srm.domain.models.catalog import RuntimeKind from srm.domain.models.topology import ( CapabilityKind, CapabilityState, ControlPathBindingState, DomainKind, DomainState, ZoneKind, ZoneState, ) from srm.domain.ports.transformation_functions import ( TopologyDiscoveryPort, TransformationFunctionCapability, TransformationFunctionControlPathBinding, TransformationFunctionDomain, TransformationFunctionZone, ) # TF-SDK zone state uses "offline"; SRM ZoneState uses "inactive". _ZONE_STATE_MAP: dict[str, ZoneState] = { "active": ZoneState.ACTIVE, "offline": ZoneState.INACTIVE, "inactive": ZoneState.INACTIVE, "unknown": ZoneState.UNKNOWN, } def _enum_or_default[T](enum_type: type[T], value: str | None, default: T) -> T: if value is None: return default try: return enum_type(value) # type: ignore[call-arg] except ValueError: return default def _zone_state(value: str | None) -> ZoneState: if value is None: return ZoneState.UNKNOWN return _ZONE_STATE_MAP.get(value, ZoneState.UNKNOWN) def _capability_kind(value: str) -> CapabilityKind | None: try: return CapabilityKind(value) except ValueError: return None def _runtime_kinds(values: list[Any] | None) -> list[RuntimeKind]: kinds: list[RuntimeKind] = [] for value in values or []: raw = value.value if hasattr(value, "value") else str(value) try: kinds.append(RuntimeKind(raw)) except ValueError: continue return kinds def _supported_actions(values: list[Any] | None) -> list[str]: actions: list[str] = [] for value in values or []: actions.append(value.value if hasattr(value, "value") else str(value)) return actions def _map_zone(zone: Any) -> TransformationFunctionZone: payload = zone.model_dump(mode="json") return TransformationFunctionZone( ref=payload["ref"], name=payload["name"], kind=_enum_or_default(ZoneKind, payload.get("kind"), ZoneKind.CUSTOM), state=_zone_state(payload.get("state")), location=payload.get("location") or {}, jurisdiction=payload.get("jurisdiction") or {}, legal_entity=payload.get("legal_entity"), federates_zone_refs=payload.get("federates_zone_refs") or [], metadata=payload.get("metadata") or {}, ) def _map_domain(domain: Any) -> TransformationFunctionDomain: payload = domain.model_dump(mode="json") return TransformationFunctionDomain( ref=payload["ref"], name=payload["name"], kind=_enum_or_default(DomainKind, payload.get("kind"), DomainKind.CUSTOM), domain_type=payload.get("domain_type"), adapter_type=payload.get("adapter_type"), state=_enum_or_default(DomainState, payload.get("state"), DomainState.UNKNOWN), federation_role=payload.get("federation_role"), federates_domain_refs=payload.get("federates_domain_refs") or [], details=payload.get("details") or {}, ) def _map_capability(capability: Any) -> TransformationFunctionCapability | None: payload = capability.model_dump(mode="json") kind = _capability_kind(payload["kind"]) if kind is None: return None return TransformationFunctionCapability( ref=payload["ref"], name=payload["name"], kind=kind, state=_enum_or_default(CapabilityState, payload.get("state"), CapabilityState.UNKNOWN), metadata=payload.get("metadata") or {}, ) def _map_binding(binding: Any) -> TransformationFunctionControlPathBinding: payload = binding.model_dump(mode="json") return TransformationFunctionControlPathBinding( ref=payload["ref"], control_path_ref=payload["control_path_ref"], supported_runtime_kinds=_runtime_kinds(payload.get("supported_runtime_kinds")), supported_actions=_supported_actions(payload.get("supported_actions")), priority=payload.get("priority", 100), is_default=payload.get("is_default", False), state=_enum_or_default( ControlPathBindingState, payload.get("state"), ControlPathBindingState.UNKNOWN, ), metadata=payload.get("metadata") or {}, ) class TfSdkTopologyDiscoveryBridge(TopologyDiscoveryPort): """Adapts a TF-SDK TopologyDiscoveryAdapter to SRM's TopologyDiscoveryPort.""" def __init__(self, adapter: TopologyDiscoveryAdapter) -> None: self._adapter = adapter def get_zones(self, kind: ZoneKind | None = None) -> list[TransformationFunctionZone]: kind_filter = kind.value if kind is not None else None return [_map_zone(zone) for zone in self._adapter.get_zones(kind=kind_filter)] def get_domains( self, zone_ref: str | None = None, kind: DomainKind | None = None, ) -> list[TransformationFunctionDomain]: kind_filter = kind.value if kind is not None else None return [ _map_domain(domain) for domain in self._adapter.get_domains(zone_ref=zone_ref, kind=kind_filter) ] def get_capabilities( self, domain_ref: str | None = None, kind: CapabilityKind | None = None, ) -> list[TransformationFunctionCapability]: kind_filter = kind.value if kind is not None else None mapped: list[TransformationFunctionCapability] = [] for capability in self._adapter.get_capabilities(domain_ref=domain_ref, kind=kind_filter): converted = _map_capability(capability) if converted is None: continue if kind is not None and converted.kind != kind: continue mapped.append(converted) return mapped def get_control_path_bindings( self, capability_ref: str | None = None, ) -> list[TransformationFunctionControlPathBinding]: return [ _map_binding(binding) for binding in self._adapter.get_control_path_bindings(capability_ref=capability_ref) ] def build_topology_discovery(bootstrap_path: str | None) -> TopologyDiscoveryPort | None: if not bootstrap_path: return None return TfSdkTopologyDiscoveryBridge(BootstrapTopology.from_file(bootstrap_path))
src/srm/app_state.py +2 −0 Changes for src/srm/app_state.py: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from srm.adapters.databus.nats_publisher import NatsPublisher from srm.adapters.transformation_functions.registry import ConfiguredControlPathRegistry from srm.api.databus.nats_subscriber import NatsSubscriber from srm.domain.ports.federation_manager.ports import FederationManagerPort from srm.domain.ports.transformation_functions import TopologyDiscoveryPort class AppState(Protocol): Loading @@ -15,5 +16,6 @@ class AppState(Protocol): databus_connection_manager: NatsConnectionManager databus_subscribers: list[NatsSubscriber] control_path_registry: ConfiguredControlPathRegistry topology_discovery: TopologyDiscoveryPort | None publisher: NatsPublisher fm_client: FederationManagerPort
src/srm/application/use_cases/deploy_service.py +1 −1 Changes for src/srm/application/use_cases/deploy_service.py: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -428,7 +428,7 @@ class DeployServiceUseCase: deploy_material: list[tuple[ServiceCapabilityRequirement, RuntimeKind]], ) -> None: # TODO: TF-SDK CapabilityExecutionAdapter.activate_capability(...) call using # capability_kind="deploy_workload" and placement.control_path_ref. # capability_kind="workload" and placement.control_path_ref. requirements_by_id = {requirement.id: requirement for requirement, _ in deploy_material} for requirement_placement in target_placement.requirements: requirement = requirements_by_id[requirement_placement.requirement_id] Loading