infrahub-server 1.2.0rc0__py3-none-any.whl → 1.2.1__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/dependencies.py +6 -6
- infrahub/api/diff/validation_models.py +7 -7
- infrahub/api/schema.py +1 -1
- infrahub/artifacts/models.py +5 -3
- infrahub/artifacts/tasks.py +3 -5
- infrahub/cli/__init__.py +13 -9
- infrahub/cli/constants.py +3 -0
- infrahub/cli/db.py +165 -183
- infrahub/cli/upgrade.py +146 -0
- infrahub/computed_attribute/gather.py +185 -0
- infrahub/computed_attribute/models.py +240 -12
- infrahub/computed_attribute/tasks.py +77 -441
- infrahub/computed_attribute/triggers.py +13 -47
- infrahub/config.py +43 -32
- infrahub/context.py +14 -0
- infrahub/core/account.py +4 -4
- infrahub/core/attribute.py +58 -58
- infrahub/core/branch/tasks.py +74 -22
- infrahub/core/changelog/diff.py +95 -36
- infrahub/core/changelog/models.py +217 -43
- infrahub/core/constants/__init__.py +28 -0
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/constants/schema.py +2 -0
- infrahub/core/constraint/node/runner.py +9 -8
- infrahub/core/diff/branch_differ.py +10 -10
- infrahub/core/diff/enricher/cardinality_one.py +5 -0
- infrahub/core/diff/enricher/hierarchy.py +17 -4
- infrahub/core/diff/enricher/labels.py +5 -0
- infrahub/core/diff/enricher/path_identifier.py +4 -0
- infrahub/core/diff/ipam_diff_parser.py +4 -5
- infrahub/core/diff/model/diff.py +27 -27
- infrahub/core/diff/model/path.py +32 -9
- infrahub/core/diff/parent_node_adder.py +78 -0
- infrahub/core/diff/payload_builder.py +13 -2
- infrahub/core/diff/query/filters.py +2 -2
- infrahub/core/diff/query/merge.py +20 -17
- infrahub/core/diff/query/save.py +188 -182
- infrahub/core/diff/query/summary_counts_enricher.py +51 -4
- infrahub/core/diff/query_parser.py +4 -4
- infrahub/core/diff/repository/deserializer.py +8 -3
- infrahub/core/diff/repository/repository.py +156 -38
- infrahub/core/diff/tasks.py +4 -4
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/index.py +3 -0
- infrahub/core/initialization.py +1 -10
- infrahub/core/ipam/constants.py +3 -4
- infrahub/core/ipam/reconciler.py +12 -12
- infrahub/core/ipam/utilization.py +10 -13
- infrahub/core/manager.py +36 -36
- infrahub/core/merge.py +7 -7
- infrahub/core/migrations/__init__.py +2 -3
- infrahub/core/migrations/graph/__init__.py +12 -3
- infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
- infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
- infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
- infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
- infrahub/core/migrations/graph/m022_add_generate_template_attr.py +48 -0
- infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
- infrahub/core/migrations/query/attribute_add.py +2 -2
- infrahub/core/migrations/query/node_duplicate.py +43 -26
- infrahub/core/migrations/query/schema_attribute_update.py +2 -2
- infrahub/core/migrations/schema/models.py +19 -4
- infrahub/core/migrations/schema/node_remove.py +26 -12
- infrahub/core/migrations/schema/tasks.py +2 -2
- infrahub/core/migrations/shared.py +16 -16
- infrahub/core/models.py +15 -6
- infrahub/core/node/__init__.py +43 -39
- infrahub/core/node/base.py +2 -4
- infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
- infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
- infrahub/core/node/constraints/interface.py +1 -2
- infrahub/core/node/delete_validator.py +3 -5
- infrahub/core/node/ipam.py +4 -4
- infrahub/core/node/permissions.py +7 -7
- infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
- infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
- infrahub/core/node/resource_manager/number_pool.py +3 -3
- infrahub/core/path.py +12 -12
- infrahub/core/property.py +11 -11
- infrahub/core/protocols.py +7 -0
- infrahub/core/protocols_base.py +21 -21
- infrahub/core/query/__init__.py +33 -33
- infrahub/core/query/attribute.py +6 -4
- infrahub/core/query/diff.py +3 -3
- infrahub/core/query/node.py +82 -32
- infrahub/core/query/relationship.py +228 -40
- infrahub/core/query/resource_manager.py +2 -0
- infrahub/core/query/standard_node.py +3 -3
- infrahub/core/query/subquery.py +9 -9
- infrahub/core/registry.py +13 -15
- infrahub/core/relationship/constraints/count.py +3 -4
- infrahub/core/relationship/constraints/peer_kind.py +3 -4
- infrahub/core/relationship/constraints/profiles_kind.py +2 -2
- infrahub/core/relationship/model.py +51 -59
- infrahub/core/schema/attribute_schema.py +16 -8
- infrahub/core/schema/basenode_schema.py +105 -44
- infrahub/core/schema/computed_attribute.py +3 -3
- infrahub/core/schema/definitions/core/__init__.py +147 -0
- infrahub/core/schema/definitions/core/account.py +171 -0
- infrahub/core/schema/definitions/core/artifact.py +136 -0
- infrahub/core/schema/definitions/core/builtin.py +24 -0
- infrahub/core/schema/definitions/core/check.py +68 -0
- infrahub/core/schema/definitions/core/core.py +17 -0
- infrahub/core/schema/definitions/core/generator.py +100 -0
- infrahub/core/schema/definitions/core/graphql_query.py +79 -0
- infrahub/core/schema/definitions/core/group.py +108 -0
- infrahub/core/schema/definitions/core/ipam.py +193 -0
- infrahub/core/schema/definitions/core/lineage.py +19 -0
- infrahub/core/schema/definitions/core/menu.py +48 -0
- infrahub/core/schema/definitions/core/permission.py +163 -0
- infrahub/core/schema/definitions/core/profile.py +18 -0
- infrahub/core/schema/definitions/core/propose_change.py +97 -0
- infrahub/core/schema/definitions/core/propose_change_comment.py +193 -0
- infrahub/core/schema/definitions/core/propose_change_validator.py +328 -0
- infrahub/core/schema/definitions/core/repository.py +286 -0
- infrahub/core/schema/definitions/core/resource_pool.py +170 -0
- infrahub/core/schema/definitions/core/template.py +27 -0
- infrahub/core/schema/definitions/core/transform.py +96 -0
- infrahub/core/schema/definitions/core/webhook.py +134 -0
- infrahub/core/schema/definitions/internal.py +16 -16
- infrahub/core/schema/dropdown.py +3 -4
- infrahub/core/schema/generated/attribute_schema.py +15 -18
- infrahub/core/schema/generated/base_node_schema.py +12 -14
- infrahub/core/schema/generated/node_schema.py +3 -5
- infrahub/core/schema/generated/relationship_schema.py +9 -11
- infrahub/core/schema/generic_schema.py +2 -2
- infrahub/core/schema/manager.py +20 -9
- infrahub/core/schema/node_schema.py +4 -2
- infrahub/core/schema/relationship_schema.py +14 -6
- infrahub/core/schema/schema_branch.py +292 -144
- infrahub/core/schema/schema_branch_computed.py +41 -4
- infrahub/core/task/task.py +3 -3
- infrahub/core/task/user_task.py +15 -15
- infrahub/core/timestamp.py +3 -3
- infrahub/core/utils.py +20 -18
- infrahub/core/validators/__init__.py +1 -3
- infrahub/core/validators/aggregated_checker.py +2 -2
- infrahub/core/validators/attribute/choices.py +2 -2
- infrahub/core/validators/attribute/enum.py +2 -2
- infrahub/core/validators/attribute/kind.py +2 -2
- infrahub/core/validators/attribute/length.py +2 -2
- infrahub/core/validators/attribute/optional.py +2 -2
- infrahub/core/validators/attribute/regex.py +2 -2
- infrahub/core/validators/attribute/unique.py +2 -2
- infrahub/core/validators/checks_runner.py +25 -2
- infrahub/core/validators/determiner.py +1 -3
- infrahub/core/validators/interface.py +6 -2
- infrahub/core/validators/model.py +22 -3
- infrahub/core/validators/models/validate_migration.py +17 -4
- infrahub/core/validators/node/attribute.py +2 -2
- infrahub/core/validators/node/generate_profile.py +2 -2
- infrahub/core/validators/node/hierarchy.py +3 -5
- infrahub/core/validators/node/inherit_from.py +27 -5
- infrahub/core/validators/node/relationship.py +2 -2
- infrahub/core/validators/relationship/count.py +4 -4
- infrahub/core/validators/relationship/optional.py +2 -2
- infrahub/core/validators/relationship/peer.py +2 -2
- infrahub/core/validators/shared.py +2 -2
- infrahub/core/validators/tasks.py +8 -0
- infrahub/core/validators/uniqueness/checker.py +22 -21
- infrahub/core/validators/uniqueness/index.py +2 -2
- infrahub/core/validators/uniqueness/model.py +11 -11
- infrahub/database/__init__.py +27 -22
- infrahub/database/metrics.py +7 -1
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
- infrahub/dependencies/builder/diff/deserializer.py +3 -1
- infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
- infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
- infrahub/dependencies/component/registry.py +2 -2
- infrahub/events/__init__.py +25 -2
- infrahub/events/artifact_action.py +64 -0
- infrahub/events/branch_action.py +33 -22
- infrahub/events/generator.py +71 -0
- infrahub/events/group_action.py +51 -21
- infrahub/events/models.py +18 -19
- infrahub/events/node_action.py +88 -37
- infrahub/events/repository_action.py +5 -18
- infrahub/events/schema_action.py +4 -9
- infrahub/events/utils.py +16 -0
- infrahub/events/validator_action.py +55 -0
- infrahub/exceptions.py +32 -24
- infrahub/generators/models.py +2 -3
- infrahub/generators/tasks.py +24 -4
- infrahub/git/base.py +7 -7
- infrahub/git/integrator.py +48 -24
- infrahub/git/models.py +101 -9
- infrahub/git/repository.py +3 -3
- infrahub/git/tasks.py +408 -6
- infrahub/git/utils.py +48 -0
- infrahub/git/worktree.py +1 -2
- infrahub/git_credential/askpass.py +1 -2
- infrahub/graphql/analyzer.py +12 -0
- infrahub/graphql/app.py +13 -15
- infrahub/graphql/context.py +39 -0
- infrahub/graphql/initialization.py +3 -0
- infrahub/graphql/loaders/node.py +2 -12
- infrahub/graphql/loaders/peers.py +77 -0
- infrahub/graphql/loaders/shared.py +13 -0
- infrahub/graphql/manager.py +17 -19
- infrahub/graphql/mutations/artifact_definition.py +5 -5
- infrahub/graphql/mutations/branch.py +26 -1
- infrahub/graphql/mutations/computed_attribute.py +9 -5
- infrahub/graphql/mutations/diff.py +23 -11
- infrahub/graphql/mutations/diff_conflict.py +5 -0
- infrahub/graphql/mutations/generator.py +83 -0
- infrahub/graphql/mutations/graphql_query.py +5 -5
- infrahub/graphql/mutations/ipam.py +54 -74
- infrahub/graphql/mutations/main.py +195 -132
- infrahub/graphql/mutations/menu.py +7 -7
- infrahub/graphql/mutations/models.py +2 -4
- infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
- infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
- infrahub/graphql/mutations/node_getter/by_id.py +1 -3
- infrahub/graphql/mutations/node_getter/interface.py +1 -2
- infrahub/graphql/mutations/proposed_change.py +7 -7
- infrahub/graphql/mutations/relationship.py +93 -19
- infrahub/graphql/mutations/repository.py +8 -8
- infrahub/graphql/mutations/resource_manager.py +3 -3
- infrahub/graphql/mutations/schema.py +19 -4
- infrahub/graphql/mutations/webhook.py +137 -0
- infrahub/graphql/parser.py +4 -4
- infrahub/graphql/permissions.py +1 -10
- infrahub/graphql/queries/diff/tree.py +19 -14
- infrahub/graphql/queries/event.py +5 -2
- infrahub/graphql/queries/ipam.py +2 -2
- infrahub/graphql/queries/relationship.py +2 -2
- infrahub/graphql/queries/search.py +2 -2
- infrahub/graphql/resolvers/many_relationship.py +264 -0
- infrahub/graphql/resolvers/resolver.py +13 -110
- infrahub/graphql/schema.py +2 -0
- infrahub/graphql/subscription/graphql_query.py +2 -0
- infrahub/graphql/types/context.py +12 -0
- infrahub/graphql/types/event.py +84 -17
- infrahub/graphql/types/node.py +2 -2
- infrahub/graphql/utils.py +2 -2
- infrahub/groups/ancestors.py +29 -0
- infrahub/groups/parsers.py +107 -0
- infrahub/lock.py +20 -20
- infrahub/menu/constants.py +0 -1
- infrahub/menu/generator.py +9 -21
- infrahub/menu/menu.py +17 -38
- infrahub/menu/models.py +117 -16
- infrahub/menu/repository.py +111 -0
- infrahub/menu/utils.py +5 -8
- infrahub/message_bus/__init__.py +11 -13
- infrahub/message_bus/messages/__init__.py +1 -21
- infrahub/message_bus/messages/check_generator_run.py +3 -3
- infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
- infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
- infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
- infrahub/message_bus/messages/send_echo_request.py +1 -1
- infrahub/message_bus/operations/__init__.py +1 -10
- infrahub/message_bus/operations/check/__init__.py +2 -2
- infrahub/message_bus/operations/check/generator.py +1 -0
- infrahub/message_bus/operations/event/__init__.py +2 -2
- infrahub/message_bus/operations/event/worker.py +0 -3
- infrahub/message_bus/operations/finalize/validator.py +51 -1
- infrahub/message_bus/operations/requests/__init__.py +0 -2
- infrahub/message_bus/operations/requests/generator_definition.py +21 -23
- infrahub/message_bus/operations/requests/proposed_change.py +14 -10
- infrahub/permissions/globals.py +15 -0
- infrahub/pools/number.py +2 -4
- infrahub/proposed_change/models.py +3 -0
- infrahub/proposed_change/tasks.py +58 -45
- infrahub/pytest_plugin.py +13 -10
- infrahub/server.py +2 -3
- infrahub/services/__init__.py +2 -2
- infrahub/services/adapters/cache/__init__.py +4 -6
- infrahub/services/adapters/cache/nats.py +4 -5
- infrahub/services/adapters/cache/redis.py +3 -7
- infrahub/services/adapters/event/__init__.py +1 -1
- infrahub/services/adapters/message_bus/__init__.py +3 -3
- infrahub/services/adapters/message_bus/local.py +2 -2
- infrahub/services/adapters/message_bus/nats.py +4 -4
- infrahub/services/adapters/message_bus/rabbitmq.py +4 -4
- infrahub/services/adapters/workflow/local.py +2 -2
- infrahub/services/component.py +5 -5
- infrahub/services/protocols.py +7 -7
- infrahub/services/scheduler.py +1 -3
- infrahub/task_manager/event.py +102 -9
- infrahub/task_manager/models.py +27 -7
- infrahub/tasks/artifact.py +7 -6
- infrahub/telemetry/__init__.py +0 -0
- infrahub/telemetry/constants.py +9 -0
- infrahub/telemetry/database.py +86 -0
- infrahub/telemetry/models.py +65 -0
- infrahub/telemetry/task_manager.py +77 -0
- infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
- infrahub/telemetry/utils.py +11 -0
- infrahub/trace.py +4 -4
- infrahub/transformations/tasks.py +2 -2
- infrahub/trigger/catalogue.py +4 -6
- infrahub/trigger/constants.py +0 -8
- infrahub/trigger/models.py +54 -5
- infrahub/trigger/setup.py +90 -0
- infrahub/trigger/tasks.py +35 -84
- infrahub/utils.py +11 -1
- infrahub/validators/__init__.py +0 -0
- infrahub/validators/events.py +42 -0
- infrahub/validators/tasks.py +41 -0
- infrahub/webhook/gather.py +17 -0
- infrahub/webhook/models.py +176 -44
- infrahub/webhook/tasks.py +154 -155
- infrahub/webhook/triggers.py +31 -7
- infrahub/workers/infrahub_async.py +2 -2
- infrahub/workers/utils.py +2 -2
- infrahub/workflows/catalogue.py +86 -35
- infrahub/workflows/initialization.py +8 -2
- infrahub/workflows/models.py +27 -1
- infrahub/workflows/utils.py +10 -1
- infrahub_sdk/client.py +35 -8
- infrahub_sdk/config.py +3 -0
- infrahub_sdk/context.py +13 -0
- infrahub_sdk/ctl/branch.py +3 -2
- infrahub_sdk/ctl/cli_commands.py +5 -1
- infrahub_sdk/ctl/utils.py +0 -16
- infrahub_sdk/exceptions.py +12 -0
- infrahub_sdk/generator.py +4 -1
- infrahub_sdk/graphql.py +45 -13
- infrahub_sdk/node.py +71 -22
- infrahub_sdk/protocols.py +21 -8
- infrahub_sdk/protocols_base.py +32 -11
- infrahub_sdk/query_groups.py +6 -35
- infrahub_sdk/schema/__init__.py +55 -26
- infrahub_sdk/schema/main.py +8 -0
- infrahub_sdk/task/__init__.py +11 -0
- infrahub_sdk/task/constants.py +3 -0
- infrahub_sdk/task/exceptions.py +25 -0
- infrahub_sdk/task/manager.py +551 -0
- infrahub_sdk/task/models.py +74 -0
- infrahub_sdk/testing/schemas/animal.py +9 -0
- infrahub_sdk/timestamp.py +142 -33
- infrahub_sdk/utils.py +29 -1
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +8 -6
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +349 -293
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/entry_points.txt +1 -0
- infrahub_testcontainers/constants.py +2 -0
- infrahub_testcontainers/container.py +157 -12
- infrahub_testcontainers/docker-compose.test.yml +31 -6
- infrahub_testcontainers/helpers.py +18 -73
- infrahub_testcontainers/host.py +41 -0
- infrahub_testcontainers/measurements.py +93 -0
- infrahub_testcontainers/models.py +38 -0
- infrahub_testcontainers/performance_test.py +166 -0
- infrahub_testcontainers/plugin.py +136 -0
- infrahub_testcontainers/prometheus.yml +30 -0
- infrahub/core/schema/definitions/core.py +0 -2286
- infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
- infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
- infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
- infrahub/message_bus/messages/event_branch_create.py +0 -11
- infrahub/message_bus/messages/event_branch_delete.py +0 -11
- infrahub/message_bus/messages/event_branch_rebased.py +0 -9
- infrahub/message_bus/messages/event_node_mutated.py +0 -15
- infrahub/message_bus/messages/event_schema_update.py +0 -9
- infrahub/message_bus/messages/request_repository_checks.py +0 -12
- infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
- infrahub/message_bus/operations/check/repository.py +0 -293
- infrahub/message_bus/operations/event/node.py +0 -20
- infrahub/message_bus/operations/event/schema.py +0 -17
- infrahub/message_bus/operations/requests/repository.py +0 -133
- infrahub/webhook/constants.py +0 -1
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from graphql.type.definition import GraphQLNonNull
|
|
6
6
|
from infrahub_sdk.utils import extract_fields
|
|
7
|
+
from opentelemetry import trace
|
|
7
8
|
|
|
8
9
|
from infrahub.core.constants import BranchSupportType, InfrahubKind, RelationshipHierarchyDirection
|
|
9
10
|
from infrahub.core.manager import NodeManager
|
|
10
|
-
from infrahub.core.query.node import NodeGetHierarchyQuery
|
|
11
11
|
from infrahub.exceptions import NodeNotFoundError
|
|
12
12
|
|
|
13
13
|
from ..models import OrderModel
|
|
14
14
|
from ..parser import extract_selection
|
|
15
15
|
from ..permissions import get_permissions
|
|
16
|
-
from ..types import RELATIONS_PROPERTY_MAP, RELATIONS_PROPERTY_MAP_REVERSED
|
|
17
16
|
|
|
18
17
|
if TYPE_CHECKING:
|
|
19
18
|
from graphql import GraphQLResolveInfo
|
|
@@ -22,6 +21,7 @@ if TYPE_CHECKING:
|
|
|
22
21
|
from infrahub.graphql.initialization import GraphqlContext
|
|
23
22
|
|
|
24
23
|
|
|
24
|
+
@trace.get_tracer(__name__).start_as_current_span("account_resolver")
|
|
25
25
|
async def account_resolver(
|
|
26
26
|
root: dict, # noqa: ARG001
|
|
27
27
|
info: GraphQLResolveInfo,
|
|
@@ -46,6 +46,7 @@ async def account_resolver(
|
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
@trace.get_tracer(__name__).start_as_current_span("default_resolver")
|
|
49
50
|
async def default_resolver(*args: Any, **kwargs) -> dict | list[dict] | None:
|
|
50
51
|
"""Not sure why but the default resolver returns sometime 4 positional args and sometime 2.
|
|
51
52
|
|
|
@@ -128,6 +129,7 @@ async def default_resolver(*args: Any, **kwargs) -> dict | list[dict] | None:
|
|
|
128
129
|
return await objs[0].to_graphql(db=db, fields=fields, related_node_ids=graphql_context.related_node_ids)
|
|
129
130
|
|
|
130
131
|
|
|
132
|
+
@trace.get_tracer(__name__).start_as_current_span("parent_field_name_resolver")
|
|
131
133
|
async def parent_field_name_resolver(parent: dict[str, dict], info: GraphQLResolveInfo) -> dict:
|
|
132
134
|
"""This resolver gets used when we know that the parent resolver has already gathered the required information.
|
|
133
135
|
|
|
@@ -137,6 +139,7 @@ async def parent_field_name_resolver(parent: dict[str, dict], info: GraphQLResol
|
|
|
137
139
|
return parent[info.field_name]
|
|
138
140
|
|
|
139
141
|
|
|
142
|
+
@trace.get_tracer(__name__).start_as_current_span("default_paginated_list_resolver")
|
|
140
143
|
async def default_paginated_list_resolver(
|
|
141
144
|
root: dict, # noqa: ARG001
|
|
142
145
|
info: GraphQLResolveInfo,
|
|
@@ -164,7 +167,7 @@ async def default_paginated_list_resolver(
|
|
|
164
167
|
edges = fields.get("edges", {})
|
|
165
168
|
node_fields = edges.get("node", {})
|
|
166
169
|
|
|
167
|
-
permission_set:
|
|
170
|
+
permission_set: dict[str, Any] | None = None
|
|
168
171
|
permissions = (
|
|
169
172
|
await get_permissions(schema=schema, graphql_context=graphql_context)
|
|
170
173
|
if graphql_context.permissions
|
|
@@ -227,121 +230,20 @@ async def default_paginated_list_resolver(
|
|
|
227
230
|
return response
|
|
228
231
|
|
|
229
232
|
|
|
233
|
+
@trace.get_tracer(__name__).start_as_current_span("single_relationship_resolver")
|
|
230
234
|
async def single_relationship_resolver(parent: dict, info: GraphQLResolveInfo, **kwargs: Any) -> dict[str, Any]:
|
|
231
235
|
graphql_context: GraphqlContext = info.context
|
|
232
236
|
resolver = graphql_context.single_relationship_resolver
|
|
233
237
|
return await resolver.resolve(parent=parent, info=info, **kwargs)
|
|
234
238
|
|
|
235
239
|
|
|
240
|
+
@trace.get_tracer(__name__).start_as_current_span("many_relationship_resolver")
|
|
236
241
|
async def many_relationship_resolver(
|
|
237
|
-
parent: dict, info: GraphQLResolveInfo, include_descendants:
|
|
242
|
+
parent: dict, info: GraphQLResolveInfo, include_descendants: bool | None = False, **kwargs: Any
|
|
238
243
|
) -> dict[str, Any]:
|
|
239
|
-
"""Resolver for relationships of cardinality=many for Edged responses
|
|
240
|
-
|
|
241
|
-
This resolver is used for paginated responses and as such we redefined the requested
|
|
242
|
-
fields by only reusing information below the 'node' key.
|
|
243
|
-
"""
|
|
244
|
-
# Extract the InfraHub schema by inspecting the GQL Schema
|
|
245
|
-
node_schema: NodeSchema = (
|
|
246
|
-
info.parent_type.of_type.graphene_type._meta.schema
|
|
247
|
-
if isinstance(info.parent_type, GraphQLNonNull)
|
|
248
|
-
else info.parent_type.graphene_type._meta.schema
|
|
249
|
-
)
|
|
250
|
-
|
|
251
244
|
graphql_context: GraphqlContext = info.context
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
fields = await extract_fields(info.field_nodes[0].selection_set)
|
|
255
|
-
edges = fields.get("edges", {})
|
|
256
|
-
node_fields = edges.get("node", {})
|
|
257
|
-
property_fields = edges.get("properties", {})
|
|
258
|
-
for key, value in property_fields.items():
|
|
259
|
-
mapped_name = RELATIONS_PROPERTY_MAP[key]
|
|
260
|
-
node_fields[mapped_name] = value
|
|
261
|
-
|
|
262
|
-
# Extract the schema of the node on the other end of the relationship from the GQL Schema
|
|
263
|
-
node_rel = node_schema.get_relationship(info.field_name)
|
|
264
|
-
|
|
265
|
-
# Extract only the filters from the kwargs and prepend the name of the field to the filters
|
|
266
|
-
offset = kwargs.pop("offset", None)
|
|
267
|
-
limit = kwargs.pop("limit", None)
|
|
268
|
-
|
|
269
|
-
filters = {
|
|
270
|
-
f"{info.field_name}__{key}": value
|
|
271
|
-
for key, value in kwargs.items()
|
|
272
|
-
if "__" in key and value or key in ["id", "ids"]
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
response: dict[str, Any] = {"edges": [], "count": None}
|
|
276
|
-
|
|
277
|
-
source_kind = node_schema.kind
|
|
278
|
-
|
|
279
|
-
async with graphql_context.db.start_session() as db:
|
|
280
|
-
ids = [parent["id"]]
|
|
281
|
-
if include_descendants:
|
|
282
|
-
query = await NodeGetHierarchyQuery.init(
|
|
283
|
-
db=db,
|
|
284
|
-
direction=RelationshipHierarchyDirection.DESCENDANTS,
|
|
285
|
-
node_id=parent["id"],
|
|
286
|
-
node_schema=node_schema,
|
|
287
|
-
at=graphql_context.at,
|
|
288
|
-
branch=graphql_context.branch,
|
|
289
|
-
)
|
|
290
|
-
if node_schema.hierarchy:
|
|
291
|
-
source_kind = node_schema.hierarchy
|
|
292
|
-
await query.execute(db=db)
|
|
293
|
-
descendants_ids = list(query.get_peer_ids())
|
|
294
|
-
ids.extend(descendants_ids)
|
|
295
|
-
|
|
296
|
-
if "count" in fields:
|
|
297
|
-
response["count"] = await NodeManager.count_peers(
|
|
298
|
-
db=db,
|
|
299
|
-
ids=ids,
|
|
300
|
-
source_kind=source_kind,
|
|
301
|
-
schema=node_rel,
|
|
302
|
-
filters=filters,
|
|
303
|
-
at=graphql_context.at,
|
|
304
|
-
branch=graphql_context.branch,
|
|
305
|
-
branch_agnostic=node_rel.branch is BranchSupportType.AGNOSTIC,
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
if not node_fields:
|
|
309
|
-
return response
|
|
310
|
-
|
|
311
|
-
objs = await NodeManager.query_peers(
|
|
312
|
-
db=db,
|
|
313
|
-
ids=ids,
|
|
314
|
-
source_kind=source_kind,
|
|
315
|
-
schema=node_rel,
|
|
316
|
-
filters=filters,
|
|
317
|
-
fields=node_fields,
|
|
318
|
-
offset=offset,
|
|
319
|
-
limit=limit,
|
|
320
|
-
at=graphql_context.at,
|
|
321
|
-
branch=graphql_context.branch,
|
|
322
|
-
branch_agnostic=node_rel.branch is BranchSupportType.AGNOSTIC,
|
|
323
|
-
fetch_peers=True,
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
if not objs:
|
|
327
|
-
return response
|
|
328
|
-
node_graph = [
|
|
329
|
-
await obj.to_graphql(db=db, fields=node_fields, related_node_ids=graphql_context.related_node_ids)
|
|
330
|
-
for obj in objs
|
|
331
|
-
]
|
|
332
|
-
|
|
333
|
-
entries = []
|
|
334
|
-
for node in node_graph:
|
|
335
|
-
entry = {"node": {}, "properties": {}}
|
|
336
|
-
for key, mapped in RELATIONS_PROPERTY_MAP_REVERSED.items():
|
|
337
|
-
value = node.pop(key, None)
|
|
338
|
-
if value:
|
|
339
|
-
entry["properties"][mapped] = value
|
|
340
|
-
entry["node"] = node
|
|
341
|
-
entries.append(entry)
|
|
342
|
-
response["edges"] = entries
|
|
343
|
-
|
|
344
|
-
return response
|
|
245
|
+
resolver = graphql_context.many_relationship_resolver
|
|
246
|
+
return await resolver.resolve(parent=parent, info=info, include_descendants=include_descendants, **kwargs)
|
|
345
247
|
|
|
346
248
|
|
|
347
249
|
async def ancestors_resolver(parent: dict, info: GraphQLResolveInfo, **kwargs) -> dict[str, Any]:
|
|
@@ -356,6 +258,7 @@ async def descendants_resolver(parent: dict, info: GraphQLResolveInfo, **kwargs)
|
|
|
356
258
|
)
|
|
357
259
|
|
|
358
260
|
|
|
261
|
+
@trace.get_tracer(__name__).start_as_current_span("hierarchy_resolver")
|
|
359
262
|
async def hierarchy_resolver(
|
|
360
263
|
direction: RelationshipHierarchyDirection, parent: dict, info: GraphQLResolveInfo, **kwargs
|
|
361
264
|
) -> dict[str, Any]:
|
infrahub/graphql/schema.py
CHANGED
|
@@ -18,6 +18,7 @@ from .mutations.branch import (
|
|
|
18
18
|
from .mutations.computed_attribute import UpdateComputedAttribute
|
|
19
19
|
from .mutations.diff import DiffUpdateMutation
|
|
20
20
|
from .mutations.diff_conflict import ResolveDiffConflict
|
|
21
|
+
from .mutations.generator import GeneratorDefinitionRequestRun
|
|
21
22
|
from .mutations.proposed_change import ProposedChangeMerge, ProposedChangeRequestRunCheck
|
|
22
23
|
from .mutations.relationship import (
|
|
23
24
|
RelationshipAdd,
|
|
@@ -83,6 +84,7 @@ class InfrahubBaseMutation(ObjectType):
|
|
|
83
84
|
InfrahubAccountTokenDelete = InfrahubAccountTokenDelete.Field()
|
|
84
85
|
CoreProposedChangeRunCheck = ProposedChangeRequestRunCheck.Field()
|
|
85
86
|
CoreProposedChangeMerge = ProposedChangeMerge.Field()
|
|
87
|
+
CoreGeneratorDefinitionRun = GeneratorDefinitionRequestRun.Field()
|
|
86
88
|
|
|
87
89
|
IPPrefixPoolGetResource = IPPrefixPoolGetResource.Field()
|
|
88
90
|
IPAddressPoolGetResource = IPAddressPoolGetResource.Field()
|
|
@@ -8,6 +8,7 @@ from infrahub.core.constants import InfrahubKind
|
|
|
8
8
|
from infrahub.core.manager import NodeManager
|
|
9
9
|
from infrahub.core.protocols import CoreGraphQLQuery
|
|
10
10
|
from infrahub.core.timestamp import Timestamp
|
|
11
|
+
from infrahub.graphql.resolvers.many_relationship import ManyRelationshipResolver
|
|
11
12
|
from infrahub.graphql.resolvers.single_relationship import SingleRelationshipResolver
|
|
12
13
|
from infrahub.log import get_logger
|
|
13
14
|
|
|
@@ -48,6 +49,7 @@ async def resolver_graphql_query(
|
|
|
48
49
|
related_node_ids=set(),
|
|
49
50
|
types=graphql_context.types,
|
|
50
51
|
single_relationship_resolver=SingleRelationshipResolver(),
|
|
52
|
+
many_relationship_resolver=ManyRelationshipResolver(),
|
|
51
53
|
),
|
|
52
54
|
root_value=None,
|
|
53
55
|
variable_values=params or {},
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from graphene import InputObjectType, String
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ContextAccountInput(InputObjectType):
|
|
5
|
+
id = String(required=True, description="The Infrahub ID of the account")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ContextInput(InputObjectType):
|
|
9
|
+
account = ContextAccountInput(
|
|
10
|
+
required=False,
|
|
11
|
+
description="The account context can be used to override the account information that will be associated with the mutation",
|
|
12
|
+
)
|
infrahub/graphql/types/event.py
CHANGED
|
@@ -2,9 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
|
-
from graphene import Boolean, DateTime, Field, Int, Interface, List, NonNull, ObjectType, String
|
|
5
|
+
from graphene import Boolean, DateTime, Field, InputObjectType, Int, Interface, List, NonNull, ObjectType, String
|
|
6
6
|
from graphene.types.generic import GenericScalar
|
|
7
7
|
|
|
8
|
+
from infrahub import events
|
|
9
|
+
|
|
8
10
|
from .common import RelatedNode
|
|
9
11
|
from .enums import DiffAction
|
|
10
12
|
|
|
@@ -20,17 +22,32 @@ class InfrahubMutatedAttribute(ObjectType):
|
|
|
20
22
|
value_previous = String(required=False)
|
|
21
23
|
|
|
22
24
|
|
|
25
|
+
class InfrahubMutatedRelationship(ObjectType):
|
|
26
|
+
name = String(required=True)
|
|
27
|
+
action = DiffAction(required=True)
|
|
28
|
+
peer = Field(RelatedNode, required=True)
|
|
29
|
+
|
|
30
|
+
|
|
23
31
|
class EventNodeInterface(Interface):
|
|
24
|
-
id = String(required=True)
|
|
25
|
-
event = String(required=True)
|
|
26
|
-
branch = String(required=False)
|
|
27
|
-
account_id = String(required=False)
|
|
28
|
-
occurred_at = DateTime(required=True)
|
|
29
|
-
level = Int(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
id = String(required=True, description="The ID of the event.")
|
|
33
|
+
event = String(required=True, description="The name of the event.")
|
|
34
|
+
branch = String(required=False, description="The branch where the event occurred.")
|
|
35
|
+
account_id = String(required=False, description="The account ID that triggered the event.")
|
|
36
|
+
occurred_at = DateTime(required=True, description="The timestamp when the event occurred.")
|
|
37
|
+
level = Int(
|
|
38
|
+
required=True,
|
|
39
|
+
description="The level of the event 0 is a root level event, the child events will have 1 and grand children 2.",
|
|
40
|
+
)
|
|
41
|
+
primary_node = Field(
|
|
42
|
+
RelatedNode, required=False, description="The primary Infrahub node this event is associated with."
|
|
43
|
+
)
|
|
44
|
+
related_nodes = List(
|
|
45
|
+
NonNull(RelatedNode), required=True, description="Related Infrahub nodes this event is associated with."
|
|
46
|
+
)
|
|
47
|
+
has_children = Boolean(
|
|
48
|
+
required=True, description="Indicates if the event is expected to have child events under it"
|
|
49
|
+
)
|
|
50
|
+
parent_id = String(required=False, description="The event ID of the direct parent to this event.")
|
|
34
51
|
|
|
35
52
|
@classmethod
|
|
36
53
|
def resolve_type(
|
|
@@ -47,6 +64,19 @@ class EventNodes(ObjectType):
|
|
|
47
64
|
node = Field(EventNodeInterface)
|
|
48
65
|
|
|
49
66
|
|
|
67
|
+
class BranchEventTypeFilter(InputObjectType):
|
|
68
|
+
branches = List(NonNull(String), required=True, description="Name of impacted branches")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class EventTypeFilter(InputObjectType):
|
|
72
|
+
branch_merged = Field(
|
|
73
|
+
BranchEventTypeFilter, required=False, description="Filters specific to infrahub.branch.merged events"
|
|
74
|
+
)
|
|
75
|
+
branch_rebased = Field(
|
|
76
|
+
BranchEventTypeFilter, required=False, description="Filters specific to infrahub.branch.rebased events"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
50
80
|
# ---------------------------------------
|
|
51
81
|
# Branch events
|
|
52
82
|
# ---------------------------------------
|
|
@@ -54,13 +84,24 @@ class BranchCreatedEvent(ObjectType):
|
|
|
54
84
|
class Meta:
|
|
55
85
|
interfaces = (EventNodeInterface,)
|
|
56
86
|
|
|
87
|
+
created_branch = String(required=True, description="The name of the branch that was created")
|
|
57
88
|
payload = Field(GenericScalar, required=True)
|
|
58
89
|
|
|
59
90
|
|
|
91
|
+
class BranchMergedEvent(ObjectType):
|
|
92
|
+
class Meta:
|
|
93
|
+
interfaces = (EventNodeInterface,)
|
|
94
|
+
|
|
95
|
+
source_branch = String(required=True, description="The name of the branch that was merged into the default branch")
|
|
96
|
+
|
|
97
|
+
|
|
60
98
|
class BranchRebasedEvent(ObjectType):
|
|
61
99
|
class Meta:
|
|
62
100
|
interfaces = (EventNodeInterface,)
|
|
63
101
|
|
|
102
|
+
rebased_branch = String(
|
|
103
|
+
required=True, description="The name of the branch that was rebased and aligned with the default branch"
|
|
104
|
+
)
|
|
64
105
|
payload = Field(GenericScalar, required=True)
|
|
65
106
|
|
|
66
107
|
|
|
@@ -68,6 +109,7 @@ class BranchDeletedEvent(ObjectType):
|
|
|
68
109
|
class Meta:
|
|
69
110
|
interfaces = (EventNodeInterface,)
|
|
70
111
|
|
|
112
|
+
deleted_branch = String(required=True, description="The name of the branch that was deleted")
|
|
71
113
|
payload = Field(GenericScalar, required=True)
|
|
72
114
|
|
|
73
115
|
|
|
@@ -80,6 +122,26 @@ class NodeMutatedEvent(ObjectType):
|
|
|
80
122
|
|
|
81
123
|
payload = Field(GenericScalar, required=True)
|
|
82
124
|
attributes = Field(List(of_type=NonNull(InfrahubMutatedAttribute), required=True), required=True)
|
|
125
|
+
relationships = Field(List(of_type=NonNull(InfrahubMutatedRelationship), required=True), required=True)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class ArtifactEvent(ObjectType):
|
|
129
|
+
class Meta:
|
|
130
|
+
interfaces = (EventNodeInterface,)
|
|
131
|
+
|
|
132
|
+
checksum = String(required=True, description="The current checksum of the artifact")
|
|
133
|
+
checksum_previous = String(required=False, description="The previous checksum of the artifact")
|
|
134
|
+
storage_id = String(required=True, description="The current storage_id of the artifact")
|
|
135
|
+
storage_id_previous = String(required=False, description="The previous storage_id of the artifact")
|
|
136
|
+
artifact_definition_id = String(required=True, description="Artifact definition ID")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class GroupEvent(ObjectType):
|
|
140
|
+
class Meta:
|
|
141
|
+
interfaces = (EventNodeInterface,)
|
|
142
|
+
|
|
143
|
+
members = List(NonNull(RelatedNode), required=True, description="Group members modified in this event")
|
|
144
|
+
ancestors = List(NonNull(RelatedNode), required=True, description="Ancestor groups of this impacted group")
|
|
83
145
|
|
|
84
146
|
|
|
85
147
|
class StandardEvent(ObjectType):
|
|
@@ -90,11 +152,16 @@ class StandardEvent(ObjectType):
|
|
|
90
152
|
|
|
91
153
|
|
|
92
154
|
EVENT_TYPES: dict[str, type[ObjectType]] = {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
155
|
+
events.ArtifactCreatedEvent.event_name: ArtifactEvent,
|
|
156
|
+
events.ArtifactUpdatedEvent.event_name: ArtifactEvent,
|
|
157
|
+
events.NodeCreatedEvent.event_name: NodeMutatedEvent,
|
|
158
|
+
events.NodeUpdatedEvent.event_name: NodeMutatedEvent,
|
|
159
|
+
events.NodeDeletedEvent.event_name: NodeMutatedEvent,
|
|
160
|
+
events.BranchCreatedEvent.event_name: BranchCreatedEvent,
|
|
161
|
+
events.BranchMergedEvent.event_name: BranchMergedEvent,
|
|
162
|
+
events.BranchRebasedEvent.event_name: BranchRebasedEvent,
|
|
163
|
+
events.BranchDeletedEvent.event_name: BranchDeletedEvent,
|
|
164
|
+
events.GroupMemberAddedEvent.event_name: GroupEvent,
|
|
165
|
+
events.GroupMemberRemovedEvent.event_name: GroupEvent,
|
|
99
166
|
"undefined": StandardEvent,
|
|
100
167
|
}
|
infrahub/graphql/types/node.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from graphene import ObjectType
|
|
6
6
|
from graphene.types.objecttype import ObjectTypeOptions
|
|
@@ -16,7 +16,7 @@ class InfrahubObject(ObjectType):
|
|
|
16
16
|
@classmethod
|
|
17
17
|
def __init_subclass_with_meta__(
|
|
18
18
|
cls,
|
|
19
|
-
schema:
|
|
19
|
+
schema: MainSchemaTypes | None = None,
|
|
20
20
|
interfaces: tuple = (),
|
|
21
21
|
_meta: InfrahubObjectOptions | None = None,
|
|
22
22
|
**options: Any,
|
infrahub/graphql/utils.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from graphene.types.definitions import GrapheneInterfaceType, GrapheneObjectType
|
|
6
6
|
from graphql import (
|
|
@@ -50,7 +50,7 @@ def find_types_implementing_interface(
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
async def extract_schema_models(
|
|
53
|
-
fields: dict, schema:
|
|
53
|
+
fields: dict, schema: GrapheneObjectType | GraphQLUnionType, root_schema: GraphQLSchema
|
|
54
54
|
) -> set[str]:
|
|
55
55
|
response = set()
|
|
56
56
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from infrahub.core.constants import RelationshipHierarchyDirection
|
|
6
|
+
from infrahub.core.manager import NodeManager
|
|
7
|
+
from infrahub.core.schema import NodeSchema
|
|
8
|
+
from infrahub.events.models import EventNode
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from infrahub.core.branch import Branch
|
|
12
|
+
from infrahub.database import InfrahubDatabase
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def collect_ancestors(db: InfrahubDatabase, branch: Branch, node_kind: str, node_id: str) -> list[EventNode]:
|
|
16
|
+
schema = db.schema.get(name=node_kind, branch=branch, duplicate=False)
|
|
17
|
+
|
|
18
|
+
if not isinstance(schema, NodeSchema):
|
|
19
|
+
return []
|
|
20
|
+
|
|
21
|
+
ancestors = await NodeManager.query_hierarchy(
|
|
22
|
+
db=db,
|
|
23
|
+
branch=branch,
|
|
24
|
+
direction=RelationshipHierarchyDirection.ANCESTORS,
|
|
25
|
+
id=node_id,
|
|
26
|
+
node_schema=schema,
|
|
27
|
+
filters={"id": None},
|
|
28
|
+
)
|
|
29
|
+
return [EventNode(id=ancestor.get_id(), kind=ancestor.get_kind()) for ancestor in ancestors.values()]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from infrahub.core.branch import Branch
|
|
4
|
+
from infrahub.core.changelog.models import RelationshipCardinalityManyChangelog
|
|
5
|
+
from infrahub.core.constants import DiffAction, InfrahubKind
|
|
6
|
+
from infrahub.core.schema import NodeSchema
|
|
7
|
+
from infrahub.database import InfrahubDatabase
|
|
8
|
+
from infrahub.events.group_action import GroupMemberAddedEvent, GroupMemberRemovedEvent, GroupMutatedEvent
|
|
9
|
+
from infrahub.events.models import EventMeta, EventNode, InfrahubEvent
|
|
10
|
+
from infrahub.events.node_action import NodeCreatedEvent, NodeMutatedEvent, NodeUpdatedEvent
|
|
11
|
+
from infrahub.exceptions import SchemaNotFoundError
|
|
12
|
+
|
|
13
|
+
from .ancestors import collect_ancestors
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class ApplicableEvent:
|
|
18
|
+
event: NodeMutatedEvent
|
|
19
|
+
node_schema: NodeSchema
|
|
20
|
+
relationship: RelationshipCardinalityManyChangelog
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class GroupNodeMutationParser:
|
|
24
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch) -> None:
|
|
25
|
+
self._db = db
|
|
26
|
+
self._branch = branch
|
|
27
|
+
|
|
28
|
+
def _get_schema(self, kind: str) -> NodeSchema | None:
|
|
29
|
+
try:
|
|
30
|
+
node_schema = self._db.schema.get_node_schema(name=kind, branch=self._branch, duplicate=False)
|
|
31
|
+
except (ValueError, SchemaNotFoundError):
|
|
32
|
+
return None
|
|
33
|
+
return node_schema
|
|
34
|
+
|
|
35
|
+
def _get_applicable_events(self, events: list[NodeMutatedEvent]) -> list[ApplicableEvent]:
|
|
36
|
+
applicable: list[ApplicableEvent] = []
|
|
37
|
+
for event in events:
|
|
38
|
+
if event_kind := self._get_schema(kind=event.kind):
|
|
39
|
+
if (
|
|
40
|
+
InfrahubKind.GENERICGROUP in event_kind.inherit_from
|
|
41
|
+
and "members" in event.changelog.relationships
|
|
42
|
+
and isinstance(
|
|
43
|
+
event.changelog.relationships["members"],
|
|
44
|
+
RelationshipCardinalityManyChangelog,
|
|
45
|
+
)
|
|
46
|
+
):
|
|
47
|
+
applicable.append(
|
|
48
|
+
ApplicableEvent(
|
|
49
|
+
event=event,
|
|
50
|
+
node_schema=event_kind,
|
|
51
|
+
relationship=event.changelog.relationships["members"],
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
return applicable
|
|
55
|
+
|
|
56
|
+
async def group_events_from_node_actions(self, events: list[NodeMutatedEvent]) -> list[InfrahubEvent]:
|
|
57
|
+
group_events: list[InfrahubEvent] = []
|
|
58
|
+
|
|
59
|
+
for applicable_event in self._get_applicable_events(events=events):
|
|
60
|
+
added_peers = [
|
|
61
|
+
EventNode(id=peer.peer_id, kind=peer.peer_kind)
|
|
62
|
+
for peer in applicable_event.relationship.peers
|
|
63
|
+
if peer.peer_status == DiffAction.ADDED
|
|
64
|
+
]
|
|
65
|
+
removed_peers = [
|
|
66
|
+
EventNode(id=peer.peer_id, kind=peer.peer_kind)
|
|
67
|
+
for peer in applicable_event.relationship.peers
|
|
68
|
+
if peer.peer_status == DiffAction.REMOVED
|
|
69
|
+
]
|
|
70
|
+
if added_peers:
|
|
71
|
+
group_events.append(
|
|
72
|
+
await self._define_group_event(
|
|
73
|
+
event_type=GroupMemberAddedEvent, parent=applicable_event.event, peers=added_peers
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
if removed_peers:
|
|
78
|
+
group_events.append(
|
|
79
|
+
await self._define_group_event(
|
|
80
|
+
event_type=GroupMemberRemovedEvent, parent=applicable_event.event, peers=removed_peers
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return group_events
|
|
85
|
+
|
|
86
|
+
async def _define_group_event(
|
|
87
|
+
self,
|
|
88
|
+
event_type: type[GroupMemberAddedEvent | GroupMemberRemovedEvent],
|
|
89
|
+
parent: NodeMutatedEvent,
|
|
90
|
+
peers: list[EventNode],
|
|
91
|
+
) -> GroupMutatedEvent:
|
|
92
|
+
event_meta = EventMeta.from_parent(parent=parent)
|
|
93
|
+
group_event = event_type(
|
|
94
|
+
meta=event_meta,
|
|
95
|
+
kind=parent.kind,
|
|
96
|
+
node_id=parent.node_id,
|
|
97
|
+
members=peers,
|
|
98
|
+
)
|
|
99
|
+
if isinstance(parent, NodeCreatedEvent | NodeUpdatedEvent):
|
|
100
|
+
# Avoid trying to find ancestors for deleted nodes
|
|
101
|
+
group_event.ancestors = await collect_ancestors(
|
|
102
|
+
db=self._db,
|
|
103
|
+
branch=self._branch,
|
|
104
|
+
node_kind=parent.kind,
|
|
105
|
+
node_id=parent.node_id,
|
|
106
|
+
)
|
|
107
|
+
return group_event
|