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
|
@@ -42,6 +42,17 @@ class ComputedAttributeTarget(BaseModel):
|
|
|
42
42
|
return hash((self.kind, self.attribute, tuple(self.filter_keys)))
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
class ComputedAttributeTriggerNode(BaseModel):
|
|
46
|
+
kind: str
|
|
47
|
+
attributes: list[str] = Field(default_factory=list)
|
|
48
|
+
relationships: list[str] = Field(default_factory=list)
|
|
49
|
+
targets_self: bool = Field(default=False)
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def fields(self) -> list[str]:
|
|
53
|
+
return self.attributes + self.relationships
|
|
54
|
+
|
|
55
|
+
|
|
45
56
|
class RegisteredNodeComputedAttribute(BaseModel):
|
|
46
57
|
local_fields: dict[str, list[ComputedAttributeTarget]] = Field(
|
|
47
58
|
default_factory=dict,
|
|
@@ -129,17 +140,17 @@ class ComputedAttributes:
|
|
|
129
140
|
if schema_path.active_attribute_schema.name not in trigger_node.local_fields:
|
|
130
141
|
trigger_node.local_fields[schema_path.active_attribute_schema.name] = []
|
|
131
142
|
|
|
132
|
-
trigger_node.local_fields[schema_path.active_attribute_schema.name].append(source_attribute)
|
|
143
|
+
trigger_node.local_fields[schema_path.active_attribute_schema.name].append(deepcopy(source_attribute))
|
|
133
144
|
elif schema_path.is_type_relationship:
|
|
134
145
|
if schema_path.active_attribute_schema.name not in trigger_node.local_fields:
|
|
135
146
|
trigger_node.local_fields[schema_path.active_attribute_schema.name] = []
|
|
136
147
|
|
|
137
|
-
trigger_node.local_fields[schema_path.active_attribute_schema.name].append(source_attribute)
|
|
148
|
+
trigger_node.local_fields[schema_path.active_attribute_schema.name].append(deepcopy(source_attribute))
|
|
138
149
|
|
|
139
150
|
if schema_path.active_relationship_schema.name not in trigger_node.relationships:
|
|
140
151
|
trigger_node.relationships[schema_path.active_relationship_schema.name] = []
|
|
141
152
|
|
|
142
|
-
trigger_node.relationships[schema_path.active_relationship_schema.name].append(source_attribute)
|
|
153
|
+
trigger_node.relationships[schema_path.active_relationship_schema.name].append(deepcopy(source_attribute))
|
|
143
154
|
|
|
144
155
|
if source_attribute.kind not in self._computed_jinja2_attribute_map:
|
|
145
156
|
self._computed_jinja2_attribute_map[source_attribute.kind] = RegisteredNodeComputedAttribute()
|
|
@@ -153,7 +164,7 @@ class ComputedAttributes:
|
|
|
153
164
|
] = []
|
|
154
165
|
self._computed_jinja2_attribute_map[source_attribute.kind].local_fields[
|
|
155
166
|
schema_path.active_relationship_schema.name
|
|
156
|
-
].append(source_attribute)
|
|
167
|
+
].append(deepcopy(source_attribute))
|
|
157
168
|
|
|
158
169
|
def get_impacted_jinja2_targets(self, kind: str, updates: list[str] | None = None) -> list[ComputedAttributeTarget]:
|
|
159
170
|
if mapping := self._computed_jinja2_attribute_map.get(kind):
|
|
@@ -172,3 +183,29 @@ class ComputedAttributes:
|
|
|
172
183
|
mapping[local_field].add(node)
|
|
173
184
|
|
|
174
185
|
return {key: list(value) for key, value in mapping.items()}
|
|
186
|
+
|
|
187
|
+
def get_jinja2_trigger_nodes(self) -> dict[ComputedAttributeTarget, list[ComputedAttributeTriggerNode]]:
|
|
188
|
+
working_map: dict[ComputedAttributeTarget, dict[str, ComputedAttributeTriggerNode]] = {}
|
|
189
|
+
for node_kind, registered_computed_attribute in self._computed_jinja2_attribute_map.items():
|
|
190
|
+
for local_field, computed_attribute_targets in registered_computed_attribute.local_fields.items():
|
|
191
|
+
for computed_attribute_target in computed_attribute_targets:
|
|
192
|
+
if computed_attribute_target not in working_map:
|
|
193
|
+
working_map[computed_attribute_target] = {}
|
|
194
|
+
if node_kind not in working_map[computed_attribute_target]:
|
|
195
|
+
working_map[computed_attribute_target][node_kind] = ComputedAttributeTriggerNode(kind=node_kind)
|
|
196
|
+
working_map[computed_attribute_target][node_kind].attributes.append(local_field)
|
|
197
|
+
if computed_attribute_target.kind == node_kind:
|
|
198
|
+
working_map[computed_attribute_target][node_kind].targets_self = True
|
|
199
|
+
for relationship, computed_attribute_targets in registered_computed_attribute.relationships.items():
|
|
200
|
+
for computed_attribute_target in computed_attribute_targets:
|
|
201
|
+
if computed_attribute_target not in working_map:
|
|
202
|
+
working_map[computed_attribute_target] = {}
|
|
203
|
+
if node_kind not in working_map[computed_attribute_target]:
|
|
204
|
+
working_map[computed_attribute_target][node_kind] = ComputedAttributeTriggerNode(kind=node_kind)
|
|
205
|
+
working_map[computed_attribute_target][node_kind].relationships.append(relationship)
|
|
206
|
+
if computed_attribute_target.kind == node_kind:
|
|
207
|
+
working_map[computed_attribute_target][node_kind].targets_self = True
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
computed_attribute_target: list(nodes.values()) for computed_attribute_target, nodes in working_map.items()
|
|
211
|
+
}
|
infrahub/core/task/task.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any
|
|
2
2
|
|
|
3
3
|
from pydantic import ConfigDict, Field
|
|
4
4
|
|
|
@@ -19,10 +19,10 @@ class Task(StandardNode):
|
|
|
19
19
|
|
|
20
20
|
title: str
|
|
21
21
|
conclusion: TaskConclusion
|
|
22
|
-
account_id:
|
|
22
|
+
account_id: str | None = Field(default=None, description="The ID of the account that created this task")
|
|
23
23
|
created_at: str = Field(default_factory=current_timestamp, description="The time when this task was created")
|
|
24
24
|
updated_at: str = Field(default_factory=current_timestamp, description="The time when this task was last updated")
|
|
25
|
-
related_node:
|
|
25
|
+
related_node: CoreNode | None = Field(default=None, description="The Infrahub node that this object refers to")
|
|
26
26
|
|
|
27
27
|
_exclude_attrs: list[str] = ["id", "uuid", "account_id", "_query", "related_node"]
|
|
28
28
|
_query: type[StandardNodeQuery] = TaskNodeCreateQuery
|
infrahub/core/task/user_task.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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 typing_extensions import Self
|
|
6
6
|
|
|
@@ -27,9 +27,9 @@ class UserTask:
|
|
|
27
27
|
self,
|
|
28
28
|
title: str,
|
|
29
29
|
db: InfrahubDatabase,
|
|
30
|
-
account:
|
|
31
|
-
account_id:
|
|
32
|
-
logger:
|
|
30
|
+
account: CoreGenericAccount | None = None,
|
|
31
|
+
account_id: str | None = None,
|
|
32
|
+
logger: BoundLogger | InfrahubLogger | None = None,
|
|
33
33
|
) -> None:
|
|
34
34
|
if not account and not account_id:
|
|
35
35
|
raise ValueError("Either account or account_id must be provided to initialize UserTask")
|
|
@@ -41,8 +41,8 @@ class UserTask:
|
|
|
41
41
|
self.account_id = account.id
|
|
42
42
|
|
|
43
43
|
self.title = title
|
|
44
|
-
self._task:
|
|
45
|
-
self.log:
|
|
44
|
+
self._task: Task | None
|
|
45
|
+
self.log: BoundLogger | InfrahubLogger = logger or get_logger()
|
|
46
46
|
self.db = db
|
|
47
47
|
|
|
48
48
|
@property
|
|
@@ -67,7 +67,7 @@ class UserTask:
|
|
|
67
67
|
if self._account:
|
|
68
68
|
return False
|
|
69
69
|
|
|
70
|
-
account:
|
|
70
|
+
account: CoreGenericAccount | None = await registry.manager.get_one(id=self.account_id, db=self.db)
|
|
71
71
|
if not account:
|
|
72
72
|
raise ValueError(f"Unable to find the account associated with {self.account_id}")
|
|
73
73
|
self._account = account
|
|
@@ -80,7 +80,7 @@ class UserTask:
|
|
|
80
80
|
|
|
81
81
|
@classmethod
|
|
82
82
|
def from_graphql_context(
|
|
83
|
-
cls, title: str, graphql_context: GraphqlContext, logger:
|
|
83
|
+
cls, title: str, graphql_context: GraphqlContext, logger: BoundLogger | InfrahubLogger | None = None
|
|
84
84
|
) -> Self:
|
|
85
85
|
if not graphql_context.db or not graphql_context.account_session:
|
|
86
86
|
raise ValueError("db and account_session must be provided to initialize a GraphQLTaskReport")
|
|
@@ -97,9 +97,9 @@ class UserTask:
|
|
|
97
97
|
|
|
98
98
|
async def __aexit__(
|
|
99
99
|
self,
|
|
100
|
-
exc_type:
|
|
101
|
-
exc_value:
|
|
102
|
-
traceback:
|
|
100
|
+
exc_type: type[BaseException] | None,
|
|
101
|
+
exc_value: BaseException | None,
|
|
102
|
+
traceback: TracebackType | None,
|
|
103
103
|
) -> None:
|
|
104
104
|
if exc_type:
|
|
105
105
|
await self.error(message=str(exc_value))
|
|
@@ -109,22 +109,22 @@ class UserTask:
|
|
|
109
109
|
await self.task.save(db=self.db)
|
|
110
110
|
|
|
111
111
|
async def add_log(
|
|
112
|
-
self, message: str, severity: Severity = Severity.INFO, db:
|
|
112
|
+
self, message: str, severity: Severity = Severity.INFO, db: InfrahubDatabase | None = None
|
|
113
113
|
) -> None:
|
|
114
114
|
tlog = TaskLog(message=message, severity=severity, task_id=self.task_id)
|
|
115
115
|
await tlog.save(db=db or self.db)
|
|
116
116
|
|
|
117
|
-
async def info(self, message: str, db:
|
|
117
|
+
async def info(self, message: str, db: InfrahubDatabase | None = None, **kwargs: Any) -> None:
|
|
118
118
|
if self.log:
|
|
119
119
|
self.log.info(message, **kwargs)
|
|
120
120
|
await self.add_log(message=message, severity=Severity.INFO, db=db)
|
|
121
121
|
|
|
122
|
-
async def warning(self, message: str, db:
|
|
122
|
+
async def warning(self, message: str, db: InfrahubDatabase | None = None, **kwargs: Any) -> None:
|
|
123
123
|
if self.log:
|
|
124
124
|
self.log.warning(message, **kwargs)
|
|
125
125
|
await self.add_log(message=message, severity=Severity.WARNING, db=db)
|
|
126
126
|
|
|
127
|
-
async def error(self, message: str, db:
|
|
127
|
+
async def error(self, message: str, db: InfrahubDatabase | None = None, **kwargs: Any) -> None:
|
|
128
128
|
if self.log:
|
|
129
129
|
self.log.error(message, **kwargs)
|
|
130
130
|
await self.add_log(message=message, severity=Severity.ERROR, db=db)
|
infrahub/core/utils.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import ipaddress
|
|
4
4
|
import re
|
|
5
5
|
from inspect import isclass
|
|
6
|
-
from typing import TYPE_CHECKING, Any
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
8
|
from infrahub.core.constants import RelationshipStatus
|
|
9
9
|
from infrahub.core.models import NodeKind
|
|
@@ -23,10 +23,10 @@ async def add_relationship(
|
|
|
23
23
|
dst_node_id: str,
|
|
24
24
|
rel_type: str,
|
|
25
25
|
db: InfrahubDatabase,
|
|
26
|
-
branch_name:
|
|
27
|
-
branch_level:
|
|
28
|
-
at:
|
|
29
|
-
status=RelationshipStatus.ACTIVE,
|
|
26
|
+
branch_name: str | None = None,
|
|
27
|
+
branch_level: int | None = None,
|
|
28
|
+
at: Timestamp | None = None,
|
|
29
|
+
status: RelationshipStatus = RelationshipStatus.ACTIVE,
|
|
30
30
|
) -> Record | None:
|
|
31
31
|
create_rel_query = """
|
|
32
32
|
MATCH (s) WHERE %(id_func)s(s) = $src_node_id
|
|
@@ -62,7 +62,9 @@ async def delete_all_relationships_for_branch(branch_name: str, db: InfrahubData
|
|
|
62
62
|
await db.execute_query(query=query, params=params, name="delete_all_relationships_for_branch")
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
async def update_relationships_to(
|
|
65
|
+
async def update_relationships_to(
|
|
66
|
+
ids: list[str], db: InfrahubDatabase, to: Timestamp | None = None
|
|
67
|
+
) -> list[Record] | None:
|
|
66
68
|
"""Update the "to" field on one or multiple relationships."""
|
|
67
69
|
if not ids:
|
|
68
70
|
return None
|
|
@@ -86,9 +88,9 @@ async def get_paths_between_nodes(
|
|
|
86
88
|
db: InfrahubDatabase,
|
|
87
89
|
source_id: str,
|
|
88
90
|
destination_id: str,
|
|
89
|
-
relationships:
|
|
90
|
-
max_length:
|
|
91
|
-
print_query=False,
|
|
91
|
+
relationships: list[str] | None = None,
|
|
92
|
+
max_length: int | None = None,
|
|
93
|
+
print_query: bool = False,
|
|
92
94
|
) -> list[Record]:
|
|
93
95
|
"""Return all paths between 2 nodes."""
|
|
94
96
|
|
|
@@ -115,7 +117,7 @@ async def get_paths_between_nodes(
|
|
|
115
117
|
return await db.execute_query(query=query, params=params, name="get_paths_between_nodes", type=QueryType.READ)
|
|
116
118
|
|
|
117
119
|
|
|
118
|
-
async def count_relationships(db: InfrahubDatabase, label:
|
|
120
|
+
async def count_relationships(db: InfrahubDatabase, label: str | None = None) -> int:
|
|
119
121
|
"""Return the total number of relationships in the database."""
|
|
120
122
|
|
|
121
123
|
label_str = f":{label}" if label else ""
|
|
@@ -141,7 +143,7 @@ async def get_nodes(db: InfrahubDatabase, label: str) -> list[Neo4jNode]:
|
|
|
141
143
|
return [result[0] for result in results]
|
|
142
144
|
|
|
143
145
|
|
|
144
|
-
async def count_nodes(db: InfrahubDatabase, label:
|
|
146
|
+
async def count_nodes(db: InfrahubDatabase, label: str | None = None) -> int:
|
|
145
147
|
"""Return the total number of nodes of a given label in the database."""
|
|
146
148
|
|
|
147
149
|
label_str = f":{label}" if label else ""
|
|
@@ -183,7 +185,7 @@ def parse_node_kind(kind: str) -> NodeKind:
|
|
|
183
185
|
|
|
184
186
|
|
|
185
187
|
def convert_ip_to_binary_str(
|
|
186
|
-
obj:
|
|
188
|
+
obj: ipaddress.IPv6Network | ipaddress.IPv4Network | ipaddress.IPv4Interface | ipaddress.IPv6Interface,
|
|
187
189
|
) -> str:
|
|
188
190
|
if isinstance(obj, ipaddress.IPv6Network | ipaddress.IPv4Network):
|
|
189
191
|
prefix_bin = f"{int(obj.network_address):b}"
|
|
@@ -230,26 +232,26 @@ class _NewClass:
|
|
|
230
232
|
_all_vars = set(dir(_OldClass) + dir(_NewClass))
|
|
231
233
|
|
|
232
234
|
|
|
233
|
-
def props(x) -> dict[str, Any]:
|
|
235
|
+
def props(x: Any) -> dict[str, Any]:
|
|
234
236
|
return {key: vars(x).get(key, getattr(x, key)) for key in dir(x) if key not in _all_vars}
|
|
235
237
|
|
|
236
238
|
|
|
237
239
|
class SubclassWithMeta_Meta(type):
|
|
238
240
|
_meta = None
|
|
239
241
|
|
|
240
|
-
def __str__(cls):
|
|
242
|
+
def __str__(cls) -> str:
|
|
241
243
|
if cls._meta:
|
|
242
244
|
return cls._meta.name
|
|
243
245
|
return cls.__name__
|
|
244
246
|
|
|
245
|
-
def __repr__(cls):
|
|
247
|
+
def __repr__(cls) -> str:
|
|
246
248
|
return f"<{cls.__name__} meta={repr(cls._meta)}>"
|
|
247
249
|
|
|
248
250
|
|
|
249
251
|
class SubclassWithMeta(metaclass=SubclassWithMeta_Meta):
|
|
250
252
|
"""This class improves __init_subclass__ to receive automatically the options from meta"""
|
|
251
253
|
|
|
252
|
-
def __init_subclass__(cls, **meta_options):
|
|
254
|
+
def __init_subclass__(cls, **meta_options: dict[str, Any]) -> None:
|
|
253
255
|
"""This method just terminates the super() chain"""
|
|
254
256
|
_Meta = getattr(cls, "Meta", None)
|
|
255
257
|
_meta_props = {}
|
|
@@ -266,7 +268,7 @@ class SubclassWithMeta(metaclass=SubclassWithMeta_Meta):
|
|
|
266
268
|
abstract = options.pop("abstract", False)
|
|
267
269
|
if abstract:
|
|
268
270
|
assert not options, (
|
|
269
|
-
"Abstract types can only contain the abstract attribute.
|
|
271
|
+
f"Abstract types can only contain the abstract attribute. Received: abstract, {', '.join(options)}"
|
|
270
272
|
)
|
|
271
273
|
else:
|
|
272
274
|
super_class = super(cls, cls)
|
|
@@ -274,5 +276,5 @@ class SubclassWithMeta(metaclass=SubclassWithMeta_Meta):
|
|
|
274
276
|
super_class.__init_subclass_with_meta__(**options)
|
|
275
277
|
|
|
276
278
|
@classmethod
|
|
277
|
-
def __init_subclass_with_meta__(cls, **meta_options) -> None:
|
|
279
|
+
def __init_subclass_with_meta__(cls, **meta_options: dict[str, Any]) -> None:
|
|
278
280
|
"""This method just terminates the super() chain"""
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
from .attribute.choices import AttributeChoicesChecker
|
|
4
2
|
from .attribute.enum import AttributeEnumChecker
|
|
5
3
|
from .attribute.kind import AttributeKindChecker
|
|
@@ -18,7 +16,7 @@ from .relationship.optional import RelationshipOptionalChecker
|
|
|
18
16
|
from .relationship.peer import RelationshipPeerChecker
|
|
19
17
|
from .uniqueness.checker import UniquenessChecker
|
|
20
18
|
|
|
21
|
-
CONSTRAINT_VALIDATOR_MAP: dict[str,
|
|
19
|
+
CONSTRAINT_VALIDATOR_MAP: dict[str, type[ConstraintCheckerInterface] | None] = {
|
|
22
20
|
"attribute.regex.update": AttributeRegexChecker,
|
|
23
21
|
"attribute.enum.update": AttributeEnumChecker,
|
|
24
22
|
"attribute.kind.update": AttributeKindChecker,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from itertools import chain
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from infrahub.core import registry
|
|
7
7
|
from infrahub.exceptions import ValidationError
|
|
@@ -19,7 +19,7 @@ if TYPE_CHECKING:
|
|
|
19
19
|
|
|
20
20
|
class AggregatedConstraintChecker:
|
|
21
21
|
def __init__(
|
|
22
|
-
self, constraints: list[ConstraintCheckerInterface], db: InfrahubDatabase, branch:
|
|
22
|
+
self, constraints: list[ConstraintCheckerInterface], db: InfrahubDatabase, branch: Branch | None = None
|
|
23
23
|
):
|
|
24
24
|
self.constraints = constraints
|
|
25
25
|
self.db = db
|
|
@@ -1,6 +1,6 @@
|
|
|
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 infrahub.core.constants import NULL_VALUE, PathType
|
|
6
6
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
@@ -75,7 +75,7 @@ class AttributeChoicesUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
75
75
|
class AttributeChoicesChecker(ConstraintCheckerInterface):
|
|
76
76
|
query_classes = [AttributeChoicesUpdateValidatorQuery]
|
|
77
77
|
|
|
78
|
-
def __init__(self, db: InfrahubDatabase, branch:
|
|
78
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
|
|
79
79
|
self.db = db
|
|
80
80
|
self.branch = branch
|
|
81
81
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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 infrahub.core.constants import NULL_VALUE, PathType
|
|
6
6
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
@@ -74,7 +74,7 @@ class AttributeEnumUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
74
74
|
class AttributeEnumChecker(ConstraintCheckerInterface):
|
|
75
75
|
query_classes = [AttributeEnumUpdateValidatorQuery]
|
|
76
76
|
|
|
77
|
-
def __init__(self, db: InfrahubDatabase, branch:
|
|
77
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
|
|
78
78
|
self.db = db
|
|
79
79
|
self.branch = branch
|
|
80
80
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import TYPE_CHECKING, Any
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
5
|
|
|
6
6
|
from infrahub.core.constants import NULL_VALUE, PathType
|
|
7
7
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
@@ -87,7 +87,7 @@ class AttributeKindUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
87
87
|
class AttributeKindChecker(ConstraintCheckerInterface):
|
|
88
88
|
query_classes = [AttributeKindUpdateValidatorQuery]
|
|
89
89
|
|
|
90
|
-
def __init__(self, db: InfrahubDatabase, branch:
|
|
90
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
|
|
91
91
|
self.db = db
|
|
92
92
|
self.branch = branch
|
|
93
93
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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 infrahub.core.constants import PathType
|
|
6
6
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
@@ -70,7 +70,7 @@ class AttributeLengthUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
70
70
|
class AttributeLengthChecker(ConstraintCheckerInterface):
|
|
71
71
|
query_classes = [AttributeLengthUpdateValidatorQuery]
|
|
72
72
|
|
|
73
|
-
def __init__(self, db: InfrahubDatabase, branch:
|
|
73
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
|
|
74
74
|
self.db = db
|
|
75
75
|
self.branch = branch
|
|
76
76
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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 infrahub.core.constants import NULL_VALUE, PathType
|
|
6
6
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
@@ -66,7 +66,7 @@ class AttributeOptionalUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
66
66
|
class AttributeOptionalChecker(ConstraintCheckerInterface):
|
|
67
67
|
query_classes = [AttributeOptionalUpdateValidatorQuery]
|
|
68
68
|
|
|
69
|
-
def __init__(self, db: InfrahubDatabase, branch:
|
|
69
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
|
|
70
70
|
self.db = db
|
|
71
71
|
self.branch = branch
|
|
72
72
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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 infrahub.core.constants import NULL_VALUE, PathType
|
|
6
6
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
@@ -70,7 +70,7 @@ class AttributeRegexUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
70
70
|
class AttributeRegexChecker(ConstraintCheckerInterface):
|
|
71
71
|
query_classes = [AttributeRegexUpdateValidatorQuery]
|
|
72
72
|
|
|
73
|
-
def __init__(self, db: InfrahubDatabase, branch:
|
|
73
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
|
|
74
74
|
self.db = db
|
|
75
75
|
self.branch = branch
|
|
76
76
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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 infrahub.core.constants import PathType
|
|
6
6
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
@@ -91,7 +91,7 @@ class AttributeUniqueUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
91
91
|
class AttributeUniquenessChecker(ConstraintCheckerInterface):
|
|
92
92
|
query_classes = [AttributeUniqueUpdateValidatorQuery]
|
|
93
93
|
|
|
94
|
-
def __init__(self, db: InfrahubDatabase, branch:
|
|
94
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None) -> None:
|
|
95
95
|
self.db = db
|
|
96
96
|
self.branch = branch
|
|
97
97
|
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from typing import Any, Coroutine
|
|
3
3
|
|
|
4
|
-
from infrahub_sdk.
|
|
4
|
+
from infrahub_sdk.protocols import CoreValidator
|
|
5
5
|
|
|
6
|
+
from infrahub.context import InfrahubContext
|
|
6
7
|
from infrahub.core.constants import ValidatorConclusion, ValidatorState
|
|
7
8
|
from infrahub.core.timestamp import Timestamp
|
|
9
|
+
from infrahub.services import InfrahubServices
|
|
10
|
+
from infrahub.validators.events import send_failed_validator, send_passed_validator
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
async def run_checks_and_update_validator(
|
|
11
|
-
checks: list[Coroutine[Any, None, ValidatorConclusion]],
|
|
14
|
+
checks: list[Coroutine[Any, None, ValidatorConclusion]],
|
|
15
|
+
validator: CoreValidator,
|
|
16
|
+
context: InfrahubContext,
|
|
17
|
+
service: InfrahubServices,
|
|
18
|
+
proposed_change_id: str,
|
|
12
19
|
) -> None:
|
|
13
20
|
"""
|
|
14
21
|
Execute a list of checks coroutines, and set validator fields accordingly.
|
|
@@ -22,11 +29,17 @@ async def run_checks_and_update_validator(
|
|
|
22
29
|
validator.completed_at.value = ""
|
|
23
30
|
await validator.save()
|
|
24
31
|
|
|
32
|
+
failed_early = False
|
|
33
|
+
|
|
25
34
|
for earliest_task in asyncio.as_completed(checks):
|
|
26
35
|
result = await earliest_task
|
|
27
36
|
if validator.conclusion.value != ValidatorConclusion.FAILURE.value and result == ValidatorConclusion.FAILURE:
|
|
28
37
|
validator.conclusion.value = ValidatorConclusion.FAILURE.value
|
|
38
|
+
failed_early = True
|
|
29
39
|
await validator.save()
|
|
40
|
+
await send_failed_validator(
|
|
41
|
+
service=service, validator=validator, proposed_change_id=proposed_change_id, context=context
|
|
42
|
+
)
|
|
30
43
|
# Continue to iterate to wait for the end of all checks
|
|
31
44
|
|
|
32
45
|
validator.state.value = ValidatorState.COMPLETED.value
|
|
@@ -35,3 +48,13 @@ async def run_checks_and_update_validator(
|
|
|
35
48
|
validator.conclusion.value = ValidatorConclusion.SUCCESS.value
|
|
36
49
|
|
|
37
50
|
await validator.save()
|
|
51
|
+
|
|
52
|
+
if not failed_early:
|
|
53
|
+
if validator.conclusion.value == ValidatorConclusion.SUCCESS.value:
|
|
54
|
+
await send_passed_validator(
|
|
55
|
+
service=service, validator=validator, proposed_change_id=proposed_change_id, context=context
|
|
56
|
+
)
|
|
57
|
+
else:
|
|
58
|
+
await send_failed_validator(
|
|
59
|
+
service=service, validator=validator, proposed_change_id=proposed_change_id, context=context
|
|
60
|
+
)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Union
|
|
2
|
-
|
|
3
1
|
from infrahub.core.constants import RelationshipKind, SchemaPathType
|
|
4
2
|
from infrahub.core.constants.schema import UpdateSupport
|
|
5
3
|
from infrahub.core.diff.model.path import NodeDiffFieldSummary
|
|
@@ -132,7 +130,7 @@ class ConstraintValidatorDeterminer:
|
|
|
132
130
|
return constraints
|
|
133
131
|
|
|
134
132
|
async def _get_constraints_for_one_field(
|
|
135
|
-
self, schema: MainSchemaTypes, field:
|
|
133
|
+
self, schema: MainSchemaTypes, field: AttributeSchema | RelationshipSchema
|
|
136
134
|
) -> list[SchemaUpdateConstraintInfo]:
|
|
137
135
|
constraints: list[SchemaUpdateConstraintInfo] = []
|
|
138
136
|
for prop_name, prop_field_info in field.model_fields.items():
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from infrahub.core.path import GroupedDataPaths
|
|
4
8
|
|
|
5
|
-
from .model import SchemaConstraintValidatorRequest
|
|
9
|
+
from .model import SchemaConstraintValidatorRequest
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
class ConstraintCheckerInterface(ABC):
|
|
@@ -1,17 +1,36 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Any
|
|
2
2
|
|
|
3
|
-
from pydantic import BaseModel, Field
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_serializer
|
|
4
4
|
|
|
5
5
|
from infrahub.core.branch import Branch
|
|
6
6
|
from infrahub.core.path import SchemaPath
|
|
7
7
|
from infrahub.core.schema import GenericSchema, NodeSchema
|
|
8
|
+
from infrahub.core.schema.schema_branch import SchemaBranch
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class SchemaConstraintValidatorRequest(BaseModel):
|
|
12
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
13
|
+
|
|
11
14
|
branch: Branch = Field(..., description="The name of the branch to target")
|
|
12
15
|
constraint_name: str = Field(..., description="The name of the constraint to validate")
|
|
13
|
-
node_schema:
|
|
16
|
+
node_schema: NodeSchema | GenericSchema = Field(..., description="Schema of Node or Generic to validate")
|
|
14
17
|
schema_path: SchemaPath = Field(..., description="SchemaPath to the element of the schema to validate")
|
|
18
|
+
schema_branch: SchemaBranch = Field(..., description="SchemaBranch of the element to validate")
|
|
19
|
+
|
|
20
|
+
@model_serializer()
|
|
21
|
+
def serialize_model(self) -> dict[str, Any]:
|
|
22
|
+
return {
|
|
23
|
+
"branch": self.branch.model_dump(),
|
|
24
|
+
"constraint_name": self.constraint_name,
|
|
25
|
+
"node_schema": self.node_schema.model_dump(),
|
|
26
|
+
"schema_path": self.schema_path.model_dump(),
|
|
27
|
+
"schema_branch": self.schema_branch.to_dict_schema_object(),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@field_validator("schema_branch", mode="before")
|
|
31
|
+
@classmethod
|
|
32
|
+
def validate_schema_branch(cls, value: Any) -> SchemaBranch:
|
|
33
|
+
return SchemaBranch.validate(data=value)
|
|
15
34
|
|
|
16
35
|
|
|
17
36
|
class SchemaViolation(BaseModel):
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_serializer
|
|
2
4
|
|
|
3
5
|
from infrahub.core.branch import Branch
|
|
4
6
|
from infrahub.core.models import SchemaUpdateConstraintInfo
|
|
@@ -9,13 +11,24 @@ from infrahub.message_bus import InfrahubResponseData
|
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
class SchemaValidateMigrationData(BaseModel):
|
|
12
|
-
model_config = ConfigDict(
|
|
13
|
-
arbitrary_types_allowed=True, json_encoders={SchemaBranch: SchemaBranch.to_dict_schema_object}
|
|
14
|
-
)
|
|
14
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
15
15
|
branch: Branch
|
|
16
16
|
schema_branch: SchemaBranch
|
|
17
17
|
constraints: list[SchemaUpdateConstraintInfo]
|
|
18
18
|
|
|
19
|
+
@model_serializer()
|
|
20
|
+
def serialize_model(self) -> dict[str, Any]:
|
|
21
|
+
return {
|
|
22
|
+
"branch": self.branch.model_dump(),
|
|
23
|
+
"schema_branch": self.schema_branch.to_dict_schema_object(),
|
|
24
|
+
"constraints": [constraint.model_dump() for constraint in self.constraints],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@field_validator("schema_branch", mode="before")
|
|
28
|
+
@classmethod
|
|
29
|
+
def validate_schema_branch(cls, value: Any) -> SchemaBranch:
|
|
30
|
+
return SchemaBranch.validate(data=value)
|
|
31
|
+
|
|
19
32
|
|
|
20
33
|
class SchemaValidatorPathResponseData(InfrahubResponseData):
|
|
21
34
|
violations: list[SchemaViolation] = Field(default_factory=list)
|
|
@@ -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 ..interface import ConstraintCheckerInterface
|
|
6
6
|
from ..query import NodeNotPresentValidatorQuery
|
|
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
|
|
16
16
|
class NodeAttributeAddChecker(ConstraintCheckerInterface):
|
|
17
17
|
query_classes = [NodeNotPresentValidatorQuery]
|
|
18
18
|
|
|
19
|
-
def __init__(self, db: InfrahubDatabase, branch:
|
|
19
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
|
|
20
20
|
self.db = db
|
|
21
21
|
self.branch = branch
|
|
22
22
|
|