infrahub-server 1.2.0rc0__py3-none-any.whl → 1.2.2__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 +72 -432
- 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 +98 -37
- 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 +62 -26
- infrahub/generators/models.py +2 -3
- infrahub/generators/tasks.py +24 -4
- infrahub/git/base.py +87 -36
- infrahub/git/integrator.py +48 -48
- 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 -83
- 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 +15 -6
- 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 +73 -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.2.dist-info}/METADATA +8 -6
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/RECORD +349 -293
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.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.2.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/WHEEL +0 -0
infrahub/webhook/models.py
CHANGED
|
@@ -1,64 +1,175 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import base64
|
|
2
4
|
import hashlib
|
|
3
5
|
import hmac
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from typing import Any, Optional, Union
|
|
7
|
-
from uuid import uuid4
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
from uuid import UUID, uuid4
|
|
8
8
|
|
|
9
|
-
from
|
|
10
|
-
from
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field, computed_field
|
|
10
|
+
from typing_extensions import Self
|
|
11
11
|
|
|
12
|
+
from infrahub.core import registry
|
|
12
13
|
from infrahub.core.constants import InfrahubKind
|
|
14
|
+
from infrahub.core.timestamp import Timestamp
|
|
15
|
+
from infrahub.events.utils import get_all_infrahub_node_kind_events
|
|
13
16
|
from infrahub.git.repository import InfrahubReadOnlyRepository, InfrahubRepository
|
|
14
|
-
from infrahub.
|
|
15
|
-
from infrahub.
|
|
17
|
+
from infrahub.trigger.constants import NAME_SEPARATOR
|
|
18
|
+
from infrahub.trigger.models import EventTrigger, ExecuteWorkflow, TriggerDefinition, TriggerType
|
|
19
|
+
from infrahub.workflows.catalogue import WEBHOOK_PROCESS
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from httpx import Response
|
|
23
|
+
from infrahub_sdk.protocols import CoreCustomWebhook, CoreStandardWebhook, CoreTransformPython, CoreWebhook
|
|
24
|
+
|
|
25
|
+
from infrahub.core.protocols import CoreWebhook as CoreWebhookNode
|
|
26
|
+
from infrahub.services import InfrahubServices
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class WebhookTriggerDefinition(TriggerDefinition):
|
|
30
|
+
id: str
|
|
31
|
+
type: TriggerType = TriggerType.WEBHOOK
|
|
32
|
+
|
|
33
|
+
def generate_name(self) -> str:
|
|
34
|
+
return f"{self.type.value}{NAME_SEPARATOR}{self.id}"
|
|
16
35
|
|
|
36
|
+
@classmethod
|
|
37
|
+
def generate_name_from_id(cls, id: str) -> str:
|
|
38
|
+
return f"{TriggerType.WEBHOOK.value}{NAME_SEPARATOR}{id}"
|
|
17
39
|
|
|
18
|
-
|
|
19
|
-
|
|
40
|
+
@classmethod
|
|
41
|
+
def from_object(cls, obj: CoreWebhook | CoreWebhookNode) -> Self:
|
|
42
|
+
event_trigger = EventTrigger()
|
|
43
|
+
if obj.event_type.value == "all":
|
|
44
|
+
event_trigger.events.add("infrahub.*")
|
|
45
|
+
else:
|
|
46
|
+
event_trigger.events.add(obj.event_type.value)
|
|
47
|
+
|
|
48
|
+
if obj.branch_scope.value == "default_branch":
|
|
49
|
+
event_trigger.match_related = {
|
|
50
|
+
"prefect.resource.role": "infrahub.branch",
|
|
51
|
+
"infrahub.resource.label": registry.default_branch,
|
|
52
|
+
}
|
|
53
|
+
elif obj.branch_scope.value == "other_branches":
|
|
54
|
+
event_trigger.match_related = {
|
|
55
|
+
"prefect.resource.role": "infrahub.branch",
|
|
56
|
+
"infrahub.resource.label": f"!{registry.default_branch}",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if obj.node_kind.value and obj.event_type.value in get_all_infrahub_node_kind_events():
|
|
60
|
+
event_trigger.match = {"infrahub.node.kind": obj.node_kind.value}
|
|
61
|
+
|
|
62
|
+
definition = cls(
|
|
63
|
+
id=obj.id,
|
|
64
|
+
name=obj.name.value,
|
|
65
|
+
trigger=event_trigger,
|
|
66
|
+
actions=[
|
|
67
|
+
ExecuteWorkflow(
|
|
68
|
+
workflow=WEBHOOK_PROCESS,
|
|
69
|
+
parameters={
|
|
70
|
+
"webhook_id": obj.id,
|
|
71
|
+
"webhook_name": obj.name.value,
|
|
72
|
+
"webhook_kind": obj.get_kind(),
|
|
73
|
+
"branch_name": "{{ event.resource['infrahub.branch.name'] }}",
|
|
74
|
+
"event_id": "{{ event.id }}",
|
|
75
|
+
"event_type": "{{ event.event }}",
|
|
76
|
+
"event_occured_at": "{{ event.occurred }}",
|
|
77
|
+
"event_payload": {
|
|
78
|
+
"__prefect_kind": "json",
|
|
79
|
+
"value": {"__prefect_kind": "jinja", "template": "{{ event.payload | tojson }}"},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
),
|
|
83
|
+
],
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
return definition
|
|
20
87
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
88
|
+
|
|
89
|
+
class EventContext(BaseModel):
|
|
90
|
+
id: str = Field(..., description="The internal id of the event")
|
|
91
|
+
branch: str | None = Field(None, description="The branch associated with the event")
|
|
92
|
+
account_id: str | None = Field(None, description="The id of the account associated with the event")
|
|
93
|
+
occured_at: str = Field(..., description="The time when the event occurred")
|
|
94
|
+
event: str = Field(..., description="The event type")
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def from_event(cls, event_id: str, event_type: str, event_occured_at: str, event_payload: dict[str, Any]) -> Self:
|
|
98
|
+
"""Extract the context from the raw event we are getting from Prefect."""
|
|
99
|
+
|
|
100
|
+
infrahub_context: dict[str, Any] = event_payload.get("context", {})
|
|
101
|
+
account_info: dict[str, Any] = infrahub_context.get("account", {})
|
|
102
|
+
branch_info: dict[str, Any] = infrahub_context.get("branch", {})
|
|
103
|
+
|
|
104
|
+
return cls(
|
|
105
|
+
id=event_id,
|
|
106
|
+
branch=branch_info.get("name")
|
|
107
|
+
if branch_info and branch_info.get("name") != registry.get_global_branch().name
|
|
108
|
+
else None,
|
|
109
|
+
account_id=account_info.get("account_id"),
|
|
110
|
+
occured_at=event_occured_at,
|
|
111
|
+
event=event_type,
|
|
112
|
+
)
|
|
24
113
|
|
|
25
114
|
|
|
26
115
|
class Webhook(BaseModel):
|
|
27
116
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
28
|
-
|
|
117
|
+
name: str = Field(...)
|
|
29
118
|
url: str = Field(...)
|
|
30
119
|
event_type: str = Field(...)
|
|
31
|
-
data: dict[str, Any] = Field(...)
|
|
32
120
|
validate_certificates: bool = Field(...)
|
|
33
121
|
_payload: Any = None
|
|
34
|
-
_headers:
|
|
122
|
+
_headers: dict[str, Any] | None = None
|
|
35
123
|
|
|
36
|
-
async def _prepare_payload(self) -> None:
|
|
37
|
-
self._payload = {"
|
|
124
|
+
async def _prepare_payload(self, data: dict[str, Any], context: EventContext, service: InfrahubServices) -> None: # noqa: ARG002
|
|
125
|
+
self._payload = {"data": data, **context.model_dump()}
|
|
38
126
|
|
|
39
127
|
def _assign_headers(self) -> None:
|
|
40
128
|
self._headers = {}
|
|
41
129
|
|
|
130
|
+
@computed_field # type: ignore[prop-decorator]
|
|
42
131
|
@property
|
|
43
132
|
def webhook_type(self) -> str:
|
|
44
133
|
return self.__class__.__name__
|
|
45
134
|
|
|
46
|
-
async def
|
|
47
|
-
await self._prepare_payload()
|
|
135
|
+
async def prepare(self, data: dict[str, Any], context: EventContext, service: InfrahubServices) -> None:
|
|
136
|
+
await self._prepare_payload(data=data, context=context, service=service)
|
|
48
137
|
self._assign_headers()
|
|
49
|
-
|
|
138
|
+
|
|
139
|
+
async def send(self, data: dict[str, Any], context: EventContext, service: InfrahubServices) -> Response:
|
|
140
|
+
await self.prepare(data=data, context=context, service=service)
|
|
141
|
+
return await service.http.post(url=self.url, json=self.get_payload(), headers=self._headers)
|
|
142
|
+
|
|
143
|
+
def get_payload(self) -> dict[str, Any]:
|
|
144
|
+
return self._payload
|
|
145
|
+
|
|
146
|
+
def to_cache(self) -> dict[str, Any]:
|
|
147
|
+
return self.model_dump()
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
def from_cache(cls, data: dict[str, Any]) -> Self:
|
|
151
|
+
return cls(**data)
|
|
50
152
|
|
|
51
153
|
|
|
52
154
|
class CustomWebhook(Webhook):
|
|
53
155
|
"""Custom webhook"""
|
|
54
156
|
|
|
157
|
+
@classmethod
|
|
158
|
+
def from_object(cls, obj: CoreCustomWebhook) -> Self:
|
|
159
|
+
return cls(
|
|
160
|
+
name=obj.name.value,
|
|
161
|
+
url=obj.url.value,
|
|
162
|
+
event_type=obj.event_type.value,
|
|
163
|
+
validate_certificates=obj.validate_certificates.value or False,
|
|
164
|
+
)
|
|
165
|
+
|
|
55
166
|
|
|
56
167
|
class StandardWebhook(Webhook):
|
|
57
|
-
shared_key:
|
|
168
|
+
shared_key: str = Field(...)
|
|
58
169
|
|
|
59
|
-
def _assign_headers(self) -> None:
|
|
60
|
-
message_id = f"msg_{uuid4().hex}"
|
|
61
|
-
timestamp = str(
|
|
170
|
+
def _assign_headers(self, uuid: UUID | None = None, at: Timestamp | None = None) -> None:
|
|
171
|
+
message_id = f"msg_{uuid.hex}" if uuid else f"msg_{uuid4().hex}"
|
|
172
|
+
timestamp = str(at.to_timestamp()) if at else str(Timestamp().to_timestamp())
|
|
62
173
|
payload = self._payload or {}
|
|
63
174
|
unsigned_data = f"{message_id}.{timestamp}.{payload}".encode()
|
|
64
175
|
signature = self._sign(data=unsigned_data)
|
|
@@ -72,7 +183,17 @@ class StandardWebhook(Webhook):
|
|
|
72
183
|
}
|
|
73
184
|
|
|
74
185
|
def _sign(self, data: bytes) -> bytes:
|
|
75
|
-
return hmac.new(key=self.shared_key, msg=data, digestmod=hashlib.sha256).digest()
|
|
186
|
+
return hmac.new(key=self.shared_key.encode(), msg=data, digestmod=hashlib.sha256).digest()
|
|
187
|
+
|
|
188
|
+
@classmethod
|
|
189
|
+
def from_object(cls, obj: CoreStandardWebhook) -> Self:
|
|
190
|
+
return cls(
|
|
191
|
+
name=obj.name.value,
|
|
192
|
+
url=obj.url.value,
|
|
193
|
+
event_type=obj.event_type.value,
|
|
194
|
+
validate_certificates=obj.validate_certificates.value or False,
|
|
195
|
+
shared_key=obj.shared_key.value,
|
|
196
|
+
)
|
|
76
197
|
|
|
77
198
|
|
|
78
199
|
class TransformWebhook(Webhook):
|
|
@@ -82,37 +203,48 @@ class TransformWebhook(Webhook):
|
|
|
82
203
|
transform_name: str = Field(...)
|
|
83
204
|
transform_class: str = Field(...)
|
|
84
205
|
transform_file: str = Field(...)
|
|
206
|
+
transform_timeout: int = Field(...)
|
|
85
207
|
|
|
86
|
-
async def _prepare_payload(self) -> None:
|
|
87
|
-
repo:
|
|
208
|
+
async def _prepare_payload(self, data: dict[str, Any], context: EventContext, service: InfrahubServices) -> None:
|
|
209
|
+
repo: InfrahubReadOnlyRepository | InfrahubRepository
|
|
88
210
|
if self.repository_kind == InfrahubKind.READONLYREPOSITORY:
|
|
89
211
|
repo = await InfrahubReadOnlyRepository.init(
|
|
90
212
|
id=self.repository_id,
|
|
91
213
|
name=self.repository_name,
|
|
92
|
-
client=
|
|
93
|
-
service=
|
|
214
|
+
client=service.client,
|
|
215
|
+
service=service,
|
|
94
216
|
)
|
|
95
217
|
else:
|
|
96
218
|
repo = await InfrahubRepository.init(
|
|
97
219
|
id=self.repository_id,
|
|
98
220
|
name=self.repository_name,
|
|
99
|
-
client=
|
|
100
|
-
service=
|
|
221
|
+
client=service.client,
|
|
222
|
+
service=service,
|
|
101
223
|
)
|
|
102
224
|
|
|
103
|
-
|
|
104
|
-
commit = repo.get_commit_value(branch_name=
|
|
105
|
-
|
|
106
|
-
timeout = DEFAULT_TRANSFORM_TIMEOUT
|
|
107
|
-
if transform := await self.service.client.get(
|
|
108
|
-
kind=CoreTransformPython, name__value=self.transform_name, raise_when_missing=False
|
|
109
|
-
):
|
|
110
|
-
timeout = transform.timeout.value
|
|
225
|
+
branch = context.branch or repo.default_branch
|
|
226
|
+
commit = repo.get_commit_value(branch_name=branch)
|
|
111
227
|
|
|
112
|
-
self._payload = await repo.execute_python_transform.with_options(timeout_seconds=
|
|
113
|
-
branch_name=
|
|
228
|
+
self._payload = await repo.execute_python_transform.with_options(timeout_seconds=self.transform_timeout)(
|
|
229
|
+
branch_name=branch,
|
|
114
230
|
commit=commit,
|
|
115
231
|
location=f"{self.transform_file}::{self.transform_class}",
|
|
116
|
-
data={"
|
|
117
|
-
client=
|
|
232
|
+
data={"data": data, **context.model_dump()},
|
|
233
|
+
client=service.client,
|
|
234
|
+
) # type: ignore[misc]
|
|
235
|
+
|
|
236
|
+
@classmethod
|
|
237
|
+
def from_object(cls, obj: CoreCustomWebhook, transform: CoreTransformPython) -> Self:
|
|
238
|
+
return cls(
|
|
239
|
+
name=obj.name.value,
|
|
240
|
+
url=obj.url.value,
|
|
241
|
+
event_type=obj.event_type.value,
|
|
242
|
+
validate_certificates=obj.validate_certificates.value or False,
|
|
243
|
+
repository_id=transform.repository.id,
|
|
244
|
+
repository_name=transform.repository.peer.name.value,
|
|
245
|
+
repository_kind=transform.repository.peer.get_kind(),
|
|
246
|
+
transform_name=transform.name.value,
|
|
247
|
+
transform_class=transform.class_name.value,
|
|
248
|
+
transform_file=transform.file_path.value,
|
|
249
|
+
transform_timeout=transform.timeout.value,
|
|
118
250
|
)
|
infrahub/webhook/tasks.py
CHANGED
|
@@ -1,182 +1,181 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
import ujson
|
|
5
|
-
from infrahub_sdk
|
|
6
|
-
from
|
|
6
|
+
from infrahub_sdk import InfrahubClient # noqa: TC002 needed for prefect flow
|
|
7
|
+
from infrahub_sdk.protocols import CoreTransformPython, CoreWebhook
|
|
8
|
+
from prefect import flow, task
|
|
7
9
|
from prefect.automations import AutomationCore
|
|
10
|
+
from prefect.cache_policies import NONE
|
|
8
11
|
from prefect.client.orchestration import get_client
|
|
9
|
-
from prefect.client.schemas.filters import DeploymentFilter, DeploymentFilterName
|
|
10
|
-
from prefect.events.actions import RunDeployment
|
|
11
|
-
from prefect.events.schemas.automations import EventTrigger, Posture
|
|
12
|
-
from prefect.events.schemas.events import ResourceSpecification
|
|
13
12
|
from prefect.logging import get_run_logger
|
|
14
13
|
|
|
15
|
-
from infrahub.
|
|
16
|
-
from infrahub.
|
|
17
|
-
from infrahub.
|
|
18
|
-
from infrahub.
|
|
14
|
+
from infrahub.message_bus.types import KVTTL
|
|
15
|
+
from infrahub.services import InfrahubServices # noqa: TC001 needed for prefect flow
|
|
16
|
+
from infrahub.trigger.models import TriggerType
|
|
17
|
+
from infrahub.trigger.setup import setup_triggers
|
|
18
|
+
from infrahub.workflows.utils import add_tags
|
|
19
19
|
|
|
20
|
-
from .
|
|
21
|
-
from .models import CustomWebhook,
|
|
20
|
+
from .gather import gather_trigger_webhook
|
|
21
|
+
from .models import CustomWebhook, EventContext, StandardWebhook, TransformWebhook, Webhook, WebhookTriggerDefinition
|
|
22
22
|
|
|
23
23
|
if TYPE_CHECKING:
|
|
24
|
-
from
|
|
24
|
+
from httpx import Response
|
|
25
25
|
|
|
26
|
+
WEBHOOK_MAP: dict[str, type[Webhook]] = {
|
|
27
|
+
"StandardWebhook": StandardWebhook,
|
|
28
|
+
"CustomWebhook": CustomWebhook,
|
|
29
|
+
"TransformWebhook": TransformWebhook,
|
|
30
|
+
}
|
|
26
31
|
|
|
27
|
-
@flow(name="event-send-webhook", flow_run_name="Send Webhook")
|
|
28
|
-
async def send_webhook(model: SendWebhookData, service: InfrahubServices) -> None:
|
|
29
|
-
log = get_run_logger()
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
@task(name="webhook-send", task_run_name="Send Standard Webhook {webhook.name}", cache_policy=NONE, retries=3)
|
|
34
|
+
async def webhook_send(
|
|
35
|
+
webhook: Webhook, context: EventContext, event_data: dict, service: InfrahubServices
|
|
36
|
+
) -> Response:
|
|
37
|
+
response = await webhook.send(data=event_data, context=context, service=service)
|
|
38
|
+
response.raise_for_status()
|
|
39
|
+
return response
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@task(name="webhook-convert-node", task_run_name="Convert node to webhook", cache_policy=NONE)
|
|
43
|
+
async def convert_node_to_webhook(webhook_node: CoreWebhook, client: InfrahubClient) -> Webhook:
|
|
44
|
+
webhook_kind = webhook_node.get_kind()
|
|
45
|
+
|
|
46
|
+
if webhook_kind not in ["CoreStandardWebhook", "CoreCustomWebhook"]:
|
|
47
|
+
raise ValueError(f"Unsupported webhook kind: {webhook_kind}")
|
|
48
|
+
|
|
49
|
+
if webhook_kind == "CoreStandardWebhook":
|
|
50
|
+
return StandardWebhook.from_object(obj=webhook_node)
|
|
51
|
+
|
|
52
|
+
# Processing Custom Webhook
|
|
53
|
+
if webhook_node.transformation.id:
|
|
54
|
+
transform = await client.get(
|
|
55
|
+
kind=CoreTransformPython,
|
|
56
|
+
id=webhook_node.transformation.id,
|
|
57
|
+
prefetch_relationships=True,
|
|
58
|
+
include=["name", "class_name", "file_path", "repository"],
|
|
36
59
|
)
|
|
60
|
+
return TransformWebhook.from_object(obj=webhook_node, transform=transform)
|
|
61
|
+
|
|
62
|
+
return CustomWebhook.from_object(obj=webhook_node)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@flow(name="webhook-process", flow_run_name="Send webhook for {webhook_name}")
|
|
66
|
+
async def webhook_process(
|
|
67
|
+
webhook_id: str,
|
|
68
|
+
webhook_name: str, # noqa: ARG001
|
|
69
|
+
webhook_kind: str,
|
|
70
|
+
event_id: str,
|
|
71
|
+
event_type: str,
|
|
72
|
+
event_occured_at: str,
|
|
73
|
+
event_payload: dict,
|
|
74
|
+
service: InfrahubServices,
|
|
75
|
+
branch_name: str | None = None,
|
|
76
|
+
) -> None:
|
|
77
|
+
log = get_run_logger()
|
|
78
|
+
|
|
79
|
+
if branch_name:
|
|
80
|
+
await add_tags(branches=[branch_name])
|
|
81
|
+
|
|
82
|
+
webhook_data_str = await service.cache.get(key=f"webhook:{webhook_id}")
|
|
83
|
+
if not webhook_data_str:
|
|
84
|
+
log.info(f"Webhook {webhook_id} not found in cache")
|
|
85
|
+
webhook_node = await service.client.get(kind=webhook_kind, id=webhook_id)
|
|
86
|
+
webhook = await convert_node_to_webhook(webhook_node=webhook_node, client=service.client)
|
|
87
|
+
webhook_data = webhook.to_cache()
|
|
88
|
+
await service.cache.set(key=f"webhook:{webhook_id}", value=ujson.dumps(webhook_data), expires=KVTTL.TWO_HOURS)
|
|
89
|
+
|
|
90
|
+
else:
|
|
91
|
+
webhook_data = ujson.loads(webhook_data_str)
|
|
92
|
+
|
|
93
|
+
if webhook_data["webhook_type"] not in WEBHOOK_MAP:
|
|
94
|
+
raise ValueError(f"Unsupported webhook kind: {webhook_data['webhook_type']}")
|
|
95
|
+
|
|
96
|
+
webhook_class = WEBHOOK_MAP[webhook_data["webhook_type"]]
|
|
97
|
+
webhook = webhook_class.from_cache(webhook_data)
|
|
37
98
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
webhook = webhook_class(**payload)
|
|
48
|
-
await webhook.send()
|
|
99
|
+
webhook_context = EventContext.from_event(
|
|
100
|
+
event_id=event_id,
|
|
101
|
+
event_type=event_type,
|
|
102
|
+
event_occured_at=event_occured_at,
|
|
103
|
+
event_payload=event_payload,
|
|
104
|
+
)
|
|
105
|
+
event_data = event_payload.get("data", {})
|
|
106
|
+
response = await webhook_send(webhook=webhook, context=webhook_context, event_data=event_data, service=service)
|
|
107
|
+
log.info(f"Successfully sent webhook to {response.url} with status {response.status_code}")
|
|
49
108
|
|
|
50
|
-
log.info("Successfully sent webhook")
|
|
51
109
|
|
|
110
|
+
@flow(name="webhook-setup-automation-all", flow_run_name="Configure all webhooks")
|
|
111
|
+
async def configure_webhook_all(service: InfrahubServices) -> None:
|
|
112
|
+
log = get_run_logger()
|
|
113
|
+
|
|
114
|
+
triggers = await gather_trigger_webhook(db=service.database)
|
|
52
115
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
await service.workflow.submit_workflow(workflow=WEBHOOK_SEND, parameters={"model": model})
|
|
116
|
+
async with get_client(sync_client=False) as prefect_client:
|
|
117
|
+
await setup_triggers(
|
|
118
|
+
client=prefect_client,
|
|
119
|
+
triggers=triggers,
|
|
120
|
+
trigger_type=TriggerType.WEBHOOK,
|
|
121
|
+
) # type: ignore[misc]
|
|
60
122
|
|
|
123
|
+
log.info(f"{len(triggers)} Webhooks automation configuration completed")
|
|
61
124
|
|
|
62
|
-
|
|
63
|
-
|
|
125
|
+
|
|
126
|
+
@flow(name="webhook-setup-automation-one", flow_run_name="Configurate webhook for {webhook_name}")
|
|
127
|
+
async def configure_webhook_one(
|
|
128
|
+
webhook_name: str, # noqa: ARG001
|
|
129
|
+
event_data: dict,
|
|
130
|
+
service: InfrahubServices,
|
|
131
|
+
) -> None:
|
|
64
132
|
log = get_run_logger()
|
|
65
133
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
expected_webhooks.append(webhook_key)
|
|
74
|
-
standard_payload = {
|
|
75
|
-
"webhook_type": "standard",
|
|
76
|
-
"webhook_configuration": {
|
|
77
|
-
"url": webhook.url.value,
|
|
78
|
-
"shared_key": webhook.shared_key.value,
|
|
79
|
-
"validate_certificates": webhook.validate_certificates.value,
|
|
80
|
-
},
|
|
81
|
-
}
|
|
82
|
-
await service.cache.set(key=webhook_key, value=ujson.dumps(standard_payload))
|
|
83
|
-
|
|
84
|
-
for webhook in custom_webhooks:
|
|
85
|
-
webhook_key = f"webhook:active:{webhook.id}"
|
|
86
|
-
expected_webhooks.append(webhook_key)
|
|
87
|
-
payload: dict[str, Any] = {
|
|
88
|
-
"webhook_type": "custom",
|
|
89
|
-
"webhook_configuration": {
|
|
90
|
-
"url": webhook.url.value,
|
|
91
|
-
"validate_certificates": webhook.validate_certificates.value,
|
|
92
|
-
},
|
|
93
|
-
}
|
|
94
|
-
if webhook.transformation.id:
|
|
95
|
-
transform = await service.client.get(
|
|
96
|
-
kind=CoreTransformPython,
|
|
97
|
-
id=webhook.transformation.id,
|
|
98
|
-
prefetch_relationships=True,
|
|
99
|
-
populate_store=True,
|
|
100
|
-
include=["name", "class_name", "file_path", "repository"],
|
|
101
|
-
)
|
|
102
|
-
payload["webhook_type"] = "transform"
|
|
103
|
-
payload["webhook_configuration"]["transform_name"] = transform.name.value
|
|
104
|
-
payload["webhook_configuration"]["transform_class"] = transform.class_name.value
|
|
105
|
-
payload["webhook_configuration"]["transform_file"] = transform.file_path.value
|
|
106
|
-
payload["webhook_configuration"]["repository_id"] = transform.repository.id
|
|
107
|
-
payload["webhook_configuration"]["repository_name"] = transform.repository.peer.name.value
|
|
108
|
-
|
|
109
|
-
await service.cache.set(key=webhook_key, value=ujson.dumps(payload))
|
|
110
|
-
|
|
111
|
-
cached_webhooks = await service.cache.list_keys(filter_pattern="webhook:active:*")
|
|
112
|
-
for cached_webhook in cached_webhooks:
|
|
113
|
-
if cached_webhook not in expected_webhooks:
|
|
114
|
-
await service.cache.delete(key=cached_webhook)
|
|
115
|
-
|
|
116
|
-
has_webhooks = bool(expected_webhooks)
|
|
117
|
-
|
|
118
|
-
async with get_client(sync_client=False) as client:
|
|
119
|
-
deployments = {
|
|
120
|
-
item.name: item
|
|
121
|
-
for item in await client.read_deployments(
|
|
122
|
-
deployment_filter=DeploymentFilter(
|
|
123
|
-
name=DeploymentFilterName(
|
|
124
|
-
any_=[
|
|
125
|
-
WEBHOOK_TRIGGER.name,
|
|
126
|
-
]
|
|
127
|
-
)
|
|
128
|
-
)
|
|
129
|
-
)
|
|
130
|
-
}
|
|
131
|
-
if WEBHOOK_TRIGGER.name not in deployments:
|
|
132
|
-
raise ValueError("Unable to find the deployment for WEBHOOK_TRIGGER")
|
|
133
|
-
|
|
134
|
-
deployment_id_webhook_trigger = deployments[WEBHOOK_TRIGGER.name].id
|
|
135
|
-
|
|
136
|
-
webhook_configure_automation: Automation | None = None
|
|
137
|
-
automations = await client.read_automations_by_name(name=AUTOMATION_NAME_RUN)
|
|
138
|
-
if automations:
|
|
139
|
-
webhook_configure_automation = automations[0]
|
|
140
|
-
|
|
141
|
-
if not has_webhooks:
|
|
142
|
-
if webhook_configure_automation:
|
|
143
|
-
await client.delete_automation(automation_id=webhook_configure_automation.id)
|
|
144
|
-
return
|
|
134
|
+
webhook = await service.client.get(kind=CoreWebhook, id=event_data["node_id"])
|
|
135
|
+
trigger = WebhookTriggerDefinition.from_object(webhook)
|
|
136
|
+
|
|
137
|
+
async with get_client(sync_client=False) as prefect_client:
|
|
138
|
+
# Query the deployment associated with the trigger to have its ID
|
|
139
|
+
deployment_name = trigger.get_deployment_names()[0]
|
|
140
|
+
deployment = await prefect_client.read_deployment_by_name(name=f"{deployment_name}/{deployment_name}")
|
|
145
141
|
|
|
146
142
|
automation = AutomationCore(
|
|
147
|
-
name=
|
|
148
|
-
description=
|
|
143
|
+
name=trigger.generate_name(),
|
|
144
|
+
description=trigger.get_description(),
|
|
149
145
|
enabled=True,
|
|
150
|
-
trigger=
|
|
151
|
-
|
|
152
|
-
expect={"infrahub.node.*"},
|
|
153
|
-
within=timedelta(0),
|
|
154
|
-
match=ResourceSpecification(
|
|
155
|
-
{
|
|
156
|
-
"infrahub.node.action": MutationAction.available_types(),
|
|
157
|
-
}
|
|
158
|
-
),
|
|
159
|
-
threshold=1,
|
|
160
|
-
),
|
|
161
|
-
actions=[
|
|
162
|
-
RunDeployment(
|
|
163
|
-
source="selected",
|
|
164
|
-
deployment_id=deployment_id_webhook_trigger,
|
|
165
|
-
parameters={
|
|
166
|
-
"event_type": "{{ event.resource['infrahub.node.kind'] }}.{{ event.resource['infrahub.node.action'] }}",
|
|
167
|
-
"event_data": {
|
|
168
|
-
"__prefect_kind": "json",
|
|
169
|
-
"value": {"__prefect_kind": "jinja", "template": "{{ event.payload['data'] | tojson }}"},
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
job_variables={},
|
|
173
|
-
),
|
|
174
|
-
],
|
|
146
|
+
trigger=trigger.trigger.get_prefect(),
|
|
147
|
+
actions=[action.get(deployment.id) for action in trigger.actions],
|
|
175
148
|
)
|
|
176
149
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
150
|
+
existing_automations = await prefect_client.read_automations_by_name(trigger.generate_name())
|
|
151
|
+
existing_automation = existing_automations[0] if existing_automations else None
|
|
152
|
+
|
|
153
|
+
if existing_automation:
|
|
154
|
+
await prefect_client.update_automation(automation_id=existing_automation.id, automation=automation)
|
|
155
|
+
log.info(f"Automation {trigger.generate_name()} updated")
|
|
180
156
|
else:
|
|
181
|
-
await
|
|
182
|
-
log.info(f"{
|
|
157
|
+
await prefect_client.create_automation(automation=automation)
|
|
158
|
+
log.info(f"Automation {trigger.generate_name()} created")
|
|
159
|
+
|
|
160
|
+
await service.cache.delete(key=f"webhook:{webhook.id}")
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@flow(name="webhook-delete-automation", flow_run_name="Delete webhook automation for {webhook_name}")
|
|
164
|
+
async def delete_webhook_automation(
|
|
165
|
+
webhook_id: str,
|
|
166
|
+
webhook_name: str, # noqa: ARG001
|
|
167
|
+
service: InfrahubServices,
|
|
168
|
+
) -> None:
|
|
169
|
+
log = get_run_logger()
|
|
170
|
+
|
|
171
|
+
async with get_client(sync_client=False) as prefect_client:
|
|
172
|
+
automation_name = WebhookTriggerDefinition.generate_name_from_id(id=webhook_id)
|
|
173
|
+
|
|
174
|
+
existing_automations = await prefect_client.read_automations_by_name(automation_name)
|
|
175
|
+
existing_automation = existing_automations[0] if existing_automations else None
|
|
176
|
+
|
|
177
|
+
if existing_automation:
|
|
178
|
+
await prefect_client.delete_automation(automation_id=existing_automation.id)
|
|
179
|
+
log.info(f"Automation {automation_name} deleted")
|
|
180
|
+
|
|
181
|
+
await service.cache.delete(key=f"webhook:{webhook_id}")
|