infrahub-server 1.1.6__py3-none-any.whl → 1.2.0rc0__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/artifact.py +16 -4
- infrahub/api/dependencies.py +8 -0
- infrahub/api/oauth2.py +0 -1
- infrahub/api/oidc.py +0 -1
- infrahub/api/query.py +18 -7
- infrahub/api/schema.py +32 -6
- infrahub/api/transformation.py +12 -5
- infrahub/{message_bus/messages/check_artifact_create.py → artifacts/models.py} +2 -4
- infrahub/{message_bus/operations/check/artifact.py → artifacts/tasks.py} +26 -25
- infrahub/cli/__init__.py +0 -2
- infrahub/cli/db.py +6 -7
- infrahub/cli/events.py +8 -3
- infrahub/cli/git_agent.py +9 -7
- infrahub/cli/tasks.py +4 -6
- infrahub/computed_attribute/tasks.py +63 -17
- infrahub/computed_attribute/triggers.py +90 -0
- infrahub/config.py +1 -1
- infrahub/context.py +39 -0
- infrahub/core/account.py +5 -8
- infrahub/core/attribute.py +53 -21
- infrahub/core/branch/models.py +4 -4
- infrahub/core/branch/tasks.py +89 -130
- infrahub/core/changelog/__init__.py +0 -0
- infrahub/core/changelog/diff.py +232 -0
- infrahub/core/changelog/models.py +488 -0
- infrahub/core/constants/__init__.py +19 -2
- infrahub/core/constants/infrahubkind.py +1 -0
- infrahub/core/diff/combiner.py +12 -8
- infrahub/core/diff/coordinator.py +49 -70
- infrahub/core/diff/data_check_synchronizer.py +86 -7
- infrahub/core/diff/enricher/aggregated.py +3 -3
- infrahub/core/diff/enricher/cardinality_one.py +2 -7
- infrahub/core/diff/enricher/hierarchy.py +5 -3
- infrahub/core/diff/enricher/labels.py +14 -4
- infrahub/core/diff/enricher/path_identifier.py +3 -9
- infrahub/core/diff/enricher/summary_counts.py +3 -1
- infrahub/core/diff/merger/merger.py +8 -4
- infrahub/core/diff/model/path.py +47 -29
- infrahub/core/diff/query/all_conflicts.py +6 -3
- infrahub/core/diff/query/artifact.py +1 -1
- infrahub/core/diff/query/delete_query.py +1 -1
- infrahub/core/diff/query/diff_get.py +3 -2
- infrahub/core/diff/query/diff_summary.py +1 -1
- infrahub/core/diff/query/field_specifiers.py +3 -1
- infrahub/core/diff/query/field_summary.py +3 -2
- infrahub/core/diff/query/filters.py +12 -1
- infrahub/core/diff/query/get_conflict_query.py +1 -1
- infrahub/core/diff/query/has_conflicts_query.py +6 -3
- infrahub/core/diff/query/merge.py +3 -3
- infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +4 -4
- infrahub/core/diff/query/roots_metadata.py +9 -2
- infrahub/core/diff/query/save.py +151 -66
- infrahub/core/diff/query/summary_counts_enricher.py +220 -0
- infrahub/core/diff/query/time_range_query.py +3 -2
- infrahub/core/diff/query/update_conflict_query.py +1 -1
- infrahub/core/diff/query_parser.py +49 -24
- infrahub/core/diff/repository/deserializer.py +24 -25
- infrahub/core/diff/repository/repository.py +76 -20
- infrahub/core/diff/tasks.py +9 -8
- infrahub/core/enums.py +1 -1
- infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
- infrahub/core/ipam/reconciler.py +1 -1
- infrahub/core/ipam/tasks.py +2 -3
- infrahub/core/manager.py +18 -13
- infrahub/core/merge.py +5 -2
- infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
- infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
- infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
- infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
- infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
- infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
- infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
- infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
- infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
- infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
- infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
- infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
- infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
- infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
- infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
- infrahub/core/migrations/graph/m017_add_core_profile.py +1 -1
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -2
- infrahub/core/migrations/query/attribute_add.py +1 -1
- infrahub/core/migrations/query/attribute_rename.py +1 -1
- infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
- infrahub/core/migrations/query/node_duplicate.py +1 -1
- infrahub/core/migrations/query/relationship_duplicate.py +1 -1
- infrahub/core/migrations/query/schema_attribute_update.py +1 -1
- infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
- infrahub/core/migrations/schema/node_remove.py +1 -1
- infrahub/core/migrations/schema/tasks.py +5 -5
- infrahub/core/migrations/shared.py +4 -4
- infrahub/core/models.py +7 -8
- infrahub/core/node/__init__.py +161 -40
- infrahub/core/node/base.py +1 -1
- infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
- infrahub/core/node/delete_validator.py +4 -4
- infrahub/core/node/ipam.py +13 -8
- infrahub/core/node/permissions.py +4 -0
- infrahub/core/node/resource_manager/ip_prefix_pool.py +8 -5
- infrahub/core/node/standard.py +3 -5
- infrahub/core/property.py +1 -1
- infrahub/core/protocols.py +4 -0
- infrahub/core/protocols_base.py +4 -2
- infrahub/core/query/__init__.py +2 -5
- infrahub/core/query/attribute.py +9 -9
- infrahub/core/query/branch.py +5 -5
- infrahub/core/query/delete.py +1 -1
- infrahub/core/query/diff.py +45 -7
- infrahub/core/query/ipam.py +4 -4
- infrahub/core/query/node.py +19 -14
- infrahub/core/query/relationship.py +10 -11
- infrahub/core/query/resource_manager.py +13 -11
- infrahub/core/query/standard_node.py +6 -6
- infrahub/core/query/task.py +3 -3
- infrahub/core/query/task_log.py +1 -1
- infrahub/core/query/utils.py +5 -5
- infrahub/core/registry.py +0 -2
- infrahub/core/relationship/constraints/count.py +1 -1
- infrahub/core/relationship/constraints/peer_kind.py +1 -1
- infrahub/core/relationship/model.py +66 -26
- infrahub/core/schema/__init__.py +6 -4
- infrahub/core/schema/basenode_schema.py +1 -3
- infrahub/core/schema/definitions/core.py +14 -2
- infrahub/core/schema/definitions/internal.py +16 -0
- infrahub/core/schema/generated/genericnode_schema.py +5 -0
- infrahub/core/schema/generated/node_schema.py +5 -0
- infrahub/core/schema/generic_schema.py +5 -1
- infrahub/core/schema/manager.py +45 -42
- infrahub/core/schema/node_schema.py +4 -0
- infrahub/core/schema/profile_schema.py +4 -0
- infrahub/core/schema/relationship_schema.py +2 -2
- infrahub/core/schema/schema_branch.py +248 -14
- infrahub/core/schema/template_schema.py +36 -0
- infrahub/core/task/user_task.py +7 -5
- infrahub/core/timestamp.py +1 -1
- infrahub/core/utils.py +3 -2
- infrahub/core/validators/attribute/choices.py +1 -1
- infrahub/core/validators/attribute/enum.py +1 -1
- infrahub/core/validators/attribute/kind.py +1 -1
- infrahub/core/validators/attribute/length.py +1 -1
- infrahub/core/validators/attribute/optional.py +1 -1
- infrahub/core/validators/attribute/regex.py +1 -1
- infrahub/core/validators/attribute/unique.py +1 -1
- infrahub/core/validators/checks_runner.py +37 -0
- infrahub/core/validators/node/generate_profile.py +1 -1
- infrahub/core/validators/node/hierarchy.py +1 -1
- infrahub/core/validators/query.py +1 -1
- infrahub/core/validators/relationship/count.py +1 -1
- infrahub/core/validators/relationship/optional.py +1 -1
- infrahub/core/validators/relationship/peer.py +1 -1
- infrahub/core/validators/tasks.py +8 -6
- infrahub/core/validators/uniqueness/query.py +20 -17
- infrahub/database/__init__.py +15 -2
- infrahub/database/memgraph.py +1 -1
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
- infrahub/dependencies/builder/diff/combiner.py +1 -1
- infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
- infrahub/dependencies/builder/diff/coordinator.py +0 -2
- infrahub/dependencies/builder/diff/deserializer.py +1 -1
- infrahub/dependencies/builder/diff/enricher/summary_counts.py +1 -1
- infrahub/events/branch_action.py +47 -21
- infrahub/events/group_action.py +73 -0
- infrahub/events/models.py +159 -51
- infrahub/events/node_action.py +74 -8
- infrahub/events/repository_action.py +8 -8
- infrahub/events/schema_action.py +21 -8
- infrahub/generators/tasks.py +12 -13
- infrahub/git/base.py +3 -5
- infrahub/git/constants.py +0 -1
- infrahub/git/integrator.py +36 -35
- infrahub/git/repository.py +7 -8
- infrahub/git/tasks.py +43 -107
- infrahub/git_credential/helper.py +2 -3
- infrahub/graphql/analyzer.py +572 -11
- infrahub/graphql/app.py +34 -26
- infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
- infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
- infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
- infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
- infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
- infrahub/graphql/enums.py +1 -1
- infrahub/graphql/initialization.py +5 -1
- infrahub/graphql/loaders/node.py +2 -2
- infrahub/graphql/manager.py +59 -54
- infrahub/graphql/mutations/account.py +20 -13
- infrahub/graphql/mutations/artifact_definition.py +16 -12
- infrahub/graphql/mutations/branch.py +61 -40
- infrahub/graphql/mutations/computed_attribute.py +19 -13
- infrahub/graphql/mutations/diff.py +37 -9
- infrahub/graphql/mutations/diff_conflict.py +9 -8
- infrahub/graphql/mutations/graphql_query.py +19 -11
- infrahub/graphql/mutations/ipam.py +21 -19
- infrahub/graphql/mutations/main.py +197 -44
- infrahub/graphql/mutations/menu.py +8 -8
- infrahub/graphql/mutations/proposed_change.py +36 -28
- infrahub/graphql/mutations/relationship.py +302 -105
- infrahub/graphql/mutations/repository.py +41 -35
- infrahub/graphql/mutations/resource_manager.py +26 -26
- infrahub/graphql/mutations/schema.py +51 -33
- infrahub/graphql/mutations/tasks.py +16 -10
- infrahub/graphql/parser.py +1 -1
- infrahub/graphql/permissions.py +6 -4
- infrahub/graphql/queries/account.py +22 -18
- infrahub/graphql/queries/branch.py +6 -4
- infrahub/graphql/queries/diff/tree.py +48 -42
- infrahub/graphql/queries/event.py +112 -0
- infrahub/graphql/queries/internal.py +3 -3
- infrahub/graphql/queries/ipam.py +23 -18
- infrahub/graphql/queries/relationship.py +11 -10
- infrahub/graphql/queries/resource_manager.py +43 -27
- infrahub/graphql/queries/search.py +9 -8
- infrahub/graphql/queries/status.py +12 -9
- infrahub/graphql/queries/task.py +11 -9
- infrahub/graphql/resolvers/resolver.py +69 -43
- infrahub/graphql/resolvers/single_relationship.py +16 -10
- infrahub/graphql/schema.py +2 -0
- infrahub/graphql/subscription/__init__.py +1 -1
- infrahub/graphql/subscription/events.py +1 -1
- infrahub/graphql/subscription/graphql_query.py +8 -8
- infrahub/graphql/types/branch.py +2 -2
- infrahub/graphql/types/common.py +6 -1
- infrahub/graphql/types/enums.py +2 -0
- infrahub/graphql/types/event.py +100 -0
- infrahub/graphql/types/interface.py +2 -2
- infrahub/graphql/types/node.py +3 -3
- infrahub/graphql/types/permission.py +2 -2
- infrahub/graphql/types/relationship.py +3 -3
- infrahub/graphql/types/standard_node.py +9 -11
- infrahub/graphql/utils.py +28 -182
- infrahub/groups/tasks.py +2 -3
- infrahub/lock.py +1 -1
- infrahub/menu/constants.py +1 -0
- infrahub/menu/generator.py +14 -3
- infrahub/menu/menu.py +116 -127
- infrahub/menu/models.py +4 -4
- infrahub/message_bus/messages/__init__.py +0 -4
- infrahub/message_bus/messages/event_branch_merge.py +3 -0
- infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
- infrahub/message_bus/operations/__init__.py +3 -5
- infrahub/message_bus/operations/check/__init__.py +2 -2
- infrahub/message_bus/operations/check/generator.py +1 -3
- infrahub/message_bus/operations/check/repository.py +1 -1
- infrahub/message_bus/operations/event/branch.py +7 -3
- infrahub/message_bus/operations/event/schema.py +1 -1
- infrahub/message_bus/operations/finalize/validator.py +1 -1
- infrahub/message_bus/operations/git/file.py +2 -2
- infrahub/message_bus/operations/git/repository.py +1 -1
- infrahub/message_bus/operations/requests/__init__.py +0 -2
- infrahub/message_bus/operations/requests/generator_definition.py +1 -1
- infrahub/message_bus/operations/requests/proposed_change.py +26 -11
- infrahub/message_bus/operations/requests/repository.py +2 -2
- infrahub/message_bus/operations/send/echo.py +1 -1
- infrahub/message_bus/types.py +1 -1
- infrahub/permissions/__init__.py +2 -1
- infrahub/permissions/types.py +26 -0
- infrahub/pools/prefix.py +29 -165
- infrahub/prefect_server/__init__.py +0 -0
- infrahub/prefect_server/app.py +18 -0
- infrahub/prefect_server/database.py +20 -0
- infrahub/prefect_server/events.py +28 -0
- infrahub/prefect_server/models.py +46 -0
- infrahub/proposed_change/models.py +15 -1
- infrahub/proposed_change/tasks.py +173 -35
- infrahub/pytest_plugin.py +4 -4
- infrahub/server.py +12 -11
- infrahub/services/__init__.py +147 -62
- infrahub/services/adapters/cache/__init__.py +7 -5
- infrahub/services/adapters/cache/nats.py +40 -22
- infrahub/services/adapters/cache/redis.py +0 -4
- infrahub/services/adapters/event/__init__.py +10 -18
- infrahub/services/adapters/http/__init__.py +0 -5
- infrahub/services/adapters/http/httpx.py +22 -15
- infrahub/services/adapters/message_bus/__init__.py +23 -6
- infrahub/services/adapters/message_bus/local.py +8 -6
- infrahub/services/adapters/message_bus/nats.py +12 -6
- infrahub/services/adapters/message_bus/rabbitmq.py +22 -9
- infrahub/services/adapters/workflow/__init__.py +11 -8
- infrahub/services/adapters/workflow/local.py +28 -7
- infrahub/services/adapters/workflow/worker.py +23 -7
- infrahub/services/component.py +38 -35
- infrahub/services/scheduler.py +32 -29
- infrahub/storage.py +2 -4
- infrahub/task_manager/constants.py +1 -1
- infrahub/task_manager/event.py +182 -0
- infrahub/task_manager/models.py +125 -1
- infrahub/task_manager/task.py +1 -1
- infrahub/tasks/artifact.py +14 -16
- infrahub/tasks/registry.py +1 -1
- infrahub/tasks/telemetry.py +13 -14
- infrahub/transformations/tasks.py +3 -5
- infrahub/trigger/__init__.py +0 -0
- infrahub/trigger/catalogue.py +15 -0
- infrahub/trigger/constants.py +9 -0
- infrahub/trigger/models.py +69 -0
- infrahub/trigger/tasks.py +85 -0
- infrahub/types.py +1 -1
- infrahub/utils.py +1 -1
- infrahub/webhook/constants.py +0 -2
- infrahub/webhook/models.py +8 -2
- infrahub/webhook/tasks.py +20 -73
- infrahub/webhook/triggers.py +20 -0
- infrahub/workers/infrahub_async.py +36 -25
- infrahub/workers/utils.py +63 -0
- infrahub/workflows/catalogue.py +13 -37
- infrahub/workflows/initialization.py +6 -8
- infrahub/workflows/models.py +3 -5
- infrahub/workflows/utils.py +1 -1
- infrahub_sdk/ctl/check.py +3 -3
- infrahub_sdk/ctl/cli_commands.py +11 -10
- infrahub_sdk/ctl/exceptions.py +0 -6
- infrahub_sdk/ctl/exporter.py +1 -1
- infrahub_sdk/ctl/generator.py +5 -5
- infrahub_sdk/ctl/importer.py +3 -2
- infrahub_sdk/ctl/menu.py +1 -1
- infrahub_sdk/ctl/object.py +1 -1
- infrahub_sdk/ctl/repository.py +23 -15
- infrahub_sdk/ctl/schema.py +2 -2
- infrahub_sdk/ctl/utils.py +4 -3
- infrahub_sdk/ctl/validate.py +2 -1
- infrahub_sdk/exceptions.py +6 -0
- infrahub_sdk/generator.py +3 -0
- infrahub_sdk/node.py +2 -2
- infrahub_sdk/schema/__init__.py +14 -2
- infrahub_sdk/schema/main.py +7 -0
- infrahub_sdk/utils.py +11 -1
- infrahub_sdk/yaml.py +2 -3
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/METADATA +46 -12
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/RECORD +338 -321
- infrahub_testcontainers/container.py +14 -6
- infrahub_testcontainers/docker-compose.test.yml +24 -5
- infrahub_testcontainers/haproxy.cfg +43 -0
- infrahub_testcontainers/helpers.py +85 -1
- infrahub/core/branch/constants.py +0 -2
- infrahub/graphql/query.py +0 -52
- infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
- infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
- infrahub/schema/constants.py +0 -1
- infrahub/schema/tasks.py +0 -76
- infrahub/services/adapters/database/__init__.py +0 -9
- infrahub_sdk/ctl/_file.py +0 -13
- /infrahub/{schema → artifacts}/__init__.py +0 -0
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/entry_points.txt +0 -0
infrahub/services/__init__.py
CHANGED
|
@@ -1,50 +1,168 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from typing import TYPE_CHECKING, Awaitable, Callable, Optional
|
|
4
4
|
|
|
5
5
|
from infrahub.components import ComponentType
|
|
6
|
-
from infrahub.database import InfrahubDatabase
|
|
7
6
|
from infrahub.exceptions import InitializationError
|
|
8
7
|
from infrahub.log import get_logger
|
|
9
|
-
from infrahub.message_bus import InfrahubMessage, InfrahubResponse
|
|
10
8
|
from infrahub.message_bus.messages import ROUTING_KEY_MAP
|
|
11
|
-
from infrahub.message_bus.types import MessageTTL
|
|
12
9
|
|
|
13
|
-
from .adapters.cache import InfrahubCache
|
|
14
10
|
from .adapters.event import InfrahubEventService
|
|
15
|
-
from .adapters.http import InfrahubHTTP
|
|
16
11
|
from .adapters.http.httpx import HttpxAdapter
|
|
17
|
-
from .adapters.
|
|
18
|
-
from .adapters.workflow import
|
|
12
|
+
from .adapters.workflow.local import WorkflowLocalExecution
|
|
13
|
+
from .adapters.workflow.worker import WorkflowWorkerExecution
|
|
19
14
|
from .component import InfrahubComponent
|
|
20
|
-
from .protocols import InfrahubLogger
|
|
21
15
|
from .scheduler import InfrahubScheduler
|
|
22
16
|
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from infrahub_sdk import InfrahubClient
|
|
19
|
+
|
|
20
|
+
from infrahub.database import InfrahubDatabase
|
|
21
|
+
from infrahub.message_bus import InfrahubMessage
|
|
22
|
+
from infrahub.message_bus.types import MessageTTL
|
|
23
|
+
|
|
24
|
+
from .adapters.cache import InfrahubCache
|
|
25
|
+
from .adapters.http import InfrahubHTTP
|
|
26
|
+
from .adapters.message_bus import InfrahubMessageBus
|
|
27
|
+
from .adapters.workflow import InfrahubWorkflow
|
|
28
|
+
from .protocols import InfrahubLogger
|
|
29
|
+
|
|
23
30
|
|
|
24
31
|
class InfrahubServices:
|
|
32
|
+
_cache: InfrahubCache | None
|
|
33
|
+
_client: InfrahubClient | None
|
|
34
|
+
_database: InfrahubDatabase | None
|
|
35
|
+
_message_bus: InfrahubMessageBus | None
|
|
36
|
+
_workflow: InfrahubWorkflow | None
|
|
37
|
+
_component: InfrahubComponent | None
|
|
38
|
+
|
|
39
|
+
log: InfrahubLogger
|
|
40
|
+
component_type: ComponentType
|
|
41
|
+
http: InfrahubHTTP
|
|
42
|
+
event: InfrahubEventService
|
|
43
|
+
scheduler: InfrahubScheduler
|
|
44
|
+
|
|
25
45
|
def __init__(
|
|
26
46
|
self,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
log: InfrahubLogger,
|
|
48
|
+
component_type: ComponentType,
|
|
49
|
+
http: InfrahubHTTP,
|
|
50
|
+
event: InfrahubEventService,
|
|
51
|
+
scheduler: InfrahubScheduler,
|
|
52
|
+
cache: InfrahubCache | None = None,
|
|
53
|
+
client: InfrahubClient | None = None,
|
|
54
|
+
database: InfrahubDatabase | None = None,
|
|
55
|
+
message_bus: InfrahubMessageBus | None = None,
|
|
56
|
+
workflow: InfrahubWorkflow | None = None,
|
|
57
|
+
):
|
|
58
|
+
"""
|
|
59
|
+
This method should not be called directly, use `new` instead for a proper initialization.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
self._cache = cache
|
|
38
63
|
self._client = client
|
|
39
64
|
self._database = database
|
|
40
|
-
self.
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
self.
|
|
45
|
-
self.
|
|
46
|
-
self.scheduler =
|
|
47
|
-
self.
|
|
65
|
+
self._message_bus = message_bus
|
|
66
|
+
self._workflow = workflow
|
|
67
|
+
self.log = log
|
|
68
|
+
self.component_type = component_type
|
|
69
|
+
self.http = http
|
|
70
|
+
self.event = event
|
|
71
|
+
self.scheduler = scheduler
|
|
72
|
+
self._component = None
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
async def new(
|
|
76
|
+
cls,
|
|
77
|
+
cache: InfrahubCache | None = None,
|
|
78
|
+
client: InfrahubClient | None = None,
|
|
79
|
+
database: InfrahubDatabase | None = None,
|
|
80
|
+
event: InfrahubEventService | None = None,
|
|
81
|
+
message_bus: InfrahubMessageBus | None = None,
|
|
82
|
+
workflow: InfrahubWorkflow | None = None,
|
|
83
|
+
log: InfrahubLogger | None = None,
|
|
84
|
+
component_type: ComponentType | None = None,
|
|
85
|
+
http: InfrahubHTTP | None = None,
|
|
86
|
+
) -> InfrahubServices:
|
|
87
|
+
"""
|
|
88
|
+
Instantiate InfrahubServices object, and finalize initializations of underlying services having a circular
|
|
89
|
+
dependency with InfrahubServices.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
component_type = component_type or ComponentType.NONE
|
|
93
|
+
|
|
94
|
+
scheduler = InfrahubScheduler(component_type)
|
|
95
|
+
service = cls(
|
|
96
|
+
cache=cache,
|
|
97
|
+
client=client,
|
|
98
|
+
database=database,
|
|
99
|
+
message_bus=message_bus,
|
|
100
|
+
workflow=workflow,
|
|
101
|
+
log=log or get_logger(),
|
|
102
|
+
component_type=component_type,
|
|
103
|
+
scheduler=scheduler,
|
|
104
|
+
event=event or InfrahubEventService(message_bus),
|
|
105
|
+
http=http or HttpxAdapter(),
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# This circular dependency could be removed if InfrahubScheduler only depends on what it needs.
|
|
109
|
+
scheduler.service = service
|
|
110
|
+
|
|
111
|
+
if message_bus is not None:
|
|
112
|
+
# Need circular dependency for injecting `service` within `execute_message`. This might be removed
|
|
113
|
+
# using proper dependency injections.
|
|
114
|
+
message_bus.service = service
|
|
115
|
+
|
|
116
|
+
if cache is not None and database is not None:
|
|
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
|
|
136
|
+
|
|
137
|
+
return service
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def component(self) -> InfrahubComponent:
|
|
141
|
+
if not self._component:
|
|
142
|
+
raise InitializationError("Service is not initialized with a component")
|
|
143
|
+
|
|
144
|
+
return self._component
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def message_bus(self) -> InfrahubMessageBus:
|
|
148
|
+
if not self._message_bus:
|
|
149
|
+
raise InitializationError("Service is not initialized with a message bus")
|
|
150
|
+
|
|
151
|
+
return self._message_bus
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def workflow(self) -> InfrahubWorkflow:
|
|
155
|
+
if not self._workflow:
|
|
156
|
+
raise InitializationError("Service is not initialized with a workflow")
|
|
157
|
+
|
|
158
|
+
return self._workflow
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def cache(self) -> InfrahubCache:
|
|
162
|
+
if not self._cache:
|
|
163
|
+
raise InitializationError("Service is not initialized with a cache")
|
|
164
|
+
|
|
165
|
+
return self._cache
|
|
48
166
|
|
|
49
167
|
@property
|
|
50
168
|
def client(self) -> InfrahubClient:
|
|
@@ -53,9 +171,6 @@ class InfrahubServices:
|
|
|
53
171
|
|
|
54
172
|
return self._client
|
|
55
173
|
|
|
56
|
-
def set_client(self, client: InfrahubClient | None) -> None:
|
|
57
|
-
self._client = client
|
|
58
|
-
|
|
59
174
|
@property
|
|
60
175
|
def database(self) -> InfrahubDatabase:
|
|
61
176
|
if not self._database:
|
|
@@ -63,18 +178,7 @@ class InfrahubServices:
|
|
|
63
178
|
|
|
64
179
|
return self._database
|
|
65
180
|
|
|
66
|
-
async def initialize(self) -> None:
|
|
67
|
-
"""Initialize the Services"""
|
|
68
|
-
await self.message_bus.initialize(service=self)
|
|
69
|
-
await self.cache.initialize(service=self)
|
|
70
|
-
await self.http.initialize(service=self)
|
|
71
|
-
await self.component.initialize(service=self)
|
|
72
|
-
await self.scheduler.initialize(service=self)
|
|
73
|
-
await self.workflow.initialize(service=self)
|
|
74
|
-
await self.event.initialize(service=self)
|
|
75
|
-
|
|
76
181
|
async def shutdown(self) -> None:
|
|
77
|
-
"""Initialize the Services"""
|
|
78
182
|
await self.scheduler.shutdown()
|
|
79
183
|
await self.message_bus.shutdown()
|
|
80
184
|
|
|
@@ -84,24 +188,5 @@ class InfrahubServices:
|
|
|
84
188
|
raise ValueError("Unable to determine routing key")
|
|
85
189
|
await self.message_bus.publish(message, routing_key=routing_key, delay=delay, is_retry=is_retry)
|
|
86
190
|
|
|
87
|
-
async def reply(self, message: InfrahubResponse, initiator: InfrahubMessage) -> None:
|
|
88
|
-
if initiator.meta:
|
|
89
|
-
message.meta.correlation_id = initiator.meta.correlation_id
|
|
90
|
-
routing_key = initiator.meta.reply_to or ""
|
|
91
|
-
await self.message_bus.reply(message, routing_key=routing_key)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class ServiceManager:
|
|
95
|
-
def __init__(self) -> None:
|
|
96
|
-
self.service = InfrahubServices()
|
|
97
|
-
self.send = self.service.send
|
|
98
|
-
|
|
99
|
-
def prepare(self, service: InfrahubServices) -> None:
|
|
100
|
-
self.service = service
|
|
101
|
-
self.send = self.service.send
|
|
102
|
-
|
|
103
191
|
|
|
104
192
|
ServiceFunction = Callable[[InfrahubServices], Awaitable[None]]
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
services = ServiceManager()
|
|
@@ -1,34 +1,36 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
3
4
|
from typing import TYPE_CHECKING, Optional
|
|
4
5
|
|
|
5
6
|
if TYPE_CHECKING:
|
|
6
7
|
from infrahub.message_bus.types import KVTTL
|
|
7
|
-
from infrahub.services import InfrahubServices
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class InfrahubCache:
|
|
10
|
+
class InfrahubCache(ABC):
|
|
11
11
|
"""Base class for caching services"""
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
"""Initialize the cache"""
|
|
15
|
-
|
|
13
|
+
@abstractmethod
|
|
16
14
|
async def delete(self, key: str) -> None:
|
|
17
15
|
"""Delete a key from the cache."""
|
|
18
16
|
raise NotImplementedError()
|
|
19
17
|
|
|
18
|
+
@abstractmethod
|
|
20
19
|
async def get(self, key: str) -> Optional[str]:
|
|
21
20
|
"""Retrieve a value from the cache."""
|
|
22
21
|
raise NotImplementedError()
|
|
23
22
|
|
|
23
|
+
@abstractmethod
|
|
24
24
|
async def get_values(self, keys: list[str]) -> list[Optional[str]]:
|
|
25
25
|
"""Return a list the values for requested keys."""
|
|
26
26
|
raise NotImplementedError()
|
|
27
27
|
|
|
28
|
+
@abstractmethod
|
|
28
29
|
async def list_keys(self, filter_pattern: str) -> list[str]:
|
|
29
30
|
"""Return a list of active keys that match the provided filter."""
|
|
30
31
|
raise NotImplementedError()
|
|
31
32
|
|
|
33
|
+
@abstractmethod
|
|
32
34
|
async def set(
|
|
33
35
|
self, key: str, value: str, expires: Optional[KVTTL] = None, not_exists: bool = False
|
|
34
36
|
) -> Optional[bool]:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import ssl
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Optional
|
|
5
5
|
|
|
6
6
|
import nats
|
|
7
7
|
|
|
@@ -9,26 +9,38 @@ from infrahub import config
|
|
|
9
9
|
from infrahub.message_bus.types import KVTTL
|
|
10
10
|
from infrahub.services.adapters.cache import InfrahubCache
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
from infrahub.services import InfrahubServices
|
|
12
|
+
# Inherit from BaseModel to avoid implementing a `__init__` otherwise `cls(...)` fails.
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
class NATSCache(InfrahubCache):
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
connection: nats.NATS
|
|
17
|
+
jetstream: nats.js.JetStreamContext
|
|
18
|
+
kv: dict[int, nats.js.kv.KeyValue]
|
|
19
|
+
kv_buckets: dict[str, KVTTL]
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
connection: nats.NATS,
|
|
24
|
+
jetstream: nats.js.JetStreamContext,
|
|
25
|
+
kv: dict[int, nats.js.kv.KeyValue],
|
|
26
|
+
kv_buckets: dict[str, KVTTL],
|
|
27
|
+
):
|
|
28
|
+
self.connection = connection
|
|
29
|
+
self.jetstream = jetstream
|
|
30
|
+
self.kv = kv
|
|
31
|
+
self.kv_buckets = kv_buckets
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
async def new(cls) -> NATSCache:
|
|
22
35
|
# FIXME: remove once NATS supports TTL for keys (2.11)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
36
|
+
kv_buckets = {
|
|
37
|
+
NATSCache._tokenize_key_name("validator_execution_id:"): KVTTL.TWO_HOURS,
|
|
38
|
+
NATSCache._tokenize_key_name("workers:primary:"): KVTTL.FIFTEEN,
|
|
39
|
+
NATSCache._tokenize_key_name("workers:schema_hash:branch:"): KVTTL.TWO_HOURS,
|
|
40
|
+
NATSCache._tokenize_key_name("workers:active:"): KVTTL.FIFTEEN,
|
|
41
|
+
NATSCache._tokenize_key_name("workers:worker:"): KVTTL.TWO_HOURS,
|
|
29
42
|
}
|
|
30
43
|
|
|
31
|
-
async def initialize(self, service: InfrahubServices) -> None:
|
|
32
44
|
tls_context = None
|
|
33
45
|
if config.SETTINGS.cache.tls_enabled:
|
|
34
46
|
tls_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
|
|
@@ -38,25 +50,27 @@ class NATSCache(InfrahubCache):
|
|
|
38
50
|
tls_context.check_hostname = False
|
|
39
51
|
tls_context.verify_mode = ssl.CERT_NONE
|
|
40
52
|
|
|
41
|
-
|
|
53
|
+
connection = await nats.connect(
|
|
42
54
|
f"nats://{config.SETTINGS.cache.address}:{config.SETTINGS.cache.service_port}",
|
|
43
55
|
user=config.SETTINGS.cache.username,
|
|
44
56
|
password=config.SETTINGS.cache.password,
|
|
45
57
|
tls=tls_context,
|
|
46
58
|
)
|
|
47
|
-
|
|
48
|
-
self.jetstream = self.connection.jetstream()
|
|
59
|
+
jetstream = connection.jetstream()
|
|
49
60
|
|
|
50
61
|
kv_config = nats.js.api.KeyValueConfig(bucket=f"kv_{config.SETTINGS.cache.database}")
|
|
51
|
-
|
|
62
|
+
kv = {0: await jetstream.create_key_value(config=kv_config)}
|
|
52
63
|
|
|
53
64
|
# FIXME: remove once NATS supports TTL for keys (2.11)
|
|
54
65
|
for ttl in KVTTL.variations():
|
|
55
66
|
kv_config.bucket = f"kv_{config.SETTINGS.cache.database}_ttl_{ttl.name.lower()}"
|
|
56
67
|
kv_config.ttl = ttl.value
|
|
57
|
-
|
|
68
|
+
kv[ttl.value] = await jetstream.create_key_value(config=kv_config)
|
|
69
|
+
|
|
70
|
+
return cls(kv_buckets=kv_buckets, kv=kv, connection=connection, jetstream=jetstream)
|
|
58
71
|
|
|
59
|
-
|
|
72
|
+
@staticmethod
|
|
73
|
+
def _tokenize_key_name(key: str) -> str:
|
|
60
74
|
return key.replace(":", ".")
|
|
61
75
|
|
|
62
76
|
# FIXME: remove once NATS supports TTL for keys (2.11)
|
|
@@ -121,7 +135,11 @@ class NATSCache(InfrahubCache):
|
|
|
121
135
|
return [key.replace(".", ":") for key in keys]
|
|
122
136
|
|
|
123
137
|
async def set(
|
|
124
|
-
self,
|
|
138
|
+
self,
|
|
139
|
+
key: str,
|
|
140
|
+
value: str,
|
|
141
|
+
expires: Optional[KVTTL] = None, # noqa: ARG002
|
|
142
|
+
not_exists: bool = False,
|
|
125
143
|
) -> Optional[bool]:
|
|
126
144
|
key = self._tokenize_key_name(key)
|
|
127
145
|
if not_exists:
|
|
@@ -4,7 +4,6 @@ import redis.asyncio as redis
|
|
|
4
4
|
|
|
5
5
|
from infrahub import config
|
|
6
6
|
from infrahub.message_bus.types import KVTTL
|
|
7
|
-
from infrahub.services import InfrahubServices
|
|
8
7
|
from infrahub.services.adapters.cache import InfrahubCache
|
|
9
8
|
|
|
10
9
|
|
|
@@ -20,9 +19,6 @@ class RedisCache(InfrahubCache):
|
|
|
20
19
|
ssl_ca_certs=config.SETTINGS.cache.tls_ca_file,
|
|
21
20
|
)
|
|
22
21
|
|
|
23
|
-
async def initialize(self, service: InfrahubServices) -> None:
|
|
24
|
-
pass
|
|
25
|
-
|
|
26
22
|
async def delete(self, key: str) -> None:
|
|
27
23
|
await self.connection.delete(key)
|
|
28
24
|
|
|
@@ -5,29 +5,18 @@ from typing import TYPE_CHECKING
|
|
|
5
5
|
|
|
6
6
|
from prefect.events import emit_event
|
|
7
7
|
|
|
8
|
-
from infrahub.exceptions import InitializationError
|
|
9
|
-
|
|
10
8
|
if TYPE_CHECKING:
|
|
11
9
|
from infrahub.events import InfrahubEvent
|
|
12
|
-
from infrahub.services import
|
|
10
|
+
from infrahub.services import InfrahubMessageBus
|
|
13
11
|
|
|
14
12
|
|
|
15
13
|
class InfrahubEventService:
|
|
16
14
|
"""Base class for infrahub event service"""
|
|
17
15
|
|
|
18
|
-
def __init__(self) -> None:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def service(self) -> InfrahubServices:
|
|
23
|
-
if not self._service:
|
|
24
|
-
raise InitializationError("Event is not initialized with a service")
|
|
25
|
-
|
|
26
|
-
return self._service
|
|
27
|
-
|
|
28
|
-
async def initialize(self, service: InfrahubServices) -> None:
|
|
29
|
-
"""Initialize the event service"""
|
|
30
|
-
self._service = service
|
|
16
|
+
def __init__(self, message_bus: InfrahubMessageBus | None = None) -> None:
|
|
17
|
+
# Ideally message_bus should not be optional, we let it like this for existing tests that
|
|
18
|
+
# pass without a bus as corresponding tested events do not send bus messages.
|
|
19
|
+
self.message_bus = message_bus
|
|
31
20
|
|
|
32
21
|
async def send(self, event: InfrahubEvent) -> None:
|
|
33
22
|
tasks = [self._send_bus(event=event), self._send_prefect(event=event)]
|
|
@@ -35,12 +24,15 @@ class InfrahubEventService:
|
|
|
35
24
|
|
|
36
25
|
async def _send_bus(self, event: InfrahubEvent) -> None:
|
|
37
26
|
for message in event.get_messages():
|
|
38
|
-
|
|
27
|
+
if self.message_bus is None:
|
|
28
|
+
raise ValueError("InfrahubEventService.message_bus is None.")
|
|
29
|
+
await self.message_bus.send(message=message)
|
|
39
30
|
|
|
40
31
|
async def _send_prefect(self, event: InfrahubEvent) -> None:
|
|
41
32
|
emit_event(
|
|
33
|
+
id=event.meta.id,
|
|
42
34
|
event=event.get_name(),
|
|
43
35
|
resource=event.get_resource(),
|
|
44
36
|
related=event.get_related(),
|
|
45
|
-
payload=event.
|
|
37
|
+
payload=event.get_event_payload(),
|
|
46
38
|
)
|
|
@@ -5,13 +5,8 @@ from typing import TYPE_CHECKING, Any
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
6
|
import httpx
|
|
7
7
|
|
|
8
|
-
from infrahub.services import InfrahubServices
|
|
9
|
-
|
|
10
8
|
|
|
11
9
|
class InfrahubHTTP:
|
|
12
|
-
async def initialize(self, service: InfrahubServices) -> None:
|
|
13
|
-
"""Initialize the HTTP adapter"""
|
|
14
|
-
|
|
15
10
|
async def get(
|
|
16
11
|
self,
|
|
17
12
|
url: str,
|
|
@@ -2,30 +2,37 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import ssl
|
|
4
4
|
from functools import cached_property
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Any
|
|
6
6
|
|
|
7
7
|
import httpx
|
|
8
8
|
|
|
9
9
|
from infrahub import config
|
|
10
10
|
from infrahub.exceptions import HTTPServerError, HTTPServerSSLError, HTTPServerTimeoutError
|
|
11
|
+
from infrahub.log import get_logger
|
|
11
12
|
from infrahub.services.adapters.http import InfrahubHTTP
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
from infrahub.services import InfrahubServices
|
|
14
|
+
log = get_logger()
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class HttpxAdapter(InfrahubHTTP):
|
|
18
|
-
|
|
19
|
-
service: InfrahubServices
|
|
18
|
+
"""The HttpxAdapter is a generic interface for InfrahubHTTP
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
The class provides a way to send HTTP requests from Infrahub for example
|
|
21
|
+
when sending webhooks, telemetry data or when communicating with SSO
|
|
22
|
+
providers. The main purpose is to have a single location to manage
|
|
23
|
+
configuration and error handling with regards to HTTP traffic and
|
|
24
|
+
allow users to define configurations such as timeout, TLS options
|
|
25
|
+
and eventually proxy settings in one location."""
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
_settings: config.HTTPSettings | None = None
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def settings(self) -> config.HTTPSettings:
|
|
31
|
+
if self._settings:
|
|
32
|
+
return self._settings
|
|
33
|
+
|
|
34
|
+
self._settings = config.SETTINGS.http
|
|
35
|
+
return self._settings
|
|
29
36
|
|
|
30
37
|
@cached_property
|
|
31
38
|
def tls_context(self) -> ssl.SSLContext:
|
|
@@ -62,16 +69,16 @@ class HttpxAdapter(InfrahubHTTP):
|
|
|
62
69
|
**params,
|
|
63
70
|
)
|
|
64
71
|
except ssl.SSLCertVerificationError as exc:
|
|
65
|
-
|
|
72
|
+
log.info(f"TLS verification failed for connection to {url}")
|
|
66
73
|
raise HTTPServerSSLError(message=f"Unable to validate TLS certificate for connection to {url}") from exc
|
|
67
74
|
except httpx.ReadTimeout as exc:
|
|
68
|
-
|
|
75
|
+
log.info(f"Connection timed out when trying to reach {url}")
|
|
69
76
|
raise HTTPServerTimeoutError(
|
|
70
77
|
message=f"Connection to {url} timed out after {self.settings.timeout}"
|
|
71
78
|
) from exc
|
|
72
79
|
except httpx.RequestError as exc:
|
|
73
80
|
# Catch all error from httpx
|
|
74
|
-
|
|
81
|
+
log.warning(f"Unhandled HTTP error for {url} ({exc})")
|
|
75
82
|
raise HTTPServerError(message=f"Unknown http error when connecting to {url}") from exc
|
|
76
83
|
|
|
77
84
|
return response
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
3
4
|
from typing import TYPE_CHECKING, Optional, TypeVar
|
|
4
5
|
|
|
6
|
+
from infrahub.message_bus.messages import ROUTING_KEY_MAP
|
|
7
|
+
|
|
5
8
|
ResponseClass = TypeVar("ResponseClass")
|
|
6
9
|
|
|
7
10
|
if TYPE_CHECKING:
|
|
8
|
-
from infrahub.message_bus import InfrahubMessage
|
|
11
|
+
from infrahub.message_bus import InfrahubMessage, InfrahubResponse
|
|
9
12
|
from infrahub.message_bus.types import MessageTTL
|
|
10
13
|
from infrahub.services import InfrahubServices
|
|
11
14
|
|
|
12
15
|
|
|
13
|
-
class InfrahubMessageBus:
|
|
16
|
+
class InfrahubMessageBus(ABC):
|
|
14
17
|
DELIVER_TIMEOUT: int = 30 * 60 # 30 minutes
|
|
15
18
|
worker_bindings: list[str] = [
|
|
16
19
|
"check.*.*",
|
|
@@ -26,20 +29,34 @@ class InfrahubMessageBus:
|
|
|
26
29
|
]
|
|
27
30
|
event_bindings: list[str] = ["refresh.registry.*"]
|
|
28
31
|
broadcasted_event_bindings: list[str] = ["refresh.git.*"]
|
|
32
|
+
service: InfrahubServices
|
|
29
33
|
|
|
30
|
-
async def
|
|
31
|
-
"""Initialize the Message bus"""
|
|
32
|
-
|
|
33
|
-
async def shutdown(self) -> None:
|
|
34
|
+
async def shutdown(self) -> None: # noqa: B027 We want a default empty behavior, so it's ok to have an empty non-abstract method.
|
|
34
35
|
"""Shutdown the Message bus"""
|
|
35
36
|
|
|
37
|
+
@abstractmethod
|
|
36
38
|
async def publish(
|
|
37
39
|
self, message: InfrahubMessage, routing_key: str, delay: Optional[MessageTTL] = None, is_retry: bool = False
|
|
38
40
|
) -> None:
|
|
39
41
|
raise NotImplementedError()
|
|
40
42
|
|
|
43
|
+
@abstractmethod
|
|
41
44
|
async def reply(self, message: InfrahubMessage, routing_key: str) -> None:
|
|
42
45
|
raise NotImplementedError()
|
|
43
46
|
|
|
47
|
+
@abstractmethod
|
|
44
48
|
async def rpc(self, message: InfrahubMessage, response_class: type[ResponseClass]) -> ResponseClass:
|
|
45
49
|
raise NotImplementedError()
|
|
50
|
+
|
|
51
|
+
async def send(self, message: InfrahubMessage, delay: Optional[MessageTTL] = None, is_retry: bool = False) -> None:
|
|
52
|
+
routing_key = ROUTING_KEY_MAP.get(type(message))
|
|
53
|
+
if not routing_key:
|
|
54
|
+
raise ValueError("Unable to determine routing key")
|
|
55
|
+
await self.publish(message, routing_key=routing_key, delay=delay, is_retry=is_retry)
|
|
56
|
+
|
|
57
|
+
# TODO rename it
|
|
58
|
+
async def reply_if_initiator_meta(self, message: InfrahubResponse, initiator: InfrahubMessage) -> None:
|
|
59
|
+
if initiator.meta:
|
|
60
|
+
message.meta.correlation_id = initiator.meta.correlation_id
|
|
61
|
+
routing_key = initiator.meta.reply_to or ""
|
|
62
|
+
await self.reply(message, routing_key=routing_key)
|
|
@@ -10,34 +10,36 @@ from infrahub.dependencies.registry import build_component_registry
|
|
|
10
10
|
from infrahub.message_bus import InfrahubMessage, Meta
|
|
11
11
|
from infrahub.message_bus.messages import ROUTING_KEY_MAP
|
|
12
12
|
from infrahub.message_bus.operations import execute_message
|
|
13
|
-
from infrahub.services import InfrahubServices
|
|
14
13
|
from infrahub.services.adapters.message_bus import InfrahubMessageBus
|
|
15
14
|
|
|
16
15
|
if TYPE_CHECKING:
|
|
17
|
-
from infrahub.database import InfrahubDatabase
|
|
18
16
|
from infrahub.message_bus.types import MessageTTL
|
|
19
17
|
|
|
20
18
|
ResponseClass = TypeVar("ResponseClass")
|
|
21
19
|
|
|
22
20
|
|
|
23
21
|
class BusSimulator(InfrahubMessageBus):
|
|
24
|
-
def __init__(self
|
|
22
|
+
def __init__(self) -> None:
|
|
25
23
|
self.messages: list[InfrahubMessage] = []
|
|
26
24
|
self.messages_per_routing_key: dict[str, list[InfrahubMessage]] = {}
|
|
27
|
-
self.service: InfrahubServices = InfrahubServices(database=database, message_bus=self)
|
|
28
25
|
self.replies: dict[str, list[InfrahubMessage]] = defaultdict(list)
|
|
29
26
|
build_component_registry()
|
|
30
27
|
|
|
31
28
|
async def publish(
|
|
32
|
-
self,
|
|
29
|
+
self,
|
|
30
|
+
message: InfrahubMessage,
|
|
31
|
+
routing_key: str,
|
|
32
|
+
delay: Optional[MessageTTL] = None, # noqa: ARG002
|
|
33
|
+
is_retry: bool = False, # noqa: ARG002
|
|
33
34
|
) -> None:
|
|
34
35
|
self.messages.append(message)
|
|
35
36
|
if routing_key not in self.messages_per_routing_key:
|
|
36
37
|
self.messages_per_routing_key[routing_key] = []
|
|
37
38
|
self.messages_per_routing_key[routing_key].append(message)
|
|
39
|
+
assert self.service is not None
|
|
38
40
|
await execute_message(routing_key=routing_key, message_body=message.body, service=self.service)
|
|
39
41
|
|
|
40
|
-
async def reply(self, message: InfrahubMessage, routing_key: str) -> None:
|
|
42
|
+
async def reply(self, message: InfrahubMessage, routing_key: str) -> None: # noqa: ARG002
|
|
41
43
|
correlation_id = message.meta.correlation_id or "default"
|
|
42
44
|
self.replies[correlation_id].append(message)
|
|
43
45
|
|