Loading .gitignore +1 −0 Changes for .gitignore: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ wheels/ # AI software tools .claude CLAUDE.md .agents .tox/ htmlcov/ Loading src/srm/adapters/database/mappers.py +3 −3 Changes for src/srm/adapters/database/mappers.py: 3 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -295,7 +295,7 @@ class ServiceCapabilityRequirementMapper: domain_kind=domain.domain_kind, is_required=domain.is_required, selector=domain.selector, parameters=domain.parameters.model_dump(mode="python"), parameters=domain.parameters.model_dump(mode="json"), policy=domain.policy, capability_requirement_metadata=domain.metadata, created_at=domain.created_at, Loading Loading @@ -436,8 +436,8 @@ class CapabilityInstanceMapper: state=domain.state, external_id=domain.external_id, external_ref=domain.external_ref, parameters_snapshot=domain.parameters_snapshot.model_dump(mode="python"), result_summary=domain.result_summary.model_dump(mode="python"), parameters_snapshot=domain.parameters_snapshot.model_dump(mode="json"), result_summary=domain.result_summary.model_dump(mode="json"), failure_detail=domain.failure_detail, capability_instance_metadata=domain.metadata, app_provider_id=domain.app_provider_id, Loading src/srm/adapters/transformation_functions/registry.py 0 → 100644 +46 −0 Changes for src/srm/adapters/transformation_functions/registry.py: 46 added lines, 0 removed lines. Original line number Diff line number Diff line from collections.abc import Mapping from srm.config import ControlPathSettings from srm.domain.ports.transformation_functions import ( ControlPathRegistry, TransformationFunctionAdapterFactory, TransformationFunctionExecutionPort, UnknownControlPathRef, ) class NoAdapterFactoryInstalled(RuntimeError): pass class ConfiguredControlPathRegistry(ControlPathRegistry): def __init__(self, adapters: Mapping[str, TransformationFunctionExecutionPort]) -> None: self._adapters = dict(adapters) def get_adapter(self, control_path_ref: str) -> TransformationFunctionExecutionPort: try: return self._adapters[control_path_ref] except KeyError as exc: raise UnknownControlPathRef(control_path_ref) from exc def control_path_refs(self) -> list[str]: return sorted(self._adapters) def build_control_path_registry( settings: ControlPathSettings, factory: TransformationFunctionAdapterFactory | None, ) -> ConfiguredControlPathRegistry: if not settings.entries: return ConfiguredControlPathRegistry({}) if factory is None: raise NoAdapterFactoryInstalled( "control paths are configured but no TF-SDK adapter factory is installed: " + ", ".join(entry.control_path_ref for entry in settings.entries) ) return ConfiguredControlPathRegistry( { entry.control_path_ref: factory.create_adapter(entry.adapter, entry.config) for entry in settings.entries } ) src/srm/api/databus/dependencies.py +51 −0 Changes for src/srm/api/databus/dependencies.py: 51 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -14,10 +14,21 @@ from srm.adapters.database.repos.topology import SqlZoneRepository from srm.adapters.databus.nats_connection_manager import NatsConnectionManager from srm.adapters.databus.nats_publisher import NatsPublisher from srm.application.command_handlers.deploy_service import DeployServiceCommandCoordinator from srm.application.command_handlers.network_capability_activate import ( NetworkCapabilityActivateCommandCoordinator, ) from srm.application.command_handlers.terminate_service import TerminateServiceCommandCoordinator from srm.application.services.capability_placement import CapabilityPlacementPlanner from srm.application.services.device_targeted_control_path import ( DeviceTargetedControlPathResolver, ) from srm.application.use_cases.deploy_service import DeployServiceUseCase from srm.application.use_cases.network_capability_activate import ( NetworkCapabilityActivateUseCase, ) from srm.application.use_cases.terminate_service import TerminateServiceUseCase from srm.domain.ports.databus.publisher import DataBusPublisher from srm.domain.ports.transformation_functions import ControlPathRegistry def get_deploy_service_use_case( Loading Loading @@ -54,6 +65,46 @@ def get_deploy_service_command_coordinator( ) def build_network_capability_activate_use_case( session: AsyncSession, publisher: DataBusPublisher, control_paths: ControlPathRegistry, ) -> NetworkCapabilityActivateUseCase: zones = SqlZoneRepository(session) return NetworkCapabilityActivateUseCase( service_specifications=SqlServiceSpecificationRepository(session), service_capability_requirements=SqlServiceCapabilityRequirementRepository(session), service_orders=SqlServiceOrderRepository(session), service_instances=SqlServiceInstanceRepository(session), capability_instances=SqlCapabilityInstanceRepository(session), zones=zones, publisher=publisher, resolver=DeviceTargetedControlPathResolver( CapabilityPlacementPlanner(zones), control_paths, ), control_paths=control_paths, ) def get_network_capability_activate_command_coordinator( session_maker: async_sessionmaker[AsyncSession], connection_manager: NatsConnectionManager, control_paths: ControlPathRegistry, ) -> NetworkCapabilityActivateCommandCoordinator: def use_case_factory( session: AsyncSession, publisher: DataBusPublisher, ) -> NetworkCapabilityActivateUseCase: return build_network_capability_activate_use_case(session, publisher, control_paths) return NetworkCapabilityActivateCommandCoordinator( session_maker=session_maker, use_case_factory=use_case_factory, publisher=NatsPublisher(connection_manager), ) def get_terminate_service_use_case( session: AsyncSession, connection_manager: NatsConnectionManager, Loading src/srm/api/databus/nats_subscriber.py +10 −1 Changes for src/srm/api/databus/nats_subscriber.py: 10 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -9,9 +9,11 @@ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from srm.adapters.databus.nats_connection_manager import NatsConnectionManager from srm.api.databus.dependencies import ( get_deploy_service_command_coordinator, get_network_capability_activate_command_coordinator, get_terminate_service_command_coordinator, ) from srm.api.databus.schemas import AnswerableCommandV1, InboundMessage from srm.domain.ports.transformation_functions import ControlPathRegistry logger: structlog.BoundLogger = structlog.get_logger(__name__) Loading @@ -30,13 +32,13 @@ async def _noop_callback(envelope: AnswerableCommandV1) -> None: COMMAND_HANDLERS: dict[str, MessageHandler] = { "command.srm.service.scale": _noop_callback, "command.srm.network.capability.activate": _noop_callback, "command.srm.network.capability.update": _noop_callback, "command.srm.network.capability.deactivate": _noop_callback, } COMMAND_SUBJECTS = ( "command.srm.service.deploy", "command.srm.network.capability.activate", "command.srm.service.terminate", *COMMAND_HANDLERS.keys(), ) Loading @@ -45,6 +47,7 @@ COMMAND_SUBJECTS = ( async def subscribe_to_subjects( connection_manager: NatsConnectionManager, session_maker: async_sessionmaker[AsyncSession], control_paths: ControlPathRegistry, ) -> list["NatsSubscriber"]: deploy_coordinator = get_deploy_service_command_coordinator( session_maker, Loading @@ -54,9 +57,15 @@ async def subscribe_to_subjects( session_maker, connection_manager, ) network_activate_coordinator = get_network_capability_activate_command_coordinator( session_maker, connection_manager, control_paths, ) command_handlers = { "command.srm.service.deploy": deploy_coordinator.handle, "command.srm.network.capability.activate": network_activate_coordinator.handle, "command.srm.service.terminate": terminate_coordinator.handle, **COMMAND_HANDLERS, } Loading Loading
.gitignore +1 −0 Changes for .gitignore: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ wheels/ # AI software tools .claude CLAUDE.md .agents .tox/ htmlcov/ Loading
src/srm/adapters/database/mappers.py +3 −3 Changes for src/srm/adapters/database/mappers.py: 3 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -295,7 +295,7 @@ class ServiceCapabilityRequirementMapper: domain_kind=domain.domain_kind, is_required=domain.is_required, selector=domain.selector, parameters=domain.parameters.model_dump(mode="python"), parameters=domain.parameters.model_dump(mode="json"), policy=domain.policy, capability_requirement_metadata=domain.metadata, created_at=domain.created_at, Loading Loading @@ -436,8 +436,8 @@ class CapabilityInstanceMapper: state=domain.state, external_id=domain.external_id, external_ref=domain.external_ref, parameters_snapshot=domain.parameters_snapshot.model_dump(mode="python"), result_summary=domain.result_summary.model_dump(mode="python"), parameters_snapshot=domain.parameters_snapshot.model_dump(mode="json"), result_summary=domain.result_summary.model_dump(mode="json"), failure_detail=domain.failure_detail, capability_instance_metadata=domain.metadata, app_provider_id=domain.app_provider_id, Loading
src/srm/adapters/transformation_functions/registry.py 0 → 100644 +46 −0 Changes for src/srm/adapters/transformation_functions/registry.py: 46 added lines, 0 removed lines. Original line number Diff line number Diff line from collections.abc import Mapping from srm.config import ControlPathSettings from srm.domain.ports.transformation_functions import ( ControlPathRegistry, TransformationFunctionAdapterFactory, TransformationFunctionExecutionPort, UnknownControlPathRef, ) class NoAdapterFactoryInstalled(RuntimeError): pass class ConfiguredControlPathRegistry(ControlPathRegistry): def __init__(self, adapters: Mapping[str, TransformationFunctionExecutionPort]) -> None: self._adapters = dict(adapters) def get_adapter(self, control_path_ref: str) -> TransformationFunctionExecutionPort: try: return self._adapters[control_path_ref] except KeyError as exc: raise UnknownControlPathRef(control_path_ref) from exc def control_path_refs(self) -> list[str]: return sorted(self._adapters) def build_control_path_registry( settings: ControlPathSettings, factory: TransformationFunctionAdapterFactory | None, ) -> ConfiguredControlPathRegistry: if not settings.entries: return ConfiguredControlPathRegistry({}) if factory is None: raise NoAdapterFactoryInstalled( "control paths are configured but no TF-SDK adapter factory is installed: " + ", ".join(entry.control_path_ref for entry in settings.entries) ) return ConfiguredControlPathRegistry( { entry.control_path_ref: factory.create_adapter(entry.adapter, entry.config) for entry in settings.entries } )
src/srm/api/databus/dependencies.py +51 −0 Changes for src/srm/api/databus/dependencies.py: 51 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -14,10 +14,21 @@ from srm.adapters.database.repos.topology import SqlZoneRepository from srm.adapters.databus.nats_connection_manager import NatsConnectionManager from srm.adapters.databus.nats_publisher import NatsPublisher from srm.application.command_handlers.deploy_service import DeployServiceCommandCoordinator from srm.application.command_handlers.network_capability_activate import ( NetworkCapabilityActivateCommandCoordinator, ) from srm.application.command_handlers.terminate_service import TerminateServiceCommandCoordinator from srm.application.services.capability_placement import CapabilityPlacementPlanner from srm.application.services.device_targeted_control_path import ( DeviceTargetedControlPathResolver, ) from srm.application.use_cases.deploy_service import DeployServiceUseCase from srm.application.use_cases.network_capability_activate import ( NetworkCapabilityActivateUseCase, ) from srm.application.use_cases.terminate_service import TerminateServiceUseCase from srm.domain.ports.databus.publisher import DataBusPublisher from srm.domain.ports.transformation_functions import ControlPathRegistry def get_deploy_service_use_case( Loading Loading @@ -54,6 +65,46 @@ def get_deploy_service_command_coordinator( ) def build_network_capability_activate_use_case( session: AsyncSession, publisher: DataBusPublisher, control_paths: ControlPathRegistry, ) -> NetworkCapabilityActivateUseCase: zones = SqlZoneRepository(session) return NetworkCapabilityActivateUseCase( service_specifications=SqlServiceSpecificationRepository(session), service_capability_requirements=SqlServiceCapabilityRequirementRepository(session), service_orders=SqlServiceOrderRepository(session), service_instances=SqlServiceInstanceRepository(session), capability_instances=SqlCapabilityInstanceRepository(session), zones=zones, publisher=publisher, resolver=DeviceTargetedControlPathResolver( CapabilityPlacementPlanner(zones), control_paths, ), control_paths=control_paths, ) def get_network_capability_activate_command_coordinator( session_maker: async_sessionmaker[AsyncSession], connection_manager: NatsConnectionManager, control_paths: ControlPathRegistry, ) -> NetworkCapabilityActivateCommandCoordinator: def use_case_factory( session: AsyncSession, publisher: DataBusPublisher, ) -> NetworkCapabilityActivateUseCase: return build_network_capability_activate_use_case(session, publisher, control_paths) return NetworkCapabilityActivateCommandCoordinator( session_maker=session_maker, use_case_factory=use_case_factory, publisher=NatsPublisher(connection_manager), ) def get_terminate_service_use_case( session: AsyncSession, connection_manager: NatsConnectionManager, Loading
src/srm/api/databus/nats_subscriber.py +10 −1 Changes for src/srm/api/databus/nats_subscriber.py: 10 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -9,9 +9,11 @@ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from srm.adapters.databus.nats_connection_manager import NatsConnectionManager from srm.api.databus.dependencies import ( get_deploy_service_command_coordinator, get_network_capability_activate_command_coordinator, get_terminate_service_command_coordinator, ) from srm.api.databus.schemas import AnswerableCommandV1, InboundMessage from srm.domain.ports.transformation_functions import ControlPathRegistry logger: structlog.BoundLogger = structlog.get_logger(__name__) Loading @@ -30,13 +32,13 @@ async def _noop_callback(envelope: AnswerableCommandV1) -> None: COMMAND_HANDLERS: dict[str, MessageHandler] = { "command.srm.service.scale": _noop_callback, "command.srm.network.capability.activate": _noop_callback, "command.srm.network.capability.update": _noop_callback, "command.srm.network.capability.deactivate": _noop_callback, } COMMAND_SUBJECTS = ( "command.srm.service.deploy", "command.srm.network.capability.activate", "command.srm.service.terminate", *COMMAND_HANDLERS.keys(), ) Loading @@ -45,6 +47,7 @@ COMMAND_SUBJECTS = ( async def subscribe_to_subjects( connection_manager: NatsConnectionManager, session_maker: async_sessionmaker[AsyncSession], control_paths: ControlPathRegistry, ) -> list["NatsSubscriber"]: deploy_coordinator = get_deploy_service_command_coordinator( session_maker, Loading @@ -54,9 +57,15 @@ async def subscribe_to_subjects( session_maker, connection_manager, ) network_activate_coordinator = get_network_capability_activate_command_coordinator( session_maker, connection_manager, control_paths, ) command_handlers = { "command.srm.service.deploy": deploy_coordinator.handle, "command.srm.network.capability.activate": network_activate_coordinator.handle, "command.srm.service.terminate": terminate_coordinator.handle, **COMMAND_HANDLERS, } Loading