infrahub-server 1.3.5__py3-none-any.whl → 1.4.0b0__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.
- infrahub/api/internal.py +5 -0
- infrahub/artifacts/tasks.py +17 -22
- infrahub/branch/merge_mutation_checker.py +38 -0
- infrahub/cli/__init__.py +2 -2
- infrahub/cli/context.py +7 -3
- infrahub/cli/db.py +5 -16
- infrahub/cli/upgrade.py +7 -29
- infrahub/computed_attribute/tasks.py +36 -46
- infrahub/config.py +53 -2
- infrahub/constants/environment.py +1 -0
- infrahub/core/attribute.py +9 -7
- infrahub/core/branch/tasks.py +43 -41
- infrahub/core/constants/__init__.py +20 -6
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/diff/coordinator.py +3 -1
- infrahub/core/diff/repository/repository.py +0 -8
- infrahub/core/diff/tasks.py +11 -8
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/index.py +1 -2
- infrahub/core/graph/schema.py +50 -29
- infrahub/core/initialization.py +62 -33
- infrahub/core/ipam/tasks.py +4 -3
- infrahub/core/merge.py +8 -10
- infrahub/core/migrations/graph/__init__.py +2 -0
- infrahub/core/migrations/graph/m035_drop_attr_value_index.py +45 -0
- infrahub/core/migrations/query/attribute_add.py +27 -2
- infrahub/core/migrations/schema/tasks.py +6 -5
- infrahub/core/node/proposed_change.py +43 -0
- infrahub/core/protocols.py +12 -0
- infrahub/core/query/attribute.py +32 -14
- infrahub/core/query/diff.py +11 -0
- infrahub/core/query/ipam.py +13 -7
- infrahub/core/query/node.py +51 -10
- infrahub/core/query/resource_manager.py +3 -3
- infrahub/core/schema/basenode_schema.py +8 -0
- infrahub/core/schema/definitions/core/__init__.py +10 -1
- infrahub/core/schema/definitions/core/ipam.py +28 -2
- infrahub/core/schema/definitions/core/propose_change.py +15 -0
- infrahub/core/schema/definitions/core/webhook.py +3 -0
- infrahub/core/schema/generic_schema.py +10 -0
- infrahub/core/schema/manager.py +10 -1
- infrahub/core/schema/node_schema.py +22 -17
- infrahub/core/schema/profile_schema.py +8 -0
- infrahub/core/schema/schema_branch.py +9 -5
- infrahub/core/schema/template_schema.py +8 -0
- infrahub/core/validators/checks_runner.py +5 -5
- infrahub/core/validators/tasks.py +6 -7
- infrahub/core/validators/uniqueness/checker.py +4 -2
- infrahub/core/validators/uniqueness/model.py +1 -0
- infrahub/core/validators/uniqueness/query.py +57 -7
- infrahub/database/__init__.py +2 -1
- infrahub/events/__init__.py +18 -0
- infrahub/events/constants.py +7 -0
- infrahub/events/generator.py +29 -2
- infrahub/events/proposed_change_action.py +181 -0
- infrahub/generators/tasks.py +24 -20
- infrahub/git/base.py +4 -7
- infrahub/git/integrator.py +21 -12
- infrahub/git/repository.py +15 -30
- infrahub/git/tasks.py +121 -106
- infrahub/graphql/field_extractor.py +69 -0
- infrahub/graphql/manager.py +15 -11
- infrahub/graphql/mutations/account.py +2 -2
- infrahub/graphql/mutations/action.py +8 -2
- infrahub/graphql/mutations/artifact_definition.py +4 -1
- infrahub/graphql/mutations/branch.py +10 -5
- infrahub/graphql/mutations/graphql_query.py +2 -1
- infrahub/graphql/mutations/main.py +14 -8
- infrahub/graphql/mutations/menu.py +2 -1
- infrahub/graphql/mutations/proposed_change.py +225 -8
- infrahub/graphql/mutations/relationship.py +5 -0
- infrahub/graphql/mutations/repository.py +2 -1
- infrahub/graphql/mutations/tasks.py +7 -9
- infrahub/graphql/mutations/webhook.py +4 -1
- infrahub/graphql/parser.py +15 -6
- infrahub/graphql/queries/__init__.py +10 -1
- infrahub/graphql/queries/account.py +3 -3
- infrahub/graphql/queries/branch.py +2 -2
- infrahub/graphql/queries/diff/tree.py +3 -3
- infrahub/graphql/queries/event.py +13 -3
- infrahub/graphql/queries/ipam.py +23 -1
- infrahub/graphql/queries/proposed_change.py +84 -0
- infrahub/graphql/queries/relationship.py +2 -2
- infrahub/graphql/queries/resource_manager.py +3 -3
- infrahub/graphql/queries/search.py +3 -2
- infrahub/graphql/queries/status.py +3 -2
- infrahub/graphql/queries/task.py +2 -2
- infrahub/graphql/resolvers/ipam.py +440 -0
- infrahub/graphql/resolvers/many_relationship.py +4 -3
- infrahub/graphql/resolvers/resolver.py +5 -5
- infrahub/graphql/resolvers/single_relationship.py +3 -2
- infrahub/graphql/schema.py +25 -5
- infrahub/graphql/types/__init__.py +2 -2
- infrahub/graphql/types/attribute.py +3 -3
- infrahub/graphql/types/event.py +60 -0
- infrahub/groups/tasks.py +6 -6
- infrahub/lock.py +3 -2
- infrahub/menu/generator.py +8 -0
- infrahub/message_bus/operations/__init__.py +9 -12
- infrahub/message_bus/operations/git/file.py +6 -5
- infrahub/message_bus/operations/git/repository.py +12 -20
- infrahub/message_bus/operations/refresh/registry.py +15 -9
- infrahub/message_bus/operations/send/echo.py +7 -4
- infrahub/message_bus/types.py +1 -0
- infrahub/permissions/globals.py +1 -4
- infrahub/permissions/manager.py +8 -5
- infrahub/pools/prefix.py +7 -5
- infrahub/prefect_server/app.py +31 -0
- infrahub/prefect_server/bootstrap.py +18 -0
- infrahub/proposed_change/action_checker.py +206 -0
- infrahub/proposed_change/approval_revoker.py +40 -0
- infrahub/proposed_change/branch_diff.py +3 -1
- infrahub/proposed_change/checker.py +45 -0
- infrahub/proposed_change/constants.py +32 -2
- infrahub/proposed_change/tasks.py +182 -150
- infrahub/py.typed +0 -0
- infrahub/server.py +29 -17
- infrahub/services/__init__.py +13 -28
- infrahub/services/adapters/cache/__init__.py +4 -0
- infrahub/services/adapters/cache/nats.py +2 -0
- infrahub/services/adapters/cache/redis.py +3 -0
- infrahub/services/adapters/message_bus/__init__.py +0 -2
- infrahub/services/adapters/message_bus/local.py +1 -2
- infrahub/services/adapters/message_bus/nats.py +6 -8
- infrahub/services/adapters/message_bus/rabbitmq.py +7 -9
- infrahub/services/adapters/workflow/__init__.py +1 -0
- infrahub/services/adapters/workflow/local.py +1 -8
- infrahub/services/component.py +2 -1
- infrahub/task_manager/event.py +52 -0
- infrahub/task_manager/models.py +9 -0
- infrahub/tasks/artifact.py +6 -7
- infrahub/tasks/check.py +4 -7
- infrahub/telemetry/tasks.py +15 -18
- infrahub/transformations/tasks.py +10 -6
- infrahub/trigger/tasks.py +4 -3
- infrahub/types.py +4 -0
- infrahub/validators/events.py +7 -7
- infrahub/validators/tasks.py +6 -7
- infrahub/webhook/models.py +45 -45
- infrahub/webhook/tasks.py +25 -24
- infrahub/workers/dependencies.py +143 -0
- infrahub/workers/infrahub_async.py +19 -43
- infrahub/workflows/catalogue.py +16 -2
- infrahub/workflows/initialization.py +5 -4
- infrahub/workflows/models.py +2 -0
- infrahub_sdk/client.py +6 -6
- infrahub_sdk/ctl/repository.py +51 -0
- infrahub_sdk/ctl/schema.py +9 -9
- infrahub_sdk/protocols.py +40 -6
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/METADATA +5 -4
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/RECORD +158 -144
- infrahub_testcontainers/container.py +17 -0
- infrahub_testcontainers/docker-compose-cluster.test.yml +56 -1
- infrahub_testcontainers/docker-compose.test.yml +56 -1
- infrahub_testcontainers/helpers.py +4 -1
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/entry_points.txt +0 -0
infrahub/py.typed
ADDED
|
File without changes
|
infrahub/server.py
CHANGED
|
@@ -23,8 +23,8 @@ from infrahub import __version__, config
|
|
|
23
23
|
from infrahub.api import router as api
|
|
24
24
|
from infrahub.api.exception_handlers import generic_api_exception_handler
|
|
25
25
|
from infrahub.components import ComponentType
|
|
26
|
+
from infrahub.constants.environment import INSTALLATION_TYPE
|
|
26
27
|
from infrahub.core.initialization import initialization
|
|
27
|
-
from infrahub.database import InfrahubDatabase, InfrahubDatabaseMode, get_db
|
|
28
28
|
from infrahub.dependencies.registry import build_component_registry
|
|
29
29
|
from infrahub.exceptions import Error, ValidationError
|
|
30
30
|
from infrahub.graphql.api.endpoints import router as graphql_router
|
|
@@ -32,18 +32,24 @@ from infrahub.lock import initialize_lock
|
|
|
32
32
|
from infrahub.log import clear_log_context, get_logger, set_log_data
|
|
33
33
|
from infrahub.middleware import InfrahubCORSMiddleware
|
|
34
34
|
from infrahub.services import InfrahubServices
|
|
35
|
-
from infrahub.services.adapters.cache import InfrahubCache
|
|
36
|
-
from infrahub.services.adapters.message_bus import InfrahubMessageBus
|
|
37
|
-
from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
|
|
38
|
-
from infrahub.services.adapters.workflow.worker import WorkflowWorkerExecution
|
|
39
35
|
from infrahub.trace import add_span_exception, configure_trace, get_traceid
|
|
40
36
|
from infrahub.worker import WORKER_IDENTITY
|
|
37
|
+
from infrahub.workers.dependencies import (
|
|
38
|
+
get_cache,
|
|
39
|
+
get_component,
|
|
40
|
+
get_database,
|
|
41
|
+
get_installation_type,
|
|
42
|
+
get_message_bus,
|
|
43
|
+
get_workflow,
|
|
44
|
+
set_component_type,
|
|
45
|
+
)
|
|
41
46
|
|
|
42
47
|
CURRENT_DIRECTORY = Path(__file__).parent.resolve()
|
|
43
48
|
|
|
44
49
|
|
|
45
50
|
async def app_initialization(application: FastAPI, enable_scheduler: bool = True) -> None:
|
|
46
51
|
config.SETTINGS.initialize_and_exit()
|
|
52
|
+
_validate_feature_selection(configuration=config.SETTINGS.active_settings)
|
|
47
53
|
|
|
48
54
|
# Initialize trace
|
|
49
55
|
if config.SETTINGS.trace.enable:
|
|
@@ -55,27 +61,24 @@ async def app_initialization(application: FastAPI, enable_scheduler: bool = True
|
|
|
55
61
|
exporter_protocol=config.SETTINGS.trace.exporter_protocol,
|
|
56
62
|
)
|
|
57
63
|
|
|
64
|
+
component_type = ComponentType.API_SERVER
|
|
65
|
+
set_component_type(component_type=component_type)
|
|
66
|
+
|
|
58
67
|
# Initialize database Driver and load local registry
|
|
59
|
-
database = application.state.db =
|
|
68
|
+
database = application.state.db = await get_database()
|
|
60
69
|
|
|
61
70
|
build_component_registry()
|
|
62
71
|
|
|
63
|
-
workflow =
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
68
|
-
component_type = ComponentType.API_SERVER
|
|
69
|
-
message_bus = config.OVERRIDE.message_bus or await InfrahubMessageBus.new_from_driver(
|
|
70
|
-
component_type=component_type, driver=config.SETTINGS.broker.driver
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
cache = config.OVERRIDE.cache or (await InfrahubCache.new_from_driver(driver=config.SETTINGS.cache.driver))
|
|
72
|
+
workflow = get_workflow()
|
|
73
|
+
message_bus = await get_message_bus()
|
|
74
|
+
cache = await get_cache()
|
|
75
|
+
component = await get_component()
|
|
74
76
|
service = await InfrahubServices.new(
|
|
75
77
|
cache=cache,
|
|
76
78
|
database=database,
|
|
77
79
|
message_bus=message_bus,
|
|
78
80
|
workflow=workflow,
|
|
81
|
+
component=component,
|
|
79
82
|
component_type=component_type,
|
|
80
83
|
)
|
|
81
84
|
initialize_lock(service=service)
|
|
@@ -212,3 +215,12 @@ async def documentation() -> RedirectResponse:
|
|
|
212
215
|
@app.get("/{rest_of_path:path}", include_in_schema=False)
|
|
213
216
|
async def react_app(req: Request, rest_of_path: str) -> Response: # noqa: ARG001
|
|
214
217
|
return templates.TemplateResponse("index.html", {"request": req})
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _validate_feature_selection(configuration: config.Settings) -> None:
|
|
221
|
+
if configuration.enterprise_features and not configuration.dev.allow_enterprise_configuration:
|
|
222
|
+
installation_type = get_installation_type()
|
|
223
|
+
if installation_type == INSTALLATION_TYPE:
|
|
224
|
+
raise ValidationError(
|
|
225
|
+
f"Enterprise features [{','.join(configuration.enterprise_features)}] are not supported when running Infrahub 'community'."
|
|
226
|
+
)
|
infrahub/services/__init__.py
CHANGED
|
@@ -9,9 +9,7 @@ from infrahub.message_bus.messages import ROUTING_KEY_MAP
|
|
|
9
9
|
|
|
10
10
|
from .adapters.event import InfrahubEventService
|
|
11
11
|
from .adapters.http.httpx import HttpxAdapter
|
|
12
|
-
from .adapters.workflow.local import WorkflowLocalExecution
|
|
13
12
|
from .adapters.workflow.worker import WorkflowWorkerExecution
|
|
14
|
-
from .component import InfrahubComponent
|
|
15
13
|
from .scheduler import InfrahubScheduler
|
|
16
14
|
|
|
17
15
|
if TYPE_CHECKING:
|
|
@@ -25,6 +23,7 @@ if TYPE_CHECKING:
|
|
|
25
23
|
from .adapters.http import InfrahubHTTP
|
|
26
24
|
from .adapters.message_bus import InfrahubMessageBus
|
|
27
25
|
from .adapters.workflow import InfrahubWorkflow
|
|
26
|
+
from .component import InfrahubComponent
|
|
28
27
|
from .protocols import InfrahubLogger
|
|
29
28
|
|
|
30
29
|
|
|
@@ -54,6 +53,7 @@ class InfrahubServices:
|
|
|
54
53
|
database: InfrahubDatabase | None = None,
|
|
55
54
|
message_bus: InfrahubMessageBus | None = None,
|
|
56
55
|
workflow: InfrahubWorkflow | None = None,
|
|
56
|
+
component: InfrahubComponent | None = None,
|
|
57
57
|
):
|
|
58
58
|
"""
|
|
59
59
|
This method should not be called directly, use `new` instead for a proper initialization.
|
|
@@ -64,12 +64,12 @@ class InfrahubServices:
|
|
|
64
64
|
self._database = database
|
|
65
65
|
self._message_bus = message_bus
|
|
66
66
|
self._workflow = workflow
|
|
67
|
+
self._component = component
|
|
67
68
|
self.log = log
|
|
68
69
|
self.component_type = component_type
|
|
69
70
|
self.http = http
|
|
70
71
|
self.event = event
|
|
71
72
|
self.scheduler = scheduler
|
|
72
|
-
self._component = None
|
|
73
73
|
|
|
74
74
|
@classmethod
|
|
75
75
|
async def new(
|
|
@@ -81,6 +81,7 @@ class InfrahubServices:
|
|
|
81
81
|
message_bus: InfrahubMessageBus | None = None,
|
|
82
82
|
workflow: InfrahubWorkflow | None = None,
|
|
83
83
|
log: InfrahubLogger | None = None,
|
|
84
|
+
component: InfrahubComponent | None = None,
|
|
84
85
|
component_type: ComponentType | None = None,
|
|
85
86
|
http: InfrahubHTTP | None = None,
|
|
86
87
|
) -> InfrahubServices:
|
|
@@ -99,6 +100,7 @@ class InfrahubServices:
|
|
|
99
100
|
message_bus=message_bus,
|
|
100
101
|
workflow=workflow,
|
|
101
102
|
log=log or get_logger(),
|
|
103
|
+
component=component,
|
|
102
104
|
component_type=component_type,
|
|
103
105
|
scheduler=scheduler,
|
|
104
106
|
event=event or InfrahubEventService(message_bus),
|
|
@@ -108,31 +110,12 @@ class InfrahubServices:
|
|
|
108
110
|
# This circular dependency could be removed if InfrahubScheduler only depends on what it needs.
|
|
109
111
|
scheduler.service = service
|
|
110
112
|
|
|
111
|
-
if
|
|
112
|
-
|
|
113
|
-
#
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
component = await InfrahubComponent.new(
|
|
118
|
-
cache=cache, component_type=component_type, db=database, message_bus=message_bus
|
|
119
|
-
)
|
|
120
|
-
# We need to post init `service._component` because InfrahubComponent.new relies on message_bus
|
|
121
|
-
# itself relying on service.
|
|
122
|
-
service._component = component
|
|
123
|
-
|
|
124
|
-
if workflow is not None:
|
|
125
|
-
if isinstance(workflow, WorkflowWorkerExecution):
|
|
126
|
-
assert service.component is not None
|
|
127
|
-
# Ideally `WorkflowWorkerExecution.initialize` would be directly part of WorkflowWorkerExecution
|
|
128
|
-
# constructor but this requires some redesign as it depends on InfrahubComponent which is instantiated
|
|
129
|
-
# after workflow instantiation.
|
|
130
|
-
await workflow.initialize(
|
|
131
|
-
component_is_primary_server=await service.component.is_primary_gunicorn_worker()
|
|
132
|
-
)
|
|
133
|
-
elif isinstance(workflow, WorkflowLocalExecution):
|
|
134
|
-
# Circular dependency is only needed for injecting `service` within `execute_workflow` while testing.
|
|
135
|
-
workflow.service = service
|
|
113
|
+
if workflow is not None and isinstance(workflow, WorkflowWorkerExecution):
|
|
114
|
+
assert service.component is not None
|
|
115
|
+
# Ideally `WorkflowWorkerExecution.initialize` would be directly part of WorkflowWorkerExecution
|
|
116
|
+
# constructor but this requires some redesign as it depends on InfrahubComponent which is instantiated
|
|
117
|
+
# after workflow instantiation.
|
|
118
|
+
await workflow.initialize(component_is_primary_server=await service.component.is_primary_gunicorn_worker())
|
|
136
119
|
|
|
137
120
|
return service
|
|
138
121
|
|
|
@@ -181,6 +164,8 @@ class InfrahubServices:
|
|
|
181
164
|
async def shutdown(self) -> None:
|
|
182
165
|
await self.scheduler.shutdown()
|
|
183
166
|
await self.message_bus.shutdown()
|
|
167
|
+
if self._cache is not None:
|
|
168
|
+
await self._cache.close_connection()
|
|
184
169
|
|
|
185
170
|
async def send(self, message: InfrahubMessage, delay: MessageTTL | None = None, is_retry: bool = False) -> None:
|
|
186
171
|
routing_key = ROUTING_KEY_MAP.get(type(message))
|
|
@@ -13,7 +13,6 @@ if TYPE_CHECKING:
|
|
|
13
13
|
from infrahub.config import BrokerDriver, BrokerSettings
|
|
14
14
|
from infrahub.message_bus import InfrahubMessage, InfrahubResponse
|
|
15
15
|
from infrahub.message_bus.types import MessageTTL
|
|
16
|
-
from infrahub.services import InfrahubServices
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
class InfrahubMessageBus(ABC):
|
|
@@ -32,7 +31,6 @@ class InfrahubMessageBus(ABC):
|
|
|
32
31
|
]
|
|
33
32
|
event_bindings: list[str] = ["refresh.registry.*"]
|
|
34
33
|
broadcasted_event_bindings: list[str] = ["refresh.git.*"]
|
|
35
|
-
service: InfrahubServices
|
|
36
34
|
|
|
37
35
|
async def shutdown(self) -> None: # noqa: B027 We want a default empty behavior, so it's ok to have an empty non-abstract method.
|
|
38
36
|
"""Shutdown the Message bus"""
|
|
@@ -36,8 +36,7 @@ class BusSimulator(InfrahubMessageBus):
|
|
|
36
36
|
if routing_key not in self.messages_per_routing_key:
|
|
37
37
|
self.messages_per_routing_key[routing_key] = []
|
|
38
38
|
self.messages_per_routing_key[routing_key].append(message)
|
|
39
|
-
|
|
40
|
-
await execute_message(routing_key=routing_key, message_body=message.body, service=self.service)
|
|
39
|
+
await execute_message(routing_key=routing_key, message_body=message.body, message_bus=self)
|
|
41
40
|
|
|
42
41
|
async def reply(self, message: InfrahubMessage, routing_key: str) -> None: # noqa: ARG002
|
|
43
42
|
correlation_id = message.meta.correlation_id or "default"
|
|
@@ -12,7 +12,7 @@ from opentelemetry.instrumentation.utils import is_instrumentation_enabled
|
|
|
12
12
|
|
|
13
13
|
from infrahub import config
|
|
14
14
|
from infrahub.components import ComponentType
|
|
15
|
-
from infrahub.log import clear_log_context, get_log_data
|
|
15
|
+
from infrahub.log import clear_log_context, get_log_data, get_logger
|
|
16
16
|
from infrahub.message_bus import InfrahubMessage, Meta, messages
|
|
17
17
|
from infrahub.message_bus.operations import execute_message
|
|
18
18
|
from infrahub.services.adapters.message_bus import InfrahubMessageBus
|
|
@@ -21,7 +21,6 @@ from infrahub.worker import WORKER_IDENTITY
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
22
|
from infrahub.config import BrokerSettings
|
|
23
23
|
from infrahub.message_bus.types import MessageTTL
|
|
24
|
-
from infrahub.services import InfrahubServices
|
|
25
24
|
|
|
26
25
|
MessageFunction = Callable[[InfrahubMessage], Awaitable[None]]
|
|
27
26
|
ResponseClass = TypeVar("ResponseClass")
|
|
@@ -38,7 +37,6 @@ class NATSMessageBus(InfrahubMessageBus):
|
|
|
38
37
|
def __init__(self, component_type: ComponentType, settings: BrokerSettings | None = None) -> None:
|
|
39
38
|
self.settings = settings or config.SETTINGS.broker
|
|
40
39
|
|
|
41
|
-
self.service: InfrahubServices
|
|
42
40
|
self.connection: nats.NATS
|
|
43
41
|
self.jetstream: nats.js.JetStreamContext
|
|
44
42
|
self.callback_queue: nats.js.api.StreamInfo
|
|
@@ -102,9 +100,9 @@ class NATSMessageBus(InfrahubMessageBus):
|
|
|
102
100
|
|
|
103
101
|
clear_log_context()
|
|
104
102
|
if message.subject in messages.MESSAGE_MAP:
|
|
105
|
-
await execute_message(routing_key=message.subject, message_body=message.data,
|
|
103
|
+
await execute_message(routing_key=message.subject, message_body=message.data, message_bus=self)
|
|
106
104
|
else:
|
|
107
|
-
|
|
105
|
+
get_logger().error("Invalid message received", message=f"{message!r}")
|
|
108
106
|
finally:
|
|
109
107
|
if is_instrumentation_enabled() and message.headers:
|
|
110
108
|
context.detach(token)
|
|
@@ -121,12 +119,12 @@ class NATSMessageBus(InfrahubMessageBus):
|
|
|
121
119
|
clear_log_context()
|
|
122
120
|
if message.subject in messages.MESSAGE_MAP:
|
|
123
121
|
delay = await execute_message(
|
|
124
|
-
routing_key=message.subject, message_body=message.data,
|
|
122
|
+
routing_key=message.subject, message_body=message.data, message_bus=self
|
|
125
123
|
)
|
|
126
124
|
if delay:
|
|
127
125
|
return await message.nak(delay / 1000)
|
|
128
126
|
else:
|
|
129
|
-
|
|
127
|
+
get_logger().error("Invalid message received", message=f"{message!r}")
|
|
130
128
|
|
|
131
129
|
return await message.ack()
|
|
132
130
|
finally:
|
|
@@ -292,7 +290,7 @@ class NATSMessageBus(InfrahubMessageBus):
|
|
|
292
290
|
request_id=request_id, correlation_id=correlation_id, reply_to=self.callback_queue.config.name
|
|
293
291
|
)
|
|
294
292
|
|
|
295
|
-
await self.
|
|
293
|
+
await self.send(message=message)
|
|
296
294
|
|
|
297
295
|
response: nats.aio.msg.Msg = await future
|
|
298
296
|
data = ujson.loads(response.data)
|
|
@@ -12,7 +12,7 @@ from opentelemetry.semconv.trace import SpanAttributes
|
|
|
12
12
|
|
|
13
13
|
from infrahub import config
|
|
14
14
|
from infrahub.components import ComponentType
|
|
15
|
-
from infrahub.log import clear_log_context, get_log_data
|
|
15
|
+
from infrahub.log import clear_log_context, get_log_data, get_logger
|
|
16
16
|
from infrahub.message_bus import InfrahubMessage, Meta, messages
|
|
17
17
|
from infrahub.message_bus.operations import execute_message
|
|
18
18
|
from infrahub.message_bus.types import MessageTTL
|
|
@@ -30,7 +30,6 @@ if TYPE_CHECKING:
|
|
|
30
30
|
from opentelemetry.instrumentation.aio_pika.span_builder import SpanBuilder
|
|
31
31
|
|
|
32
32
|
from infrahub.config import BrokerSettings
|
|
33
|
-
from infrahub.services import InfrahubServices
|
|
34
33
|
|
|
35
34
|
MessageFunction = Callable[[InfrahubMessage], Awaitable[None]]
|
|
36
35
|
ResponseClass = TypeVar("ResponseClass")
|
|
@@ -72,7 +71,6 @@ class RabbitMQMessageBus(InfrahubMessageBus):
|
|
|
72
71
|
self.channel: AbstractChannel
|
|
73
72
|
self.exchange: AbstractExchange
|
|
74
73
|
self.delayed_exchange: AbstractExchange
|
|
75
|
-
self.service: InfrahubServices # Needed because we inject `service` while sending messages.
|
|
76
74
|
self.connection: AbstractRobustConnection
|
|
77
75
|
self.callback_queue: AbstractQueue
|
|
78
76
|
self.events_queue: AbstractQueue
|
|
@@ -130,23 +128,23 @@ class RabbitMQMessageBus(InfrahubMessageBus):
|
|
|
130
128
|
|
|
131
129
|
clear_log_context()
|
|
132
130
|
if message.routing_key in messages.MESSAGE_MAP:
|
|
133
|
-
await execute_message(routing_key=message.routing_key, message_body=message.body,
|
|
131
|
+
await execute_message(routing_key=message.routing_key, message_body=message.body, message_bus=self)
|
|
134
132
|
else:
|
|
135
|
-
|
|
133
|
+
get_logger().error("Invalid message received", message=f"{message!r}")
|
|
136
134
|
|
|
137
135
|
async def on_message(self, message: AbstractIncomingMessage) -> None:
|
|
138
136
|
async with message.process():
|
|
139
137
|
clear_log_context()
|
|
140
138
|
if message.routing_key in messages.MESSAGE_MAP:
|
|
141
|
-
await execute_message(routing_key=message.routing_key, message_body=message.body,
|
|
139
|
+
await execute_message(routing_key=message.routing_key, message_body=message.body, message_bus=self)
|
|
142
140
|
else:
|
|
143
|
-
|
|
141
|
+
get_logger().error("Invalid message received", message=f"{message!r}")
|
|
144
142
|
|
|
145
143
|
async def on_reconnect(
|
|
146
144
|
self,
|
|
147
145
|
weak: bool = False, # noqa: ARG002
|
|
148
146
|
) -> None:
|
|
149
|
-
|
|
147
|
+
get_logger().info("Reconnected to RabbitMQ, reinitializing connection")
|
|
150
148
|
await self._initialize_connection()
|
|
151
149
|
|
|
152
150
|
async def _initialize_api_server(self) -> None:
|
|
@@ -246,7 +244,7 @@ class RabbitMQMessageBus(InfrahubMessageBus):
|
|
|
246
244
|
request_id = log_data.get("request_id", "")
|
|
247
245
|
message.meta = Meta(request_id=request_id, correlation_id=correlation_id, reply_to=self.callback_queue.name)
|
|
248
246
|
|
|
249
|
-
await self.
|
|
247
|
+
await self.send(message=message)
|
|
250
248
|
|
|
251
249
|
response: AbstractIncomingMessage = await future
|
|
252
250
|
data = ujson.loads(response.body)
|
|
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Any, Callable, ParamSpec, TypeVar, overload
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
7
7
|
from infrahub.context import InfrahubContext
|
|
8
8
|
from infrahub.workflows.models import WorkflowDefinition, WorkflowInfo
|
|
9
|
+
|
|
9
10
|
Return = TypeVar("Return")
|
|
10
11
|
Params = ParamSpec("Params")
|
|
11
12
|
|
|
@@ -5,19 +5,16 @@ from typing import Any
|
|
|
5
5
|
|
|
6
6
|
from typing_extensions import TYPE_CHECKING
|
|
7
7
|
|
|
8
|
-
from infrahub.workers.utils import inject_context_parameter
|
|
8
|
+
from infrahub.workers.utils import inject_context_parameter
|
|
9
9
|
from infrahub.workflows.models import WorkflowDefinition, WorkflowInfo
|
|
10
10
|
|
|
11
11
|
from . import InfrahubWorkflow, Return
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
14
|
from infrahub.context import InfrahubContext
|
|
15
|
-
from infrahub.services import InfrahubServices
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
class WorkflowLocalExecution(InfrahubWorkflow):
|
|
19
|
-
service: InfrahubServices | None = None # needed for local injections
|
|
20
|
-
|
|
21
18
|
async def execute_workflow(
|
|
22
19
|
self,
|
|
23
20
|
workflow: WorkflowDefinition,
|
|
@@ -26,12 +23,8 @@ class WorkflowLocalExecution(InfrahubWorkflow):
|
|
|
26
23
|
parameters: dict[str, Any] | None = None,
|
|
27
24
|
tags: list[str] | None = None, # noqa: ARG002
|
|
28
25
|
) -> Any:
|
|
29
|
-
if self.service is None:
|
|
30
|
-
raise ValueError("WorkflowLocalExecution.service is not initialized")
|
|
31
|
-
|
|
32
26
|
flow_func = workflow.load_function()
|
|
33
27
|
parameters = dict(parameters) if parameters is not None else {} # avoid mutating input parameters
|
|
34
|
-
inject_service_parameter(func=flow_func, parameters=parameters, service=self.service)
|
|
35
28
|
inject_context_parameter(func=flow_func, parameters=parameters, context=context)
|
|
36
29
|
|
|
37
30
|
parameters = flow_func.validate_parameters(parameters=parameters)
|
infrahub/services/component.py
CHANGED
|
@@ -15,7 +15,8 @@ from infrahub.worker import WORKER_IDENTITY
|
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
17
|
from infrahub.database import InfrahubDatabase
|
|
18
|
-
from infrahub.services import InfrahubCache
|
|
18
|
+
from infrahub.services import InfrahubCache
|
|
19
|
+
from infrahub.services.adapters.message_bus import InfrahubMessageBus
|
|
19
20
|
|
|
20
21
|
PRIMARY_API_SERVER = "workers:primary:api_server"
|
|
21
22
|
WORKER_MATCH = re.compile(r":worker:([^:]+)")
|
infrahub/task_manager/event.py
CHANGED
|
@@ -172,6 +172,46 @@ class PrefectEventData(PrefectEventModel):
|
|
|
172
172
|
|
|
173
173
|
return {"members": members, "ancestors": ancestors}
|
|
174
174
|
|
|
175
|
+
def _return_proposed_change_event(self) -> dict[str, Any]:
|
|
176
|
+
data = {}
|
|
177
|
+
for resource in self.related:
|
|
178
|
+
if resource.role != "infrahub.related.node":
|
|
179
|
+
continue
|
|
180
|
+
match self.event:
|
|
181
|
+
case "infrahub.proposed_change.merged":
|
|
182
|
+
data.update(
|
|
183
|
+
{
|
|
184
|
+
"merged_by_account_id": resource.get("infrahub.node.id"),
|
|
185
|
+
"merged_by_account_name": resource.get("infrahub.merged_by.account.name"),
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
case "infrahub.proposed_change.review_requested":
|
|
189
|
+
data.update(
|
|
190
|
+
{
|
|
191
|
+
"requested_by_account_id": resource.get("infrahub.node.id"),
|
|
192
|
+
"requested_by_account_name": resource.get("infrahub.requested_by.account.name"),
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
case (
|
|
196
|
+
"infrahub.proposed_change.approved"
|
|
197
|
+
| "infrahub.proposed_change.rejected"
|
|
198
|
+
| "infrahub.proposed_change.approval_revoked"
|
|
199
|
+
| "infrahub.proposed_change.rejection_revoked"
|
|
200
|
+
):
|
|
201
|
+
data.update(
|
|
202
|
+
{
|
|
203
|
+
"reviewer_account_id": resource.get("infrahub.node.id"),
|
|
204
|
+
"reviewer_account_name": resource.get("infrahub.reviewer.account.name"),
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
return data
|
|
208
|
+
|
|
209
|
+
def _return_proposed_change_reviewer_decision(self) -> dict[str, Any]:
|
|
210
|
+
return {"reviewer_decision": self.resource.get("infrahub.proposed_change.reviewer_decision")}
|
|
211
|
+
|
|
212
|
+
def _return_proposed_change_reviewer_former_decision(self) -> dict[str, Any]:
|
|
213
|
+
return {"reviewer_former_decision": self.resource.get("infrahub.proposed_change.reviewer_former_decision")}
|
|
214
|
+
|
|
175
215
|
def _return_event_specifics(self) -> dict[str, Any]:
|
|
176
216
|
"""Return event specific data based on the type of event being processed"""
|
|
177
217
|
|
|
@@ -192,6 +232,18 @@ class PrefectEventData(PrefectEventModel):
|
|
|
192
232
|
event_specifics = self._return_branch_rebased()
|
|
193
233
|
case "infrahub.group.member_added" | "infrahub.group.member_removed":
|
|
194
234
|
event_specifics = self._return_group_event()
|
|
235
|
+
case "infrahub.proposed_change.approved" | "infrahub.proposed_change.rejected":
|
|
236
|
+
event_specifics = {
|
|
237
|
+
**self._return_proposed_change_event(),
|
|
238
|
+
**self._return_proposed_change_reviewer_decision(),
|
|
239
|
+
}
|
|
240
|
+
case "infrahub.proposed_change.approval_revoked" | "infrahub.proposed_change.rejection_revoked":
|
|
241
|
+
event_specifics = {
|
|
242
|
+
**self._return_proposed_change_event(),
|
|
243
|
+
**self._return_proposed_change_reviewer_former_decision(),
|
|
244
|
+
}
|
|
245
|
+
case "infrahub.proposed_change.review_requested" | "infrahub.proposed_change.merged":
|
|
246
|
+
event_specifics = self._return_proposed_change_event()
|
|
195
247
|
|
|
196
248
|
return event_specifics
|
|
197
249
|
|
infrahub/task_manager/models.py
CHANGED
|
@@ -14,10 +14,12 @@ from prefect.events.filters import (
|
|
|
14
14
|
EventRelatedFilter,
|
|
15
15
|
EventResourceFilter,
|
|
16
16
|
)
|
|
17
|
+
from prefect.events.filters import EventOrder as PrefectEventOrder
|
|
17
18
|
from prefect.events.schemas.events import ResourceSpecification
|
|
18
19
|
from pydantic import BaseModel, Field
|
|
19
20
|
|
|
20
21
|
from infrahub.core.timestamp import Timestamp
|
|
22
|
+
from infrahub.events.constants import EventSortOrder
|
|
21
23
|
|
|
22
24
|
from .constants import LOG_LEVEL_MAPPING
|
|
23
25
|
|
|
@@ -176,6 +178,7 @@ class InfrahubEventFilter(EventFilter):
|
|
|
176
178
|
@classmethod
|
|
177
179
|
def from_filters(
|
|
178
180
|
cls,
|
|
181
|
+
order: EventSortOrder,
|
|
179
182
|
ids: list[str] | None = None,
|
|
180
183
|
account__ids: list[str] | None = None,
|
|
181
184
|
related_node__ids: list[str] | None = None,
|
|
@@ -201,6 +204,12 @@ class InfrahubEventFilter(EventFilter):
|
|
|
201
204
|
else:
|
|
202
205
|
filters = cls()
|
|
203
206
|
|
|
207
|
+
match order:
|
|
208
|
+
case EventSortOrder.ASC:
|
|
209
|
+
filters.order = PrefectEventOrder.ASC
|
|
210
|
+
case EventSortOrder.DESC:
|
|
211
|
+
filters.order = PrefectEventOrder.DESC
|
|
212
|
+
|
|
204
213
|
filters.add_event_filter(level=level, has_children=has_children)
|
|
205
214
|
filters.add_event_id_filter(ids=ids)
|
|
206
215
|
filters.add_event_type_filter(event_type=event_type, event_type_filter=event_type_filter)
|
infrahub/tasks/artifact.py
CHANGED
|
@@ -6,20 +6,19 @@ from infrahub import lock
|
|
|
6
6
|
from infrahub.artifacts.models import CheckArtifactCreate
|
|
7
7
|
from infrahub.core.constants import InfrahubKind
|
|
8
8
|
from infrahub.git.models import RequestArtifactGenerate
|
|
9
|
-
from infrahub.
|
|
9
|
+
from infrahub.workers.dependencies import get_client
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
@task(name="define-artifact", task_run_name="Define Artifact", cache_policy=NONE) # type: ignore[arg-type]
|
|
13
|
-
async def define_artifact(
|
|
14
|
-
model: CheckArtifactCreate | RequestArtifactGenerate, service: InfrahubServices
|
|
15
|
-
) -> tuple[InfrahubNode, bool]:
|
|
13
|
+
async def define_artifact(model: CheckArtifactCreate | RequestArtifactGenerate) -> tuple[InfrahubNode, bool]:
|
|
16
14
|
"""Return an artifact together with a flag to indicate if the artifact is created now or already existed."""
|
|
15
|
+
client = get_client()
|
|
17
16
|
created = False
|
|
18
17
|
if model.artifact_id:
|
|
19
|
-
artifact = await
|
|
18
|
+
artifact = await client.get(kind=InfrahubKind.ARTIFACT, id=model.artifact_id, branch=model.branch_name)
|
|
20
19
|
else:
|
|
21
20
|
async with lock.registry.get(f"{model.target_id}-{model.artifact_definition}", namespace="artifact"):
|
|
22
|
-
artifacts = await
|
|
21
|
+
artifacts = await client.filters(
|
|
23
22
|
kind=InfrahubKind.ARTIFACT,
|
|
24
23
|
branch=model.branch_name,
|
|
25
24
|
definition__ids=[model.artifact_definition],
|
|
@@ -28,7 +27,7 @@ async def define_artifact(
|
|
|
28
27
|
if artifacts:
|
|
29
28
|
artifact = artifacts[0]
|
|
30
29
|
else:
|
|
31
|
-
artifact = await
|
|
30
|
+
artifact = await client.create(
|
|
32
31
|
kind=InfrahubKind.ARTIFACT,
|
|
33
32
|
branch=model.branch_name,
|
|
34
33
|
data={
|
infrahub/tasks/check.py
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
from infrahub.log import get_logger
|
|
2
2
|
from infrahub.message_bus import InfrahubMessage
|
|
3
3
|
from infrahub.message_bus.types import KVTTL
|
|
4
|
-
from infrahub.
|
|
4
|
+
from infrahub.workers.dependencies import get_cache
|
|
5
5
|
|
|
6
6
|
log = get_logger()
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
async def set_check_status(message: InfrahubMessage, conclusion: str
|
|
9
|
+
async def set_check_status(message: InfrahubMessage, conclusion: str) -> None:
|
|
10
10
|
if message.meta.validator_execution_id and message.meta.check_execution_id:
|
|
11
11
|
key = f"validator_execution_id:{message.meta.validator_execution_id}:check_execution_id:{message.meta.check_execution_id}"
|
|
12
|
-
await
|
|
13
|
-
|
|
14
|
-
value=conclusion,
|
|
15
|
-
expires=KVTTL.TWO_HOURS,
|
|
16
|
-
)
|
|
12
|
+
cache = await get_cache()
|
|
13
|
+
await cache.set(key=key, value=conclusion, expires=KVTTL.TWO_HOURS)
|
|
17
14
|
log.debug("setting check status in cache", key=key, conclusion=conclusion)
|