infrahub-server 1.2.0b1__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 +1 -3
- infrahub/artifacts/tasks.py +1 -3
- 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 +239 -11
- infrahub/computed_attribute/tasks.py +77 -442
- infrahub/computed_attribute/triggers.py +11 -45
- infrahub/config.py +43 -32
- infrahub/context.py +14 -0
- infrahub/core/account.py +4 -4
- infrahub/core/attribute.py +57 -57
- infrahub/core/branch/tasks.py +12 -9
- infrahub/core/changelog/diff.py +16 -8
- infrahub/core/changelog/models.py +189 -26
- infrahub/core/constants/__init__.py +5 -1
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/constraint/node/runner.py +9 -8
- infrahub/core/diff/branch_differ.py +10 -10
- infrahub/core/diff/ipam_diff_parser.py +4 -5
- infrahub/core/diff/model/diff.py +27 -27
- infrahub/core/diff/model/path.py +3 -3
- infrahub/core/diff/query/merge.py +20 -17
- infrahub/core/diff/query_parser.py +4 -4
- infrahub/core/graph/__init__.py +1 -1
- 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 +34 -34
- infrahub/core/merge.py +7 -7
- infrahub/core/migrations/__init__.py +2 -3
- infrahub/core/migrations/graph/__init__.py +9 -4
- 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/m020_duplicate_edges.py +160 -0
- infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
- infrahub/core/migrations/graph/{m020_add_generate_template_attr.py → m022_add_generate_template_attr.py} +3 -3
- 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 +18 -21
- infrahub/core/migrations/query/schema_attribute_update.py +2 -2
- infrahub/core/migrations/schema/models.py +19 -4
- 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 +29 -28
- 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 +5 -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 +24 -24
- 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 +40 -46
- infrahub/core/schema/attribute_schema.py +9 -9
- infrahub/core/schema/basenode_schema.py +93 -44
- infrahub/core/schema/computed_attribute.py +3 -3
- infrahub/core/schema/definitions/core/__init__.py +13 -19
- infrahub/core/schema/definitions/core/account.py +151 -148
- infrahub/core/schema/definitions/core/artifact.py +122 -113
- infrahub/core/schema/definitions/core/builtin.py +19 -16
- infrahub/core/schema/definitions/core/check.py +61 -53
- infrahub/core/schema/definitions/core/core.py +17 -0
- infrahub/core/schema/definitions/core/generator.py +89 -85
- infrahub/core/schema/definitions/core/graphql_query.py +72 -70
- infrahub/core/schema/definitions/core/group.py +96 -93
- infrahub/core/schema/definitions/core/ipam.py +176 -235
- infrahub/core/schema/definitions/core/lineage.py +18 -16
- infrahub/core/schema/definitions/core/menu.py +42 -40
- infrahub/core/schema/definitions/core/permission.py +144 -142
- infrahub/core/schema/definitions/core/profile.py +16 -27
- infrahub/core/schema/definitions/core/propose_change.py +88 -79
- infrahub/core/schema/definitions/core/propose_change_comment.py +170 -165
- infrahub/core/schema/definitions/core/propose_change_validator.py +290 -288
- infrahub/core/schema/definitions/core/repository.py +231 -225
- infrahub/core/schema/definitions/core/resource_pool.py +156 -166
- infrahub/core/schema/definitions/core/template.py +27 -12
- infrahub/core/schema/definitions/core/transform.py +85 -76
- infrahub/core/schema/definitions/core/webhook.py +127 -101
- 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 +7 -7
- infrahub/core/schema/schema_branch.py +276 -138
- 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/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 +26 -22
- infrahub/database/metrics.py +7 -1
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
- infrahub/dependencies/component/registry.py +2 -2
- infrahub/events/__init__.py +25 -2
- infrahub/events/artifact_action.py +13 -25
- infrahub/events/branch_action.py +26 -18
- infrahub/events/generator.py +71 -0
- infrahub/events/group_action.py +10 -24
- infrahub/events/models.py +10 -16
- infrahub/events/node_action.py +87 -32
- 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 +23 -24
- infrahub/generators/models.py +1 -3
- infrahub/git/base.py +7 -7
- infrahub/git/integrator.py +26 -25
- infrahub/git/models.py +22 -9
- infrahub/git/repository.py +3 -3
- infrahub/git/tasks.py +67 -49
- 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 +6 -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 +13 -10
- infrahub/graphql/mutations/artifact_definition.py +5 -5
- infrahub/graphql/mutations/computed_attribute.py +4 -5
- infrahub/graphql/mutations/graphql_query.py +5 -5
- infrahub/graphql/mutations/ipam.py +50 -70
- infrahub/graphql/mutations/main.py +164 -141
- infrahub/graphql/mutations/menu.py +5 -5
- 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 +67 -35
- infrahub/graphql/mutations/repository.py +8 -8
- infrahub/graphql/mutations/resource_manager.py +3 -3
- infrahub/graphql/mutations/schema.py +4 -4
- infrahub/graphql/mutations/webhook.py +137 -0
- infrahub/graphql/parser.py +4 -4
- infrahub/graphql/queries/diff/tree.py +4 -4
- 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/subscription/graphql_query.py +2 -0
- infrahub/graphql/types/event.py +20 -11
- 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/menu/generator.py +7 -7
- infrahub/menu/menu.py +0 -10
- infrahub/menu/models.py +117 -16
- infrahub/menu/repository.py +111 -0
- infrahub/menu/utils.py +5 -8
- infrahub/message_bus/messages/__init__.py +1 -11
- infrahub/message_bus/messages/check_generator_run.py +2 -0
- infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
- infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
- infrahub/message_bus/operations/__init__.py +0 -2
- infrahub/message_bus/operations/check/generator.py +1 -0
- infrahub/message_bus/operations/event/__init__.py +2 -2
- infrahub/message_bus/operations/finalize/validator.py +51 -1
- infrahub/message_bus/operations/requests/generator_definition.py +19 -19
- infrahub/message_bus/operations/requests/proposed_change.py +3 -1
- infrahub/pools/number.py +2 -4
- infrahub/proposed_change/tasks.py +37 -28
- infrahub/pytest_plugin.py +13 -10
- infrahub/server.py +1 -2
- infrahub/services/adapters/event/__init__.py +1 -1
- infrahub/task_manager/event.py +23 -9
- infrahub/tasks/artifact.py +2 -4
- 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 +2 -5
- infrahub/trigger/constants.py +0 -8
- infrahub/trigger/models.py +14 -1
- infrahub/trigger/setup.py +90 -0
- infrahub/trigger/tasks.py +35 -90
- 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 +22 -5
- infrahub/webhook/tasks.py +44 -19
- infrahub/webhook/triggers.py +22 -5
- infrahub/workers/infrahub_async.py +2 -2
- infrahub/workers/utils.py +2 -2
- infrahub/workflows/catalogue.py +28 -20
- infrahub/workflows/initialization.py +1 -3
- infrahub/workflows/models.py +1 -1
- infrahub/workflows/utils.py +10 -1
- infrahub_sdk/client.py +27 -8
- infrahub_sdk/config.py +3 -0
- infrahub_sdk/context.py +13 -0
- infrahub_sdk/exceptions.py +6 -0
- infrahub_sdk/generator.py +4 -1
- infrahub_sdk/graphql.py +45 -13
- infrahub_sdk/node.py +69 -20
- 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 +10 -0
- infrahub_sdk/task/manager.py +12 -6
- infrahub_sdk/testing/schemas/animal.py +9 -0
- infrahub_sdk/timestamp.py +12 -4
- {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +3 -2
- {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +289 -260
- {infrahub_server-1.2.0b1.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/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/operations/event/node.py +0 -20
- infrahub/message_bus/operations/event/schema.py +0 -17
- infrahub/webhook/constants.py +0 -1
- {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
infrahub/cli/upgrade.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from deepdiff import DeepDiff
|
|
9
|
+
from infrahub_sdk.async_typer import AsyncTyper
|
|
10
|
+
from prefect.client.orchestration import get_client
|
|
11
|
+
from rich import print as rprint
|
|
12
|
+
|
|
13
|
+
from infrahub import config
|
|
14
|
+
from infrahub.core.constants import InfrahubKind
|
|
15
|
+
from infrahub.core.initialization import (
|
|
16
|
+
create_anonymous_role,
|
|
17
|
+
create_default_roles,
|
|
18
|
+
create_super_administrator_role,
|
|
19
|
+
create_super_administrators_group,
|
|
20
|
+
initialize_registry,
|
|
21
|
+
)
|
|
22
|
+
from infrahub.core.manager import NodeManager
|
|
23
|
+
from infrahub.menu.menu import default_menu
|
|
24
|
+
from infrahub.menu.models import MenuDict
|
|
25
|
+
from infrahub.menu.repository import MenuRepository
|
|
26
|
+
from infrahub.menu.utils import create_default_menu
|
|
27
|
+
from infrahub.services import InfrahubServices
|
|
28
|
+
from infrahub.services.adapters.message_bus.local import BusSimulator
|
|
29
|
+
from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
|
|
30
|
+
from infrahub.trigger.tasks import trigger_configure_all
|
|
31
|
+
from infrahub.workflows.initialization import (
|
|
32
|
+
setup_blocks,
|
|
33
|
+
setup_deployments,
|
|
34
|
+
setup_worker_pools,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
from .db import initialize_internal_schema, migrate_database, update_core_schema
|
|
38
|
+
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
from infrahub.cli.context import CliContext
|
|
41
|
+
from infrahub.database import InfrahubDatabase
|
|
42
|
+
|
|
43
|
+
app = AsyncTyper()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@app.command(name="upgrade")
|
|
47
|
+
async def upgrade_cmd(
|
|
48
|
+
ctx: typer.Context,
|
|
49
|
+
config_file: str = typer.Argument("infrahub.toml", envvar="INFRAHUB_CONFIG"),
|
|
50
|
+
check: bool = typer.Option(False, help="Check the state of the system without upgrading."),
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Upgrade Infrahub to the latest version."""
|
|
53
|
+
|
|
54
|
+
logging.getLogger("infrahub").setLevel(logging.WARNING)
|
|
55
|
+
logging.getLogger("neo4j").setLevel(logging.ERROR)
|
|
56
|
+
logging.getLogger("prefect").setLevel(logging.ERROR)
|
|
57
|
+
os.environ["PREFECT_SERVER_ANALYTICS_ENABLED"] = "false"
|
|
58
|
+
|
|
59
|
+
config.load_and_exit(config_file_name=config_file)
|
|
60
|
+
|
|
61
|
+
context: CliContext = ctx.obj
|
|
62
|
+
dbdriver = await context.init_db(retry=1)
|
|
63
|
+
|
|
64
|
+
service = await InfrahubServices.new(
|
|
65
|
+
database=dbdriver, message_bus=BusSimulator(), workflow=WorkflowLocalExecution()
|
|
66
|
+
)
|
|
67
|
+
await initialize_registry(db=dbdriver)
|
|
68
|
+
|
|
69
|
+
# NOTE add step to validate if the database and the task manager are reachable
|
|
70
|
+
|
|
71
|
+
# -------------------------------------------
|
|
72
|
+
# Add pre-upgrade validation
|
|
73
|
+
# -------------------------------------------
|
|
74
|
+
|
|
75
|
+
# -------------------------------------------
|
|
76
|
+
# Upgrade Infrahub Database and Schema
|
|
77
|
+
# -------------------------------------------
|
|
78
|
+
await migrate_database(db=dbdriver, initialize=False, check=check)
|
|
79
|
+
|
|
80
|
+
await initialize_internal_schema()
|
|
81
|
+
await update_core_schema(db=dbdriver, service=service, initialize=False)
|
|
82
|
+
|
|
83
|
+
# -------------------------------------------
|
|
84
|
+
# Upgrade Internal Objects, generated and managed by Infrahub
|
|
85
|
+
# -------------------------------------------
|
|
86
|
+
await upgrade_menu(db=dbdriver)
|
|
87
|
+
await upgrade_permissions(db=dbdriver)
|
|
88
|
+
|
|
89
|
+
# -------------------------------------------
|
|
90
|
+
# Upgrade External system : Task Manager
|
|
91
|
+
# -------------------------------------------
|
|
92
|
+
async with get_client(sync_client=False) as client:
|
|
93
|
+
await setup_blocks()
|
|
94
|
+
await setup_worker_pools(client=client)
|
|
95
|
+
await setup_deployments(client=client)
|
|
96
|
+
await trigger_configure_all(service=service)
|
|
97
|
+
|
|
98
|
+
await dbdriver.close()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
async def upgrade_menu(db: InfrahubDatabase) -> None:
|
|
102
|
+
menu_repository = MenuRepository(db=db)
|
|
103
|
+
menu_nodes = await menu_repository.get_menu_db()
|
|
104
|
+
menu_items = await menu_repository.get_menu(nodes=menu_nodes)
|
|
105
|
+
default_menu_dict = MenuDict.from_definition_list(default_menu)
|
|
106
|
+
|
|
107
|
+
if not menu_nodes:
|
|
108
|
+
await create_default_menu(db=db)
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
diff_menu = DeepDiff(menu_items.to_rest(), default_menu_dict.to_rest(), ignore_order=True)
|
|
112
|
+
|
|
113
|
+
if not diff_menu:
|
|
114
|
+
rprint("Menu Up to date, nothing to update")
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
await menu_repository.update_menu(existing_menu=menu_items, new_menu=default_menu_dict, menu_nodes=menu_nodes)
|
|
118
|
+
rprint("Menu has been updated")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
async def upgrade_permissions(db: InfrahubDatabase) -> None:
|
|
122
|
+
existing_permissions = await NodeManager.query(
|
|
123
|
+
schema=InfrahubKind.OBJECTPERMISSION,
|
|
124
|
+
db=db,
|
|
125
|
+
limit=1,
|
|
126
|
+
)
|
|
127
|
+
if existing_permissions:
|
|
128
|
+
rprint("Permissions Up to date, nothing to update")
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
await setup_permissions(db=db)
|
|
132
|
+
rprint("Permissions have been updated")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
async def setup_permissions(db: InfrahubDatabase) -> None:
|
|
136
|
+
existing_accounts = await NodeManager.query(
|
|
137
|
+
schema=InfrahubKind.ACCOUNT,
|
|
138
|
+
db=db,
|
|
139
|
+
limit=1,
|
|
140
|
+
)
|
|
141
|
+
administrator_role = await create_super_administrator_role(db=db)
|
|
142
|
+
await create_super_administrators_group(db=db, role=administrator_role, admin_accounts=existing_accounts)
|
|
143
|
+
await create_default_roles(db=db)
|
|
144
|
+
|
|
145
|
+
if config.SETTINGS.main.allow_anonymous_access:
|
|
146
|
+
await create_anonymous_role(db=db)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from prefect import task
|
|
7
|
+
from prefect.cache_policies import NONE
|
|
8
|
+
from prefect.logging import get_run_logger
|
|
9
|
+
|
|
10
|
+
from infrahub.core.constants import InfrahubKind
|
|
11
|
+
from infrahub.core.manager import NodeManager
|
|
12
|
+
from infrahub.core.protocols import CoreGenericRepository, CoreGraphQLQuery
|
|
13
|
+
from infrahub.core.registry import registry
|
|
14
|
+
from infrahub.database import InfrahubDatabase # noqa: TC001 needed for prefect flow
|
|
15
|
+
from infrahub.git.utils import get_repositories_commit_per_branch
|
|
16
|
+
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
|
|
17
|
+
from infrahub.graphql.initialization import prepare_graphql_params
|
|
18
|
+
|
|
19
|
+
from .models import (
|
|
20
|
+
ComputedAttrJinja2TriggerDefinition,
|
|
21
|
+
ComputedAttrPythonQueryTriggerDefinition,
|
|
22
|
+
ComputedAttrPythonTriggerDefinition,
|
|
23
|
+
PythonTransformComputedAttribute,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from infrahub.core.protocols import CoreTransformPython as CoreTransformPythonNode
|
|
28
|
+
from infrahub.git.models import RepositoryData
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@task(
|
|
32
|
+
name="gather-python-transform-attributes",
|
|
33
|
+
task_run_name="Gather Python transform attributes for {branch_name}",
|
|
34
|
+
cache_policy=NONE,
|
|
35
|
+
)
|
|
36
|
+
async def gather_python_transform_attributes(
|
|
37
|
+
db: InfrahubDatabase, branch_name: str, repositories: dict[str, RepositoryData] | None = None
|
|
38
|
+
) -> list[PythonTransformComputedAttribute]:
|
|
39
|
+
log = get_run_logger()
|
|
40
|
+
schema_branch = registry.schema.get_schema_branch(name=branch_name)
|
|
41
|
+
branches_with_diff_from_main = registry.get_altered_schema_branches()
|
|
42
|
+
branch = registry.get_branch_from_registry(branch=branch_name)
|
|
43
|
+
|
|
44
|
+
transform_attributes = schema_branch.computed_attributes.python_attributes_by_transform
|
|
45
|
+
|
|
46
|
+
transform_names = list(transform_attributes.keys())
|
|
47
|
+
|
|
48
|
+
if not transform_names:
|
|
49
|
+
return []
|
|
50
|
+
|
|
51
|
+
transforms: list[CoreTransformPythonNode] = await NodeManager.query(
|
|
52
|
+
db=db,
|
|
53
|
+
schema=InfrahubKind.TRANSFORMPYTHON,
|
|
54
|
+
branch=branch_name,
|
|
55
|
+
fields={"id": None, "name": None, "repository": None, "query": None},
|
|
56
|
+
filters={"name__values": transform_names},
|
|
57
|
+
prefetch_relationships=True,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
found_transforms_names = [transform.name.value for transform in transforms]
|
|
61
|
+
for transform_name in transform_names:
|
|
62
|
+
if transform_name not in found_transforms_names:
|
|
63
|
+
log.warning(
|
|
64
|
+
msg=f"The transform {transform_name} is assigned to a computed attribute but the transform could not be found in the database."
|
|
65
|
+
)
|
|
66
|
+
repositories = repositories or await get_repositories_commit_per_branch(db=db)
|
|
67
|
+
graphql_params = await prepare_graphql_params(db=db, branch=branch)
|
|
68
|
+
|
|
69
|
+
computed_attributes: list[PythonTransformComputedAttribute] = []
|
|
70
|
+
for transform in transforms:
|
|
71
|
+
repository = await transform.repository.get_peer(db=db, peer_type=CoreGenericRepository, raise_on_error=True)
|
|
72
|
+
query = await transform.query.get_peer(db=db, peer_type=CoreGraphQLQuery, raise_on_error=True)
|
|
73
|
+
query_analyzer = InfrahubGraphQLQueryAnalyzer(
|
|
74
|
+
query=query.query.value,
|
|
75
|
+
branch=branch,
|
|
76
|
+
schema_branch=schema_branch,
|
|
77
|
+
schema=graphql_params.schema,
|
|
78
|
+
)
|
|
79
|
+
for attribute in transform_attributes[transform.name.value]:
|
|
80
|
+
python_transform_computed_attribute = PythonTransformComputedAttribute(
|
|
81
|
+
name=transform.name.value,
|
|
82
|
+
branch_name=branch_name,
|
|
83
|
+
repository_id=repository.get_id(),
|
|
84
|
+
repository_name=repository.name.value,
|
|
85
|
+
repository_kind=repository.get_kind(),
|
|
86
|
+
query_analyzer=query_analyzer,
|
|
87
|
+
query_name=query.name.value,
|
|
88
|
+
computed_attribute=attribute,
|
|
89
|
+
default_schema=branch_name not in branches_with_diff_from_main,
|
|
90
|
+
)
|
|
91
|
+
python_transform_computed_attribute.populate_branch_commit(
|
|
92
|
+
repository_data=repositories.get(repository.name.value)
|
|
93
|
+
)
|
|
94
|
+
computed_attributes.append(python_transform_computed_attribute)
|
|
95
|
+
|
|
96
|
+
return computed_attributes
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@task(
|
|
100
|
+
name="gather-trigger-computed-attribute-jinja2",
|
|
101
|
+
cache_policy=NONE,
|
|
102
|
+
)
|
|
103
|
+
async def gather_trigger_computed_attribute_jinja2() -> list[ComputedAttrJinja2TriggerDefinition]:
|
|
104
|
+
log = get_run_logger()
|
|
105
|
+
|
|
106
|
+
# Build a list of all branches to process based on which branch is different from main
|
|
107
|
+
branches_with_diff_from_main = registry.get_altered_schema_branches()
|
|
108
|
+
branches_to_process: list[tuple[str, list[str]]] = [(branch, []) for branch in branches_with_diff_from_main]
|
|
109
|
+
branches_to_process.append((registry.default_branch, branches_with_diff_from_main))
|
|
110
|
+
|
|
111
|
+
triggers: list[ComputedAttrJinja2TriggerDefinition] = []
|
|
112
|
+
|
|
113
|
+
for branch_scope, branches_out_of_scope in branches_to_process:
|
|
114
|
+
schema_branch = registry.schema.get_schema_branch(name=branch_scope)
|
|
115
|
+
mapping = schema_branch.computed_attributes.get_jinja2_trigger_nodes()
|
|
116
|
+
|
|
117
|
+
log.info(f"Generating {len(mapping)} Jinja2 trigger for {branch_scope} (except {branches_out_of_scope})")
|
|
118
|
+
|
|
119
|
+
for computed_attribute, trigger_nodes in mapping.items():
|
|
120
|
+
for trigger_node in trigger_nodes:
|
|
121
|
+
trigger = ComputedAttrJinja2TriggerDefinition.from_computed_attribute(
|
|
122
|
+
branch=branch_scope,
|
|
123
|
+
computed_attribute=computed_attribute,
|
|
124
|
+
trigger_node=trigger_node,
|
|
125
|
+
branches_out_of_scope=branches_out_of_scope,
|
|
126
|
+
)
|
|
127
|
+
triggers.append(trigger)
|
|
128
|
+
|
|
129
|
+
return triggers
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@task(
|
|
133
|
+
name="gather-trigger-computed-attribute-python",
|
|
134
|
+
cache_policy=NONE,
|
|
135
|
+
)
|
|
136
|
+
async def gather_trigger_computed_attribute_python(
|
|
137
|
+
db: InfrahubDatabase,
|
|
138
|
+
) -> tuple[list[ComputedAttrPythonTriggerDefinition], list[ComputedAttrPythonQueryTriggerDefinition]]:
|
|
139
|
+
triggers_python = []
|
|
140
|
+
triggers_python_query = []
|
|
141
|
+
|
|
142
|
+
repositories = await get_repositories_commit_per_branch(db=db)
|
|
143
|
+
|
|
144
|
+
all_computed_attributes: dict[str, dict[str, PythonTransformComputedAttribute]] = defaultdict(dict)
|
|
145
|
+
for branch in list(registry.branch.values()):
|
|
146
|
+
if branch.is_global:
|
|
147
|
+
continue
|
|
148
|
+
|
|
149
|
+
computed_attributes = await gather_python_transform_attributes(
|
|
150
|
+
db=db, branch_name=branch.name, repositories=repositories
|
|
151
|
+
)
|
|
152
|
+
for computed_attribute in computed_attributes:
|
|
153
|
+
all_computed_attributes[computed_attribute.name][branch.name] = computed_attribute
|
|
154
|
+
|
|
155
|
+
for branches in all_computed_attributes.values():
|
|
156
|
+
branches_with_diff_from_main = []
|
|
157
|
+
if registry.default_branch in branches.keys():
|
|
158
|
+
commit_main = branches[registry.default_branch].repository_commit
|
|
159
|
+
branches_with_diff_from_main = [
|
|
160
|
+
branch_name for branch_name, item in branches.items() if item.repository_commit != commit_main
|
|
161
|
+
]
|
|
162
|
+
else:
|
|
163
|
+
branches_with_diff_from_main = list(branches.keys())
|
|
164
|
+
|
|
165
|
+
branches_to_process: list[tuple[str, list[str]]] = [(branch, []) for branch in branches_with_diff_from_main]
|
|
166
|
+
branches_to_process.append((registry.default_branch, branches_with_diff_from_main))
|
|
167
|
+
|
|
168
|
+
for branch_scope, branches_out_of_scope in branches_to_process:
|
|
169
|
+
trigger_python = ComputedAttrPythonTriggerDefinition.from_object(
|
|
170
|
+
computed_attribute=branches[branch_scope],
|
|
171
|
+
branch=branch_scope,
|
|
172
|
+
branches_out_of_scope=branches_out_of_scope,
|
|
173
|
+
)
|
|
174
|
+
triggers_python.append(trigger_python)
|
|
175
|
+
|
|
176
|
+
for kind in branches[branch_scope].query_analyzer.query_report.requested_read.keys():
|
|
177
|
+
trigger_python_query = ComputedAttrPythonQueryTriggerDefinition.from_object(
|
|
178
|
+
kind=kind,
|
|
179
|
+
computed_attribute=branches[branch_scope],
|
|
180
|
+
branch=branch_scope,
|
|
181
|
+
branches_out_of_scope=branches_out_of_scope,
|
|
182
|
+
)
|
|
183
|
+
triggers_python_query.append(trigger_python_query)
|
|
184
|
+
|
|
185
|
+
return triggers_python, triggers_python_query
|
|
@@ -5,15 +5,34 @@ from dataclasses import dataclass, field
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from prefect.events.schemas.automations import Automation # noqa: TC002
|
|
8
|
-
from pydantic import BaseModel, Field
|
|
8
|
+
from pydantic import BaseModel, ConfigDict, Field, computed_field
|
|
9
9
|
from typing_extensions import Self
|
|
10
10
|
|
|
11
|
+
from infrahub.core import registry
|
|
12
|
+
from infrahub.core.schema.schema_branch_computed import ( # noqa: TC001
|
|
13
|
+
ComputedAttributeTarget,
|
|
14
|
+
ComputedAttributeTriggerNode,
|
|
15
|
+
PythonDefinition,
|
|
16
|
+
)
|
|
17
|
+
from infrahub.events import NodeCreatedEvent, NodeUpdatedEvent
|
|
18
|
+
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer # noqa: TC001
|
|
19
|
+
from infrahub.trigger.constants import NAME_SEPARATOR
|
|
20
|
+
from infrahub.trigger.models import (
|
|
21
|
+
EventTrigger,
|
|
22
|
+
ExecuteWorkflow,
|
|
23
|
+
TriggerBranchDefinition,
|
|
24
|
+
TriggerType,
|
|
25
|
+
)
|
|
26
|
+
from infrahub.workflows.catalogue import (
|
|
27
|
+
COMPUTED_ATTRIBUTE_PROCESS_JINJA2,
|
|
28
|
+
COMPUTED_ATTRIBUTE_PROCESS_TRANSFORM,
|
|
29
|
+
QUERY_COMPUTED_ATTRIBUTE_TRANSFORM_TARGETS,
|
|
30
|
+
)
|
|
31
|
+
|
|
11
32
|
if TYPE_CHECKING:
|
|
12
33
|
from uuid import UUID
|
|
13
34
|
|
|
14
|
-
from
|
|
15
|
-
|
|
16
|
-
from infrahub.core.schema.schema_branch_computed import PythonDefinition
|
|
35
|
+
from infrahub.git.models import RepositoryData
|
|
17
36
|
|
|
18
37
|
|
|
19
38
|
class ComputedAttributeAutomations(BaseModel):
|
|
@@ -26,7 +45,7 @@ class ComputedAttributeAutomations(BaseModel):
|
|
|
26
45
|
if not automation.name.startswith(prefix):
|
|
27
46
|
continue
|
|
28
47
|
|
|
29
|
-
name_split = automation.name.split(
|
|
48
|
+
name_split = automation.name.split(NAME_SEPARATOR)
|
|
30
49
|
if len(name_split) != 3:
|
|
31
50
|
continue
|
|
32
51
|
|
|
@@ -47,9 +66,6 @@ class ComputedAttributeAutomations(BaseModel):
|
|
|
47
66
|
return True
|
|
48
67
|
return False
|
|
49
68
|
|
|
50
|
-
def return_obsolete(self, keep: list[UUID]) -> list[UUID]:
|
|
51
|
-
return [automation_id for automation_id in self.all_automation_ids if automation_id not in keep]
|
|
52
|
-
|
|
53
69
|
@property
|
|
54
70
|
def all_automation_ids(self) -> list[UUID]:
|
|
55
71
|
automation_ids: list[UUID] = []
|
|
@@ -59,25 +75,237 @@ class ComputedAttributeAutomations(BaseModel):
|
|
|
59
75
|
return automation_ids
|
|
60
76
|
|
|
61
77
|
|
|
62
|
-
|
|
63
|
-
|
|
78
|
+
class PythonTransformComputedAttribute(BaseModel):
|
|
79
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
64
80
|
name: str
|
|
65
81
|
repository_id: str
|
|
66
82
|
repository_name: str
|
|
67
83
|
repository_kind: str
|
|
68
84
|
query_name: str
|
|
69
|
-
|
|
85
|
+
query_analyzer: InfrahubGraphQLQueryAnalyzer
|
|
70
86
|
computed_attribute: PythonDefinition
|
|
71
87
|
default_schema: bool
|
|
88
|
+
branch_name: str
|
|
72
89
|
branch_commit: dict[str, str] = field(default_factory=dict)
|
|
73
90
|
|
|
91
|
+
@computed_field
|
|
92
|
+
def repository_commit(self) -> str:
|
|
93
|
+
return self.branch_commit[self.branch_name]
|
|
94
|
+
|
|
74
95
|
def populate_branch_commit(self, repository_data: RepositoryData | None = None) -> None:
|
|
75
96
|
if repository_data:
|
|
76
97
|
for branch, commit in repository_data.branches.items():
|
|
77
98
|
self.branch_commit[branch] = commit
|
|
78
99
|
|
|
100
|
+
def get_altered_branches(self) -> list[str]:
|
|
101
|
+
if registry.default_branch in self.branch_commit:
|
|
102
|
+
default_branch_commit = self.branch_commit[registry.default_branch]
|
|
103
|
+
return [
|
|
104
|
+
branch_name for branch_name, commit in self.branch_commit.items() if commit != default_branch_commit
|
|
105
|
+
]
|
|
106
|
+
return list(self.branch_commit.keys())
|
|
107
|
+
|
|
79
108
|
|
|
80
109
|
@dataclass
|
|
81
110
|
class PythonTransformTarget:
|
|
82
111
|
kind: str
|
|
83
112
|
object_id: str
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class ComputedAttrJinja2TriggerDefinition(TriggerBranchDefinition):
|
|
116
|
+
type: TriggerType = TriggerType.COMPUTED_ATTR_JINJA2
|
|
117
|
+
computed_attribute: ComputedAttributeTarget
|
|
118
|
+
|
|
119
|
+
@classmethod
|
|
120
|
+
def from_computed_attribute(
|
|
121
|
+
cls,
|
|
122
|
+
branch: str,
|
|
123
|
+
computed_attribute: ComputedAttributeTarget,
|
|
124
|
+
trigger_node: ComputedAttributeTriggerNode,
|
|
125
|
+
branches_out_of_scope: list[str] | None = None,
|
|
126
|
+
) -> Self:
|
|
127
|
+
"""
|
|
128
|
+
This function is used to create a trigger definition for a computed attribute of type Jinja2.
|
|
129
|
+
"""
|
|
130
|
+
event_trigger = EventTrigger()
|
|
131
|
+
event_trigger.events.add(NodeUpdatedEvent.event_name)
|
|
132
|
+
if computed_attribute.attribute.optional:
|
|
133
|
+
# If the computed attribute not optional it means that Infrahub will have assigned the value during
|
|
134
|
+
# the creation of the node so we don't need to match on node creation events as it would only add
|
|
135
|
+
# extra work that doesn't accomplish anything. For this reason the filter should only match on the
|
|
136
|
+
# node creation events if the attribute is optional.
|
|
137
|
+
event_trigger.events.add(NodeCreatedEvent.event_name)
|
|
138
|
+
|
|
139
|
+
event_trigger.match = {"infrahub.node.kind": trigger_node.kind}
|
|
140
|
+
if branches_out_of_scope:
|
|
141
|
+
event_trigger.match["infrahub.branch.name"] = [f"!{branch}" for branch in branches_out_of_scope]
|
|
142
|
+
elif not branches_out_of_scope and branch != registry.default_branch:
|
|
143
|
+
event_trigger.match["infrahub.branch.name"] = branch
|
|
144
|
+
|
|
145
|
+
event_trigger.match_related = {
|
|
146
|
+
"prefect.resource.role": ["infrahub.node.attribute_update", "infrahub.node.relationship_update"],
|
|
147
|
+
"infrahub.field.name": trigger_node.fields,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
workflow = ExecuteWorkflow(
|
|
151
|
+
workflow=COMPUTED_ATTRIBUTE_PROCESS_JINJA2,
|
|
152
|
+
parameters={
|
|
153
|
+
"branch_name": "{{ event.resource['infrahub.branch.name'] }}",
|
|
154
|
+
"node_kind": "{{ event.resource['infrahub.node.kind'] }}",
|
|
155
|
+
"object_id": "{{ event.resource['infrahub.node.id'] }}",
|
|
156
|
+
"computed_attribute_name": computed_attribute.attribute.name,
|
|
157
|
+
"computed_attribute_kind": computed_attribute.kind,
|
|
158
|
+
"updated_fields": {
|
|
159
|
+
"__prefect_kind": "json",
|
|
160
|
+
"value": {
|
|
161
|
+
"__prefect_kind": "jinja",
|
|
162
|
+
"template": "{{ event.payload['data']['fields'] | tojson }}",
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
"context": {
|
|
166
|
+
"__prefect_kind": "json",
|
|
167
|
+
"value": {
|
|
168
|
+
"__prefect_kind": "jinja",
|
|
169
|
+
"template": "{{ event.payload['context'] | tojson }}",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
definition = cls(
|
|
176
|
+
name=f"{computed_attribute.key_name}{NAME_SEPARATOR}kind{NAME_SEPARATOR}{trigger_node.kind}",
|
|
177
|
+
branch=branch,
|
|
178
|
+
computed_attribute=computed_attribute,
|
|
179
|
+
trigger=event_trigger,
|
|
180
|
+
actions=[workflow],
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return definition
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class ComputedAttrPythonTriggerDefinition(TriggerBranchDefinition):
|
|
187
|
+
type: TriggerType = TriggerType.COMPUTED_ATTR_PYTHON
|
|
188
|
+
computed_attribute: PythonTransformComputedAttribute
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def from_object(
|
|
192
|
+
cls,
|
|
193
|
+
branch: str,
|
|
194
|
+
computed_attribute: PythonTransformComputedAttribute,
|
|
195
|
+
branches_out_of_scope: list[str] | None = None,
|
|
196
|
+
) -> Self:
|
|
197
|
+
# scope = registry.default_branch
|
|
198
|
+
|
|
199
|
+
event_trigger = EventTrigger()
|
|
200
|
+
event_trigger.events.update({NodeCreatedEvent.event_name, NodeUpdatedEvent.event_name})
|
|
201
|
+
event_trigger.match = {
|
|
202
|
+
"infrahub.node.kind": [computed_attribute.computed_attribute.kind],
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if branches_out_of_scope:
|
|
206
|
+
event_trigger.match["infrahub.branch.name"] = [f"!{branch}" for branch in branches_out_of_scope]
|
|
207
|
+
elif not branches_out_of_scope and branch != registry.default_branch:
|
|
208
|
+
event_trigger.match["infrahub.branch.name"] = branch
|
|
209
|
+
|
|
210
|
+
update_fields = computed_attribute.query_analyzer.query_report.fields_by_kind(
|
|
211
|
+
kind=computed_attribute.computed_attribute.kind
|
|
212
|
+
)
|
|
213
|
+
event_trigger.match_related = {
|
|
214
|
+
"prefect.resource.role": ["infrahub.node.attribute_update", "infrahub.node.relationship_update"],
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if update_fields and "display_label" not in update_fields:
|
|
218
|
+
# The GraphQLQuery analyzer doesn't yet support figuring out which updates would match the "display label"
|
|
219
|
+
# of a query. Because of this we temporarily match any field if the display_label is part of the computed
|
|
220
|
+
# attribute query
|
|
221
|
+
event_trigger.match_related["infrahub.field.name"] = update_fields
|
|
222
|
+
|
|
223
|
+
definition = cls(
|
|
224
|
+
name=computed_attribute.computed_attribute.key_name,
|
|
225
|
+
branch=branch,
|
|
226
|
+
computed_attribute=computed_attribute,
|
|
227
|
+
trigger=event_trigger,
|
|
228
|
+
actions=[
|
|
229
|
+
ExecuteWorkflow(
|
|
230
|
+
workflow=COMPUTED_ATTRIBUTE_PROCESS_TRANSFORM,
|
|
231
|
+
parameters={
|
|
232
|
+
"branch_name": "{{ event.resource['infrahub.branch.name'] }}",
|
|
233
|
+
"node_kind": "{{ event.resource['infrahub.node.kind'] }}",
|
|
234
|
+
"object_id": "{{ event.resource['infrahub.node.id'] }}",
|
|
235
|
+
"computed_attribute_name": computed_attribute.computed_attribute.attribute.name,
|
|
236
|
+
"computed_attribute_kind": computed_attribute.computed_attribute.kind,
|
|
237
|
+
"context": {
|
|
238
|
+
"__prefect_kind": "json",
|
|
239
|
+
"value": {
|
|
240
|
+
"__prefect_kind": "jinja",
|
|
241
|
+
"template": "{{ event.payload['context'] | tojson }}",
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
),
|
|
246
|
+
],
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
return definition
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class ComputedAttrPythonQueryTriggerDefinition(TriggerBranchDefinition):
|
|
253
|
+
type: TriggerType = TriggerType.COMPUTED_ATTR_PYTHON_QUERY
|
|
254
|
+
|
|
255
|
+
@classmethod
|
|
256
|
+
def from_object(
|
|
257
|
+
cls,
|
|
258
|
+
branch: str,
|
|
259
|
+
kind: str,
|
|
260
|
+
computed_attribute: PythonTransformComputedAttribute,
|
|
261
|
+
branches_out_of_scope: list[str] | None = None,
|
|
262
|
+
) -> Self:
|
|
263
|
+
# Only matching on node updated events, before nodes are created they won't be a member of the GraphQL query
|
|
264
|
+
# group regardless so it doesn't make sense to trigger the query on node creation. For the initial object
|
|
265
|
+
# where the computed attribute belongs that to will need to be created first which will trigger its own initial
|
|
266
|
+
# process to populated the original members of the GraphQL query group
|
|
267
|
+
event_trigger = EventTrigger(events={NodeUpdatedEvent.event_name})
|
|
268
|
+
event_trigger.match = {
|
|
269
|
+
"infrahub.node.kind": kind,
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
update_fields = computed_attribute.query_analyzer.query_report.fields_by_kind(kind=kind)
|
|
273
|
+
event_trigger.match_related = {
|
|
274
|
+
"prefect.resource.role": ["infrahub.node.attribute_update", "infrahub.node.relationship_update"],
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if update_fields and "display_label" not in update_fields:
|
|
278
|
+
# The GraphQLQuery analyzer doesn't yet support figuring out which updates would match the "display label"
|
|
279
|
+
# of a query. Because of this we temporarily match any field if the display_label is part of the computed
|
|
280
|
+
# attribute query
|
|
281
|
+
event_trigger.match_related["infrahub.field.name"] = update_fields
|
|
282
|
+
|
|
283
|
+
if branches_out_of_scope:
|
|
284
|
+
event_trigger.match["infrahub.branch.name"] = [f"!{branch}" for branch in branches_out_of_scope]
|
|
285
|
+
elif not branches_out_of_scope and branch != registry.default_branch:
|
|
286
|
+
event_trigger.match["infrahub.branch.name"] = branch
|
|
287
|
+
|
|
288
|
+
definition = cls(
|
|
289
|
+
name=f"{computed_attribute.computed_attribute.key_name}{NAME_SEPARATOR}kind{NAME_SEPARATOR}{kind}",
|
|
290
|
+
branch=branch,
|
|
291
|
+
trigger=event_trigger,
|
|
292
|
+
actions=[
|
|
293
|
+
ExecuteWorkflow(
|
|
294
|
+
workflow=QUERY_COMPUTED_ATTRIBUTE_TRANSFORM_TARGETS,
|
|
295
|
+
parameters={
|
|
296
|
+
"branch_name": "{{ event.resource['infrahub.branch.name'] }}",
|
|
297
|
+
"node_kind": "{{ event.resource['infrahub.node.kind'] }}",
|
|
298
|
+
"object_id": "{{ event.resource['infrahub.node.id'] }}",
|
|
299
|
+
"context": {
|
|
300
|
+
"__prefect_kind": "json",
|
|
301
|
+
"value": {
|
|
302
|
+
"__prefect_kind": "jinja",
|
|
303
|
+
"template": "{{ event.payload['context'] | tojson }}",
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
),
|
|
308
|
+
],
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
return definition
|