omnibase_infra 0.2.1__py3-none-any.whl → 0.2.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omnibase_infra/__init__.py +1 -1
- omnibase_infra/adapters/adapter_onex_tool_execution.py +451 -0
- omnibase_infra/capabilities/__init__.py +15 -0
- omnibase_infra/capabilities/capability_inference_rules.py +211 -0
- omnibase_infra/capabilities/contract_capability_extractor.py +221 -0
- omnibase_infra/capabilities/intent_type_extractor.py +160 -0
- omnibase_infra/cli/commands.py +1 -1
- omnibase_infra/configs/widget_mapping.yaml +176 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +5 -2
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +5 -2
- omnibase_infra/enums/__init__.py +6 -0
- omnibase_infra/enums/enum_handler_error_type.py +10 -0
- omnibase_infra/enums/enum_handler_source_mode.py +72 -0
- omnibase_infra/enums/enum_kafka_acks.py +99 -0
- omnibase_infra/errors/error_compute_registry.py +4 -1
- omnibase_infra/errors/error_event_bus_registry.py +4 -1
- omnibase_infra/errors/error_infra.py +3 -1
- omnibase_infra/errors/error_policy_registry.py +4 -1
- omnibase_infra/event_bus/event_bus_kafka.py +1 -1
- omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +59 -10
- omnibase_infra/handlers/__init__.py +8 -1
- omnibase_infra/handlers/handler_consul.py +7 -1
- omnibase_infra/handlers/handler_db.py +10 -3
- omnibase_infra/handlers/handler_graph.py +10 -5
- omnibase_infra/handlers/handler_http.py +8 -2
- omnibase_infra/handlers/handler_intent.py +387 -0
- omnibase_infra/handlers/handler_mcp.py +745 -63
- omnibase_infra/handlers/handler_vault.py +11 -5
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +4 -3
- omnibase_infra/handlers/mixins/mixin_consul_service.py +2 -1
- omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +7 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +308 -4
- omnibase_infra/handlers/service_discovery/models/model_service_info.py +10 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +3 -2
- omnibase_infra/mixins/mixin_node_introspection.py +42 -7
- omnibase_infra/mixins/mixin_retry_execution.py +1 -1
- omnibase_infra/models/discovery/model_introspection_config.py +11 -0
- omnibase_infra/models/handlers/__init__.py +48 -5
- omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
- omnibase_infra/models/handlers/model_contract_discovery_result.py +6 -4
- omnibase_infra/models/handlers/model_handler_descriptor.py +15 -0
- omnibase_infra/models/handlers/model_handler_source_config.py +220 -0
- omnibase_infra/models/mcp/__init__.py +15 -0
- omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
- omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
- omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
- omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
- omnibase_infra/models/registration/model_node_capabilities.py +11 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +9 -0
- omnibase_infra/models/runtime/model_handler_contract.py +25 -9
- omnibase_infra/models/runtime/model_loaded_handler.py +9 -0
- omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +0 -5
- omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +17 -10
- omnibase_infra/nodes/effects/contract.yaml +0 -5
- omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +7 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +86 -1
- omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +3 -3
- omnibase_infra/nodes/node_registration_orchestrator/plugin.py +1 -1
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +9 -8
- omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +4 -3
- omnibase_infra/nodes/node_registration_orchestrator/wiring.py +14 -13
- omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +0 -5
- omnibase_infra/nodes/node_registration_storage_effect/node.py +4 -1
- omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +47 -26
- omnibase_infra/nodes/node_registry_effect/contract.yaml +0 -5
- omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +2 -1
- omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +28 -20
- omnibase_infra/plugins/examples/plugin_json_normalizer.py +2 -2
- omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +2 -2
- omnibase_infra/plugins/plugin_compute_base.py +16 -2
- omnibase_infra/protocols/__init__.py +2 -0
- omnibase_infra/protocols/protocol_container_aware.py +200 -0
- omnibase_infra/protocols/protocol_event_projector.py +1 -1
- omnibase_infra/runtime/__init__.py +90 -1
- omnibase_infra/runtime/binding_config_resolver.py +102 -37
- omnibase_infra/runtime/constants_notification.py +75 -0
- omnibase_infra/runtime/contract_handler_discovery.py +6 -1
- omnibase_infra/runtime/handler_bootstrap_source.py +507 -0
- omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
- omnibase_infra/runtime/handler_contract_source.py +267 -186
- omnibase_infra/runtime/handler_identity.py +81 -0
- omnibase_infra/runtime/handler_plugin_loader.py +19 -2
- omnibase_infra/runtime/handler_registry.py +11 -3
- omnibase_infra/runtime/handler_source_resolver.py +326 -0
- omnibase_infra/runtime/mixin_semver_cache.py +25 -1
- omnibase_infra/runtime/mixins/__init__.py +7 -0
- omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
- omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +31 -10
- omnibase_infra/runtime/models/__init__.py +24 -0
- omnibase_infra/runtime/models/model_health_check_result.py +2 -1
- omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
- omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
- omnibase_infra/runtime/projector_plugin_loader.py +1 -1
- omnibase_infra/runtime/projector_shell.py +229 -1
- omnibase_infra/runtime/protocol_lifecycle_executor.py +6 -6
- omnibase_infra/runtime/protocols/__init__.py +10 -0
- omnibase_infra/runtime/registry/registry_protocol_binding.py +16 -15
- omnibase_infra/runtime/registry_contract_source.py +693 -0
- omnibase_infra/runtime/registry_policy.py +9 -326
- omnibase_infra/runtime/secret_resolver.py +4 -2
- omnibase_infra/runtime/service_kernel.py +11 -3
- omnibase_infra/runtime/service_message_dispatch_engine.py +4 -2
- omnibase_infra/runtime/service_runtime_host_process.py +589 -106
- omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
- omnibase_infra/runtime/transition_notification_publisher.py +764 -0
- omnibase_infra/runtime/util_container_wiring.py +6 -5
- omnibase_infra/runtime/util_wiring.py +17 -4
- omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
- omnibase_infra/services/__init__.py +21 -0
- omnibase_infra/services/corpus_capture.py +7 -1
- omnibase_infra/services/mcp/__init__.py +31 -0
- omnibase_infra/services/mcp/mcp_server_lifecycle.py +449 -0
- omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
- omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
- omnibase_infra/services/mcp/service_mcp_tool_sync.py +547 -0
- omnibase_infra/services/registry_api/__init__.py +40 -0
- omnibase_infra/services/registry_api/main.py +261 -0
- omnibase_infra/services/registry_api/models/__init__.py +66 -0
- omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
- omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
- omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
- omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
- omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
- omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
- omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
- omnibase_infra/services/registry_api/models/model_warning.py +49 -0
- omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
- omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
- omnibase_infra/services/registry_api/routes.py +371 -0
- omnibase_infra/services/registry_api/service.py +837 -0
- omnibase_infra/services/service_capability_query.py +4 -4
- omnibase_infra/services/service_health.py +3 -2
- omnibase_infra/services/service_timeout_emitter.py +20 -3
- omnibase_infra/services/service_timeout_scanner.py +7 -3
- omnibase_infra/services/session/__init__.py +56 -0
- omnibase_infra/services/session/config_consumer.py +120 -0
- omnibase_infra/services/session/config_store.py +139 -0
- omnibase_infra/services/session/consumer.py +1007 -0
- omnibase_infra/services/session/protocol_session_aggregator.py +117 -0
- omnibase_infra/services/session/store.py +997 -0
- omnibase_infra/utils/__init__.py +19 -0
- omnibase_infra/utils/util_atomic_file.py +261 -0
- omnibase_infra/utils/util_db_transaction.py +239 -0
- omnibase_infra/utils/util_dsn_validation.py +1 -1
- omnibase_infra/utils/util_retry_optimistic.py +281 -0
- omnibase_infra/validation/__init__.py +3 -19
- omnibase_infra/validation/contracts/security.validation.yaml +114 -0
- omnibase_infra/validation/infra_validators.py +35 -24
- omnibase_infra/validation/validation_exemptions.yaml +140 -9
- omnibase_infra/validation/validator_chain_propagation.py +2 -2
- omnibase_infra/validation/validator_runtime_shape.py +1 -1
- omnibase_infra/validation/validator_security.py +473 -370
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/METADATA +3 -3
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/RECORD +161 -98
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/entry_points.txt +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Registry API FastAPI Application.
|
|
4
|
+
|
|
5
|
+
Creates and configures the FastAPI application for the Registry API.
|
|
6
|
+
Provides factory function for flexible instantiation with different
|
|
7
|
+
backend configurations.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
# Create app with container (required)
|
|
11
|
+
from omnibase_core.container import ModelONEXContainer
|
|
12
|
+
|
|
13
|
+
container = ModelONEXContainer()
|
|
14
|
+
app = create_app(container=container, cors_origins=["http://localhost:3000"])
|
|
15
|
+
|
|
16
|
+
# Create app with full backends
|
|
17
|
+
app = create_app(
|
|
18
|
+
container=container,
|
|
19
|
+
projection_reader=reader,
|
|
20
|
+
consul_handler=handler,
|
|
21
|
+
cors_origins=["http://localhost:3000"],
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Run with uvicorn
|
|
25
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
26
|
+
|
|
27
|
+
Related Tickets:
|
|
28
|
+
- OMN-1278: Contract-Driven Dashboard - Registry Discovery
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import logging
|
|
34
|
+
import os
|
|
35
|
+
from collections.abc import AsyncIterator
|
|
36
|
+
from contextlib import asynccontextmanager
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
from typing import TYPE_CHECKING
|
|
39
|
+
|
|
40
|
+
from fastapi import FastAPI
|
|
41
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
42
|
+
|
|
43
|
+
from omnibase_core.container import ModelONEXContainer
|
|
44
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
45
|
+
from omnibase_infra.errors import ModelInfraErrorContext, ProtocolConfigurationError
|
|
46
|
+
from omnibase_infra.services.registry_api.routes import router
|
|
47
|
+
from omnibase_infra.services.registry_api.service import ServiceRegistryDiscovery
|
|
48
|
+
|
|
49
|
+
if TYPE_CHECKING:
|
|
50
|
+
from omnibase_infra.handlers.service_discovery import HandlerServiceDiscoveryConsul
|
|
51
|
+
from omnibase_infra.projectors import ProjectionReaderRegistration
|
|
52
|
+
|
|
53
|
+
logger = logging.getLogger(__name__)
|
|
54
|
+
|
|
55
|
+
# API metadata
|
|
56
|
+
API_TITLE = "ONEX Registry API"
|
|
57
|
+
API_DESCRIPTION = """
|
|
58
|
+
Registry Discovery API for ONEX Dashboard Integration.
|
|
59
|
+
|
|
60
|
+
This API provides access to node registrations and live service instances
|
|
61
|
+
for dashboard consumption. It combines data from:
|
|
62
|
+
|
|
63
|
+
- **PostgreSQL Projections**: Node registration state, capabilities, and metadata
|
|
64
|
+
- **Consul Service Discovery**: Live service instances with health status
|
|
65
|
+
|
|
66
|
+
## Key Features
|
|
67
|
+
|
|
68
|
+
- **Full Dashboard Payload**: Single endpoint for all dashboard data
|
|
69
|
+
- **Partial Success**: Returns data even when one backend fails
|
|
70
|
+
- **Widget Mapping**: Configuration for capability-to-widget rendering
|
|
71
|
+
- **Health Monitoring**: Component-level health status
|
|
72
|
+
|
|
73
|
+
## Related Tickets
|
|
74
|
+
|
|
75
|
+
- OMN-1278: Contract-Driven Dashboard - Registry Discovery
|
|
76
|
+
"""
|
|
77
|
+
API_VERSION = "1.0.0"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@asynccontextmanager
|
|
81
|
+
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
|
82
|
+
"""Application lifespan handler for startup/shutdown.
|
|
83
|
+
|
|
84
|
+
Initializes backend connections on startup and cleans up on shutdown.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
app: FastAPI application instance.
|
|
88
|
+
|
|
89
|
+
Yields:
|
|
90
|
+
None (context manager pattern).
|
|
91
|
+
"""
|
|
92
|
+
logger.info("Registry API starting up")
|
|
93
|
+
|
|
94
|
+
# Log configuration
|
|
95
|
+
service: ServiceRegistryDiscovery | None = getattr(
|
|
96
|
+
app.state, "registry_service", None
|
|
97
|
+
)
|
|
98
|
+
if service is not None:
|
|
99
|
+
logger.info(
|
|
100
|
+
"Registry service configured",
|
|
101
|
+
extra={
|
|
102
|
+
"has_projection_reader": service.has_projection_reader,
|
|
103
|
+
"has_consul_handler": service.has_consul_handler,
|
|
104
|
+
},
|
|
105
|
+
)
|
|
106
|
+
else:
|
|
107
|
+
logger.warning("Registry service not configured - API will return limited data")
|
|
108
|
+
|
|
109
|
+
yield
|
|
110
|
+
|
|
111
|
+
logger.info("Registry API shutting down")
|
|
112
|
+
|
|
113
|
+
# Cleanup Consul handler if we own it
|
|
114
|
+
if service is not None and service.consul_handler is not None:
|
|
115
|
+
try:
|
|
116
|
+
await service.consul_handler.shutdown()
|
|
117
|
+
logger.info("Consul handler shutdown complete")
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logger.exception(
|
|
120
|
+
"Error during Consul handler shutdown",
|
|
121
|
+
extra={"error_type": type(e).__name__},
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def create_app(
|
|
126
|
+
container: ModelONEXContainer,
|
|
127
|
+
projection_reader: ProjectionReaderRegistration | None = None,
|
|
128
|
+
consul_handler: HandlerServiceDiscoveryConsul | None = None,
|
|
129
|
+
widget_mapping_path: Path | None = None,
|
|
130
|
+
cors_origins: list[str] | None = None,
|
|
131
|
+
) -> FastAPI:
|
|
132
|
+
"""Create and configure the Registry API FastAPI application.
|
|
133
|
+
|
|
134
|
+
Factory function that creates a FastAPI app with the specified
|
|
135
|
+
backend configurations. All backends are optional - the API will
|
|
136
|
+
return partial data with warnings when backends are unavailable.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
container: ONEX container for dependency injection. Required for
|
|
140
|
+
ONEX DI pattern compliance.
|
|
141
|
+
projection_reader: Optional projection reader for node registrations.
|
|
142
|
+
consul_handler: Optional Consul handler for live instances.
|
|
143
|
+
widget_mapping_path: Optional path to widget mapping YAML.
|
|
144
|
+
cors_origins: Optional list of allowed CORS origins.
|
|
145
|
+
If not provided, reads from CORS_ORIGINS environment variable.
|
|
146
|
+
Raises ProtocolConfigurationError if neither is configured (fail-fast).
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Configured FastAPI application.
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
ProtocolConfigurationError: If CORS origins not configured via parameter
|
|
153
|
+
or CORS_ORIGINS environment variable.
|
|
154
|
+
|
|
155
|
+
Example:
|
|
156
|
+
>>> from omnibase_infra.services.registry_api import create_app
|
|
157
|
+
>>> from omnibase_core.container import ModelONEXContainer
|
|
158
|
+
>>> container = ModelONEXContainer()
|
|
159
|
+
>>> app = create_app(container=container)
|
|
160
|
+
>>> # Run with: uvicorn module:app --host 0.0.0.0 --port 8000
|
|
161
|
+
"""
|
|
162
|
+
app = FastAPI(
|
|
163
|
+
title=API_TITLE,
|
|
164
|
+
description=API_DESCRIPTION,
|
|
165
|
+
version=API_VERSION,
|
|
166
|
+
lifespan=lifespan,
|
|
167
|
+
docs_url="/docs",
|
|
168
|
+
redoc_url="/redoc",
|
|
169
|
+
openapi_url="/openapi.json",
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Configure CORS - fail-fast if not configured
|
|
173
|
+
if cors_origins is not None:
|
|
174
|
+
origins = cors_origins
|
|
175
|
+
else:
|
|
176
|
+
env_origins = os.environ.get("CORS_ORIGINS")
|
|
177
|
+
if env_origins is None:
|
|
178
|
+
context = ModelInfraErrorContext.with_correlation(
|
|
179
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
180
|
+
operation="configure_cors",
|
|
181
|
+
)
|
|
182
|
+
raise ProtocolConfigurationError(
|
|
183
|
+
"CORS_ORIGINS must be configured. "
|
|
184
|
+
"Set the CORS_ORIGINS environment variable (comma-separated list of allowed origins) "
|
|
185
|
+
"or pass cors_origins parameter to create_app(). "
|
|
186
|
+
"Example: CORS_ORIGINS=http://localhost:3000,https://dashboard.example.com",
|
|
187
|
+
context=context,
|
|
188
|
+
)
|
|
189
|
+
origins = env_origins.split(",")
|
|
190
|
+
|
|
191
|
+
# Warn about wildcard CORS - only when explicitly configured
|
|
192
|
+
if "*" in origins:
|
|
193
|
+
logger.warning(
|
|
194
|
+
"CORS explicitly configured with wildcard origin '*'. "
|
|
195
|
+
"This is acceptable for development but should be restricted in production.",
|
|
196
|
+
extra={"origins": origins},
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
app.add_middleware(
|
|
200
|
+
CORSMiddleware,
|
|
201
|
+
allow_origins=origins,
|
|
202
|
+
allow_credentials=True,
|
|
203
|
+
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
204
|
+
allow_headers=["*"],
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# Create and attach service
|
|
208
|
+
service = ServiceRegistryDiscovery(
|
|
209
|
+
container=container,
|
|
210
|
+
projection_reader=projection_reader,
|
|
211
|
+
consul_handler=consul_handler,
|
|
212
|
+
widget_mapping_path=widget_mapping_path,
|
|
213
|
+
)
|
|
214
|
+
app.state.registry_service = service
|
|
215
|
+
|
|
216
|
+
# Include routes
|
|
217
|
+
app.include_router(router)
|
|
218
|
+
|
|
219
|
+
# Root endpoint
|
|
220
|
+
@app.get("/", include_in_schema=False)
|
|
221
|
+
async def root() -> dict[str, str]:
|
|
222
|
+
"""Root endpoint with API info."""
|
|
223
|
+
return {
|
|
224
|
+
"service": API_TITLE,
|
|
225
|
+
"version": API_VERSION,
|
|
226
|
+
"docs": "/docs",
|
|
227
|
+
"health": "/registry/health",
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
logger.info(
|
|
231
|
+
"Registry API created",
|
|
232
|
+
extra={
|
|
233
|
+
"version": API_VERSION,
|
|
234
|
+
"cors_origins": origins,
|
|
235
|
+
},
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
return app
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# Module-level app instance is not supported since container is required.
|
|
242
|
+
# For production usage, use create_app() with proper configuration:
|
|
243
|
+
#
|
|
244
|
+
# Example:
|
|
245
|
+
# from omnibase_core.container import ModelONEXContainer
|
|
246
|
+
# from omnibase_infra.services.registry_api import create_app
|
|
247
|
+
#
|
|
248
|
+
# container = ModelONEXContainer()
|
|
249
|
+
# app = create_app(
|
|
250
|
+
# container=container,
|
|
251
|
+
# projection_reader=reader,
|
|
252
|
+
# consul_handler=handler,
|
|
253
|
+
# cors_origins=["http://localhost:3000"],
|
|
254
|
+
# )
|
|
255
|
+
# uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
256
|
+
#
|
|
257
|
+
# For uvicorn CLI usage, create a launcher module that instantiates the container.
|
|
258
|
+
app: FastAPI | None = None
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
__all__ = ["app", "create_app"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Registry API Response Models.
|
|
4
|
+
|
|
5
|
+
Pydantic models for the Registry API HTTP responses. These models define
|
|
6
|
+
the JSON shape returned by each endpoint for dashboard consumption.
|
|
7
|
+
|
|
8
|
+
Design Principles:
|
|
9
|
+
- Flat, dashboard-friendly structures (no deep nesting)
|
|
10
|
+
- Explicit field descriptions for API documentation
|
|
11
|
+
- Immutable (frozen) for thread safety
|
|
12
|
+
- Strict validation (extra="forbid")
|
|
13
|
+
|
|
14
|
+
Related Tickets:
|
|
15
|
+
- OMN-1278: Contract-Driven Dashboard - Registry Discovery
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from omnibase_infra.services.registry_api.models.model_capability_widget_mapping import (
|
|
19
|
+
ModelCapabilityWidgetMapping,
|
|
20
|
+
)
|
|
21
|
+
from omnibase_infra.services.registry_api.models.model_pagination_info import (
|
|
22
|
+
ModelPaginationInfo,
|
|
23
|
+
)
|
|
24
|
+
from omnibase_infra.services.registry_api.models.model_registry_discovery_response import (
|
|
25
|
+
ModelRegistryDiscoveryResponse,
|
|
26
|
+
)
|
|
27
|
+
from omnibase_infra.services.registry_api.models.model_registry_health_response import (
|
|
28
|
+
ModelRegistryHealthResponse,
|
|
29
|
+
)
|
|
30
|
+
from omnibase_infra.services.registry_api.models.model_registry_instance_view import (
|
|
31
|
+
ModelRegistryInstanceView,
|
|
32
|
+
)
|
|
33
|
+
from omnibase_infra.services.registry_api.models.model_registry_node_view import (
|
|
34
|
+
ModelRegistryNodeView,
|
|
35
|
+
)
|
|
36
|
+
from omnibase_infra.services.registry_api.models.model_registry_summary import (
|
|
37
|
+
ModelRegistrySummary,
|
|
38
|
+
)
|
|
39
|
+
from omnibase_infra.services.registry_api.models.model_response_list_instances import (
|
|
40
|
+
ModelResponseListInstances,
|
|
41
|
+
)
|
|
42
|
+
from omnibase_infra.services.registry_api.models.model_response_list_nodes import (
|
|
43
|
+
ModelResponseListNodes,
|
|
44
|
+
)
|
|
45
|
+
from omnibase_infra.services.registry_api.models.model_warning import ModelWarning
|
|
46
|
+
from omnibase_infra.services.registry_api.models.model_widget_defaults import (
|
|
47
|
+
ModelWidgetDefaults,
|
|
48
|
+
)
|
|
49
|
+
from omnibase_infra.services.registry_api.models.model_widget_mapping import (
|
|
50
|
+
ModelWidgetMapping,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
"ModelCapabilityWidgetMapping",
|
|
55
|
+
"ModelPaginationInfo",
|
|
56
|
+
"ModelRegistryDiscoveryResponse",
|
|
57
|
+
"ModelRegistryHealthResponse",
|
|
58
|
+
"ModelRegistryInstanceView",
|
|
59
|
+
"ModelRegistryNodeView",
|
|
60
|
+
"ModelRegistrySummary",
|
|
61
|
+
"ModelResponseListInstances",
|
|
62
|
+
"ModelResponseListNodes",
|
|
63
|
+
"ModelWarning",
|
|
64
|
+
"ModelWidgetDefaults",
|
|
65
|
+
"ModelWidgetMapping",
|
|
66
|
+
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Capability widget mapping model for dashboard configuration.
|
|
4
|
+
|
|
5
|
+
Related Tickets:
|
|
6
|
+
- OMN-1278: Contract-Driven Dashboard - Registry Discovery
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
12
|
+
|
|
13
|
+
from omnibase_infra.services.registry_api.models.model_widget_defaults import (
|
|
14
|
+
ModelWidgetDefaults,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelCapabilityWidgetMapping(BaseModel):
|
|
19
|
+
"""Mapping from a capability to its widget configuration.
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
widget_type: Type of widget to render
|
|
23
|
+
defaults: Default widget configuration
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
27
|
+
|
|
28
|
+
widget_type: str = Field(
|
|
29
|
+
...,
|
|
30
|
+
description="Type of widget to render",
|
|
31
|
+
)
|
|
32
|
+
defaults: ModelWidgetDefaults = Field(
|
|
33
|
+
default_factory=ModelWidgetDefaults,
|
|
34
|
+
description="Default widget configuration",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = ["ModelCapabilityWidgetMapping"]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Pagination info model for list endpoints.
|
|
4
|
+
|
|
5
|
+
Related Tickets:
|
|
6
|
+
- OMN-1278: Contract-Driven Dashboard - Registry Discovery
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ModelPaginationInfo(BaseModel):
|
|
15
|
+
"""Pagination information for list endpoints.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
total: Total number of items matching the query
|
|
19
|
+
limit: Maximum items per page
|
|
20
|
+
offset: Current offset (0-based)
|
|
21
|
+
has_more: Whether more items exist beyond current page
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
25
|
+
|
|
26
|
+
total: int = Field(
|
|
27
|
+
...,
|
|
28
|
+
ge=0,
|
|
29
|
+
description="Total number of items",
|
|
30
|
+
)
|
|
31
|
+
limit: int = Field(
|
|
32
|
+
...,
|
|
33
|
+
ge=1,
|
|
34
|
+
le=1000,
|
|
35
|
+
description="Maximum items per page",
|
|
36
|
+
)
|
|
37
|
+
offset: int = Field(
|
|
38
|
+
...,
|
|
39
|
+
ge=0,
|
|
40
|
+
description="Current offset (0-based)",
|
|
41
|
+
)
|
|
42
|
+
has_more: bool = Field(
|
|
43
|
+
...,
|
|
44
|
+
description="Whether more items exist",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
__all__ = ["ModelPaginationInfo"]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Registry discovery response model for dashboard payload.
|
|
4
|
+
|
|
5
|
+
Related Tickets:
|
|
6
|
+
- OMN-1278: Contract-Driven Dashboard - Registry Discovery
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
14
|
+
|
|
15
|
+
from omnibase_infra.services.registry_api.models.model_pagination_info import (
|
|
16
|
+
ModelPaginationInfo,
|
|
17
|
+
)
|
|
18
|
+
from omnibase_infra.services.registry_api.models.model_registry_instance_view import (
|
|
19
|
+
ModelRegistryInstanceView,
|
|
20
|
+
)
|
|
21
|
+
from omnibase_infra.services.registry_api.models.model_registry_node_view import (
|
|
22
|
+
ModelRegistryNodeView,
|
|
23
|
+
)
|
|
24
|
+
from omnibase_infra.services.registry_api.models.model_registry_summary import (
|
|
25
|
+
ModelRegistrySummary,
|
|
26
|
+
)
|
|
27
|
+
from omnibase_infra.services.registry_api.models.model_warning import ModelWarning
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ModelRegistryDiscoveryResponse(BaseModel):
|
|
31
|
+
"""Full dashboard payload combining nodes, instances, and summary.
|
|
32
|
+
|
|
33
|
+
The primary response model for the GET /registry/discovery endpoint,
|
|
34
|
+
providing everything a dashboard needs in a single request.
|
|
35
|
+
|
|
36
|
+
Attributes:
|
|
37
|
+
timestamp: When this response was generated
|
|
38
|
+
warnings: List of warnings for partial success scenarios
|
|
39
|
+
summary: Aggregate statistics
|
|
40
|
+
nodes: List of registered nodes
|
|
41
|
+
live_instances: List of live Consul instances
|
|
42
|
+
pagination: Pagination info for nodes list
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
46
|
+
|
|
47
|
+
timestamp: datetime = Field(
|
|
48
|
+
...,
|
|
49
|
+
description="When this response was generated",
|
|
50
|
+
)
|
|
51
|
+
warnings: list[ModelWarning] = Field(
|
|
52
|
+
default_factory=list,
|
|
53
|
+
description="Warnings for partial success scenarios",
|
|
54
|
+
)
|
|
55
|
+
summary: ModelRegistrySummary = Field(
|
|
56
|
+
...,
|
|
57
|
+
description="Aggregate statistics",
|
|
58
|
+
)
|
|
59
|
+
nodes: list[ModelRegistryNodeView] = Field(
|
|
60
|
+
default_factory=list,
|
|
61
|
+
description="List of registered nodes",
|
|
62
|
+
)
|
|
63
|
+
live_instances: list[ModelRegistryInstanceView] = Field(
|
|
64
|
+
default_factory=list,
|
|
65
|
+
description="List of live Consul instances",
|
|
66
|
+
)
|
|
67
|
+
pagination: ModelPaginationInfo = Field(
|
|
68
|
+
...,
|
|
69
|
+
description="Pagination info for nodes list",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
__all__ = ["ModelRegistryDiscoveryResponse"]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Registry health response model for API health checks.
|
|
4
|
+
|
|
5
|
+
Related Tickets:
|
|
6
|
+
- OMN-1278: Contract-Driven Dashboard - Registry Discovery
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Literal
|
|
13
|
+
|
|
14
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
15
|
+
|
|
16
|
+
from omnibase_core.types import JsonType
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ModelRegistryHealthResponse(BaseModel):
|
|
20
|
+
"""Health check response for the registry API.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
status: Overall health status (healthy, degraded, unhealthy)
|
|
24
|
+
timestamp: When the health check was performed
|
|
25
|
+
components: Health status of individual components
|
|
26
|
+
version: API version string
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
30
|
+
|
|
31
|
+
status: Literal["healthy", "degraded", "unhealthy"] = Field(
|
|
32
|
+
...,
|
|
33
|
+
description="Overall health status",
|
|
34
|
+
)
|
|
35
|
+
timestamp: datetime = Field(
|
|
36
|
+
...,
|
|
37
|
+
description="When the health check was performed",
|
|
38
|
+
)
|
|
39
|
+
components: dict[str, JsonType] = Field(
|
|
40
|
+
default_factory=dict,
|
|
41
|
+
description="Health status of individual components",
|
|
42
|
+
)
|
|
43
|
+
version: str = Field(
|
|
44
|
+
default="1.0.0",
|
|
45
|
+
description="API version string",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
__all__ = ["ModelRegistryHealthResponse"]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Registry instance view model for dashboard display.
|
|
4
|
+
|
|
5
|
+
Related Tickets:
|
|
6
|
+
- OMN-1278: Contract-Driven Dashboard - Registry Discovery
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Literal
|
|
13
|
+
from uuid import UUID
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelRegistryInstanceView(BaseModel):
|
|
19
|
+
"""Live service instance view for dashboard display.
|
|
20
|
+
|
|
21
|
+
Represents a live Consul service instance, providing real-time
|
|
22
|
+
health and connectivity information.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
node_id: Node UUID (may be derived from service_id if not UUID)
|
|
26
|
+
service_name: Consul service name
|
|
27
|
+
service_id: Consul service instance ID
|
|
28
|
+
instance_id: Unique instance identifier (same as service_id)
|
|
29
|
+
address: Network address (IP or hostname)
|
|
30
|
+
port: Service port number
|
|
31
|
+
health_status: Health check status (passing, warning, critical, unknown)
|
|
32
|
+
health_output: Health check output message (nullable)
|
|
33
|
+
last_check_at: Timestamp of last health check (nullable)
|
|
34
|
+
tags: Consul service tags
|
|
35
|
+
meta: Consul service metadata
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
|
|
39
|
+
|
|
40
|
+
node_id: UUID = Field(
|
|
41
|
+
...,
|
|
42
|
+
description="Node UUID (may be derived from service_id)",
|
|
43
|
+
)
|
|
44
|
+
service_name: str = Field( # ONEX_EXCLUDE: pattern - Consul discovery identifier
|
|
45
|
+
...,
|
|
46
|
+
description="Consul service name (external Consul identifier, not entity reference)",
|
|
47
|
+
)
|
|
48
|
+
service_id: UUID = Field(
|
|
49
|
+
...,
|
|
50
|
+
description="Consul service instance ID",
|
|
51
|
+
)
|
|
52
|
+
instance_id: UUID = Field(
|
|
53
|
+
...,
|
|
54
|
+
description="Unique instance identifier",
|
|
55
|
+
)
|
|
56
|
+
address: str = Field(
|
|
57
|
+
...,
|
|
58
|
+
description="Network address (IP or hostname)",
|
|
59
|
+
)
|
|
60
|
+
port: int = Field(
|
|
61
|
+
...,
|
|
62
|
+
ge=1,
|
|
63
|
+
le=65535,
|
|
64
|
+
description="Service port number",
|
|
65
|
+
)
|
|
66
|
+
health_status: Literal["passing", "warning", "critical", "unknown"] = Field(
|
|
67
|
+
...,
|
|
68
|
+
description="Health check status",
|
|
69
|
+
)
|
|
70
|
+
health_output: str | None = Field(
|
|
71
|
+
default=None,
|
|
72
|
+
description="Health check output message",
|
|
73
|
+
)
|
|
74
|
+
last_check_at: datetime | None = Field(
|
|
75
|
+
default=None,
|
|
76
|
+
description="Timestamp of last health check",
|
|
77
|
+
)
|
|
78
|
+
tags: list[str] = Field(
|
|
79
|
+
default_factory=list,
|
|
80
|
+
description="Consul service tags",
|
|
81
|
+
)
|
|
82
|
+
meta: dict[str, str] = Field(
|
|
83
|
+
default_factory=dict,
|
|
84
|
+
description="Consul service metadata",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
__all__ = ["ModelRegistryInstanceView"]
|