infrahub-server 1.3.7__py3-none-any.whl → 1.4.0__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/internal.py +5 -0
- infrahub/artifacts/tasks.py +17 -22
- infrahub/branch/merge_mutation_checker.py +38 -0
- infrahub/cli/__init__.py +2 -2
- infrahub/cli/context.py +7 -3
- infrahub/cli/db.py +5 -16
- infrahub/cli/upgrade.py +10 -29
- infrahub/computed_attribute/tasks.py +36 -46
- infrahub/config.py +57 -6
- infrahub/constants/environment.py +1 -0
- infrahub/core/attribute.py +15 -7
- infrahub/core/branch/tasks.py +43 -41
- infrahub/core/constants/__init__.py +21 -6
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/diff/coordinator.py +3 -1
- infrahub/core/diff/model/path.py +0 -39
- infrahub/core/diff/repository/repository.py +0 -8
- infrahub/core/diff/tasks.py +11 -8
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/index.py +1 -2
- infrahub/core/graph/schema.py +50 -29
- infrahub/core/initialization.py +81 -47
- infrahub/core/ipam/tasks.py +4 -3
- infrahub/core/merge.py +8 -10
- infrahub/core/migrations/__init__.py +2 -0
- infrahub/core/migrations/graph/__init__.py +4 -0
- infrahub/core/migrations/graph/m036_drop_attr_value_index.py +45 -0
- infrahub/core/migrations/graph/m037_index_attr_vals.py +577 -0
- infrahub/core/migrations/query/attribute_add.py +27 -2
- infrahub/core/migrations/schema/attribute_kind_update.py +156 -0
- infrahub/core/migrations/schema/tasks.py +6 -5
- infrahub/core/models.py +5 -1
- infrahub/core/node/proposed_change.py +43 -0
- infrahub/core/protocols.py +12 -0
- infrahub/core/query/attribute.py +32 -14
- infrahub/core/query/diff.py +11 -0
- infrahub/core/query/ipam.py +13 -7
- infrahub/core/query/node.py +51 -10
- infrahub/core/query/resource_manager.py +3 -3
- infrahub/core/schema/basenode_schema.py +8 -0
- infrahub/core/schema/definitions/core/__init__.py +10 -1
- infrahub/core/schema/definitions/core/ipam.py +28 -2
- infrahub/core/schema/definitions/core/propose_change.py +15 -0
- infrahub/core/schema/definitions/core/webhook.py +3 -0
- infrahub/core/schema/definitions/internal.py +1 -1
- infrahub/core/schema/generated/attribute_schema.py +1 -1
- infrahub/core/schema/generic_schema.py +10 -0
- infrahub/core/schema/manager.py +10 -1
- infrahub/core/schema/node_schema.py +22 -22
- infrahub/core/schema/profile_schema.py +8 -0
- infrahub/core/schema/schema_branch.py +11 -7
- infrahub/core/schema/template_schema.py +8 -0
- infrahub/core/validators/attribute/kind.py +5 -1
- infrahub/core/validators/checks_runner.py +5 -5
- infrahub/core/validators/determiner.py +22 -2
- infrahub/core/validators/tasks.py +6 -7
- infrahub/core/validators/uniqueness/checker.py +4 -2
- infrahub/core/validators/uniqueness/model.py +1 -0
- infrahub/core/validators/uniqueness/query.py +57 -7
- infrahub/database/__init__.py +2 -1
- infrahub/events/__init__.py +20 -0
- infrahub/events/constants.py +7 -0
- infrahub/events/generator.py +29 -2
- infrahub/events/proposed_change_action.py +203 -0
- infrahub/generators/tasks.py +24 -20
- infrahub/git/base.py +4 -7
- infrahub/git/integrator.py +21 -12
- infrahub/git/repository.py +15 -30
- infrahub/git/tasks.py +121 -106
- infrahub/graphql/app.py +2 -1
- infrahub/graphql/field_extractor.py +69 -0
- infrahub/graphql/manager.py +15 -11
- infrahub/graphql/mutations/account.py +2 -2
- infrahub/graphql/mutations/action.py +8 -2
- infrahub/graphql/mutations/artifact_definition.py +4 -1
- infrahub/graphql/mutations/branch.py +10 -5
- infrahub/graphql/mutations/graphql_query.py +2 -1
- infrahub/graphql/mutations/main.py +14 -8
- infrahub/graphql/mutations/menu.py +2 -1
- infrahub/graphql/mutations/proposed_change.py +230 -8
- infrahub/graphql/mutations/relationship.py +5 -0
- infrahub/graphql/mutations/repository.py +2 -1
- infrahub/graphql/mutations/tasks.py +7 -9
- infrahub/graphql/mutations/webhook.py +4 -1
- infrahub/graphql/parser.py +15 -6
- infrahub/graphql/queries/__init__.py +10 -1
- infrahub/graphql/queries/account.py +3 -3
- infrahub/graphql/queries/branch.py +2 -2
- infrahub/graphql/queries/diff/tree.py +56 -5
- infrahub/graphql/queries/event.py +13 -3
- infrahub/graphql/queries/ipam.py +23 -1
- infrahub/graphql/queries/proposed_change.py +84 -0
- infrahub/graphql/queries/relationship.py +2 -2
- infrahub/graphql/queries/resource_manager.py +3 -3
- infrahub/graphql/queries/search.py +3 -2
- infrahub/graphql/queries/status.py +3 -2
- infrahub/graphql/queries/task.py +2 -2
- infrahub/graphql/resolvers/ipam.py +440 -0
- infrahub/graphql/resolvers/many_relationship.py +4 -3
- infrahub/graphql/resolvers/resolver.py +5 -5
- infrahub/graphql/resolvers/single_relationship.py +3 -2
- infrahub/graphql/schema.py +25 -5
- infrahub/graphql/types/__init__.py +2 -2
- infrahub/graphql/types/attribute.py +3 -3
- infrahub/graphql/types/event.py +68 -0
- infrahub/groups/tasks.py +6 -6
- infrahub/lock.py +3 -2
- infrahub/menu/generator.py +8 -0
- infrahub/message_bus/operations/__init__.py +9 -12
- infrahub/message_bus/operations/git/file.py +6 -5
- infrahub/message_bus/operations/git/repository.py +12 -20
- infrahub/message_bus/operations/refresh/registry.py +15 -9
- infrahub/message_bus/operations/send/echo.py +7 -4
- infrahub/message_bus/types.py +1 -0
- infrahub/permissions/__init__.py +2 -1
- infrahub/permissions/constants.py +13 -0
- infrahub/permissions/globals.py +31 -2
- infrahub/permissions/manager.py +8 -5
- infrahub/pools/prefix.py +7 -5
- infrahub/prefect_server/app.py +31 -0
- infrahub/prefect_server/bootstrap.py +18 -0
- infrahub/proposed_change/action_checker.py +206 -0
- infrahub/proposed_change/approval_revoker.py +40 -0
- infrahub/proposed_change/branch_diff.py +3 -1
- infrahub/proposed_change/checker.py +45 -0
- infrahub/proposed_change/constants.py +32 -2
- infrahub/proposed_change/tasks.py +182 -150
- infrahub/py.typed +0 -0
- infrahub/server.py +29 -17
- infrahub/services/__init__.py +13 -28
- infrahub/services/adapters/cache/__init__.py +4 -0
- infrahub/services/adapters/cache/nats.py +2 -0
- infrahub/services/adapters/cache/redis.py +3 -0
- infrahub/services/adapters/message_bus/__init__.py +0 -2
- infrahub/services/adapters/message_bus/local.py +1 -2
- infrahub/services/adapters/message_bus/nats.py +6 -8
- infrahub/services/adapters/message_bus/rabbitmq.py +7 -9
- infrahub/services/adapters/workflow/__init__.py +1 -0
- infrahub/services/adapters/workflow/local.py +1 -8
- infrahub/services/component.py +2 -1
- infrahub/task_manager/event.py +56 -0
- infrahub/task_manager/models.py +9 -0
- infrahub/tasks/artifact.py +6 -7
- infrahub/tasks/check.py +4 -7
- infrahub/telemetry/tasks.py +15 -18
- infrahub/transformations/tasks.py +10 -6
- infrahub/trigger/tasks.py +4 -3
- infrahub/types.py +4 -0
- infrahub/validators/events.py +7 -7
- infrahub/validators/tasks.py +6 -7
- infrahub/webhook/models.py +45 -45
- infrahub/webhook/tasks.py +25 -24
- infrahub/workers/dependencies.py +143 -0
- infrahub/workers/infrahub_async.py +19 -43
- infrahub/workflows/catalogue.py +16 -2
- infrahub/workflows/initialization.py +5 -4
- infrahub/workflows/models.py +2 -0
- infrahub_sdk/client.py +2 -2
- infrahub_sdk/ctl/repository.py +51 -0
- infrahub_sdk/ctl/schema.py +9 -9
- infrahub_sdk/node/node.py +2 -2
- infrahub_sdk/pytest_plugin/items/graphql_query.py +1 -1
- infrahub_sdk/schema/repository.py +1 -1
- infrahub_sdk/testing/docker.py +1 -1
- infrahub_sdk/utils.py +2 -2
- {infrahub_server-1.3.7.dist-info → infrahub_server-1.4.0.dist-info}/METADATA +7 -5
- {infrahub_server-1.3.7.dist-info → infrahub_server-1.4.0.dist-info}/RECORD +174 -158
- infrahub_testcontainers/container.py +17 -0
- infrahub_testcontainers/docker-compose-cluster.test.yml +56 -1
- infrahub_testcontainers/docker-compose.test.yml +56 -1
- infrahub_testcontainers/helpers.py +4 -1
- {infrahub_server-1.3.7.dist-info → infrahub_server-1.4.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.3.7.dist-info → infrahub_server-1.4.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.3.7.dist-info → infrahub_server-1.4.0.dist-info}/entry_points.txt +0 -0
|
@@ -35,7 +35,14 @@ from .group import (
|
|
|
35
35
|
core_repository_group,
|
|
36
36
|
core_standard_group,
|
|
37
37
|
)
|
|
38
|
-
from .ipam import
|
|
38
|
+
from .ipam import (
|
|
39
|
+
builtin_ip_address,
|
|
40
|
+
builtin_ip_prefix,
|
|
41
|
+
builtin_ipam,
|
|
42
|
+
core_ipam_namespace,
|
|
43
|
+
internal_ipam_ip_prefix_available,
|
|
44
|
+
internal_ipam_ip_range_available,
|
|
45
|
+
)
|
|
39
46
|
from .lineage import lineage_owner, lineage_source
|
|
40
47
|
from .menu import generic_menu_item, menu_item
|
|
41
48
|
from .permission import (
|
|
@@ -172,6 +179,8 @@ core_models_mixed: dict[str, list] = {
|
|
|
172
179
|
core_object_permission,
|
|
173
180
|
core_account_role,
|
|
174
181
|
core_account_group,
|
|
182
|
+
internal_ipam_ip_prefix_available,
|
|
183
|
+
internal_ipam_ip_range_available,
|
|
175
184
|
],
|
|
176
185
|
}
|
|
177
186
|
|
|
@@ -59,7 +59,7 @@ builtin_ip_prefix = GenericSchema(
|
|
|
59
59
|
name="IPPrefix",
|
|
60
60
|
label="IP Prefix",
|
|
61
61
|
namespace="Builtin",
|
|
62
|
-
description="
|
|
62
|
+
description="IPv4 or IPv6 prefix also referred as network",
|
|
63
63
|
include_in_menu=False,
|
|
64
64
|
default_filter="prefix__value",
|
|
65
65
|
order_by=["prefix__version", "prefix__binary_address", "prefix__prefixlen"],
|
|
@@ -142,7 +142,7 @@ builtin_ip_address = GenericSchema(
|
|
|
142
142
|
name="IPAddress",
|
|
143
143
|
label="IP Address",
|
|
144
144
|
namespace="Builtin",
|
|
145
|
-
description="
|
|
145
|
+
description="IPv4 or IPv6 address",
|
|
146
146
|
include_in_menu=False,
|
|
147
147
|
default_filter="address__value",
|
|
148
148
|
order_by=["address__version", "address__binary_address"],
|
|
@@ -176,6 +176,32 @@ builtin_ip_address = GenericSchema(
|
|
|
176
176
|
],
|
|
177
177
|
)
|
|
178
178
|
|
|
179
|
+
internal_ipam_ip_range_available = NodeSchema(
|
|
180
|
+
name="IPRangeAvailable",
|
|
181
|
+
label="Available IP Range",
|
|
182
|
+
namespace="Internal",
|
|
183
|
+
description="Range of IPv4 or IPv6 addresses which has not been allocated yet",
|
|
184
|
+
include_in_menu=False,
|
|
185
|
+
display_labels=["address__value", "last_address__value"],
|
|
186
|
+
branch=BranchSupportType.AWARE,
|
|
187
|
+
inherit_from=[InfrahubKind.IPADDRESS],
|
|
188
|
+
generate_profile=False,
|
|
189
|
+
attributes=[Attr(name="last_address", kind="IPHost", branch=BranchSupportType.AWARE, order_weight=2000)],
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
internal_ipam_ip_prefix_available = NodeSchema(
|
|
193
|
+
name="IPPrefixAvailable",
|
|
194
|
+
label="Available IP Prefix",
|
|
195
|
+
namespace="Internal",
|
|
196
|
+
description="IPv4 or IPv6 prefix also referred as network which has not been allocated yet",
|
|
197
|
+
include_in_menu=False,
|
|
198
|
+
display_labels=["prefix__value"],
|
|
199
|
+
branch=BranchSupportType.AWARE,
|
|
200
|
+
inherit_from=[InfrahubKind.IPPREFIX],
|
|
201
|
+
generate_profile=False,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
|
|
179
205
|
core_ipam_namespace = NodeSchema(
|
|
180
206
|
name="Namespace",
|
|
181
207
|
namespace="Ipam",
|
|
@@ -38,6 +38,9 @@ core_proposed_change = NodeSchema(
|
|
|
38
38
|
default_value=ProposedChangeState.OPEN.value,
|
|
39
39
|
optional=True,
|
|
40
40
|
),
|
|
41
|
+
Attr(name="is_draft", kind="Boolean", optional=False, default_value=False),
|
|
42
|
+
# Ideally we should support some "runtime-attribute" that could not even be stored in the database.
|
|
43
|
+
Attr(name="total_comments", kind="Number", optional=True, read_only=True),
|
|
41
44
|
],
|
|
42
45
|
relationships=[
|
|
43
46
|
Rel(
|
|
@@ -48,6 +51,17 @@ core_proposed_change = NodeSchema(
|
|
|
48
51
|
kind=RelKind.ATTRIBUTE,
|
|
49
52
|
branch=BranchSupportType.AGNOSTIC,
|
|
50
53
|
identifier="coreaccount__proposedchange_approved_by",
|
|
54
|
+
read_only=True,
|
|
55
|
+
),
|
|
56
|
+
Rel(
|
|
57
|
+
name="rejected_by",
|
|
58
|
+
peer=InfrahubKind.GENERICACCOUNT,
|
|
59
|
+
optional=True,
|
|
60
|
+
cardinality=Cardinality.MANY,
|
|
61
|
+
kind=RelKind.ATTRIBUTE,
|
|
62
|
+
branch=BranchSupportType.AGNOSTIC,
|
|
63
|
+
identifier="coreaccount__proposedchange_rejected_by",
|
|
64
|
+
read_only=True,
|
|
51
65
|
),
|
|
52
66
|
Rel(
|
|
53
67
|
name="reviewers",
|
|
@@ -66,6 +80,7 @@ core_proposed_change = NodeSchema(
|
|
|
66
80
|
kind=RelKind.ATTRIBUTE,
|
|
67
81
|
branch=BranchSupportType.AGNOSTIC,
|
|
68
82
|
identifier="coreaccount__proposedchange_created_by",
|
|
83
|
+
read_only=True,
|
|
69
84
|
),
|
|
70
85
|
Rel(
|
|
71
86
|
name="comments",
|
|
@@ -120,6 +120,9 @@ core_custom_webhook = NodeSchema(
|
|
|
120
120
|
branch=BranchSupportType.AGNOSTIC,
|
|
121
121
|
generate_profile=False,
|
|
122
122
|
inherit_from=[InfrahubKind.WEBHOOK, InfrahubKind.TASKTARGET],
|
|
123
|
+
attributes=[
|
|
124
|
+
Attr(name="shared_key", kind="Password", unique=False, optional=True, order_weight=4000),
|
|
125
|
+
],
|
|
123
126
|
relationships=[
|
|
124
127
|
Rel(
|
|
125
128
|
name="transformation",
|
|
@@ -487,7 +487,7 @@ attribute_schema = SchemaNode(
|
|
|
487
487
|
kind="Text",
|
|
488
488
|
description="Defines the type of the attribute.",
|
|
489
489
|
enum=ATTRIBUTE_KIND_LABELS,
|
|
490
|
-
extra={"update": UpdateSupport.
|
|
490
|
+
extra={"update": UpdateSupport.MIGRATION_REQUIRED},
|
|
491
491
|
),
|
|
492
492
|
SchemaAttribute(
|
|
493
493
|
name="enum",
|
|
@@ -31,7 +31,7 @@ class GeneratedAttributeSchema(HashableModel):
|
|
|
31
31
|
json_schema_extra={"update": "migration_required"},
|
|
32
32
|
)
|
|
33
33
|
kind: str = Field(
|
|
34
|
-
..., description="Defines the type of the attribute.", json_schema_extra={"update": "
|
|
34
|
+
..., description="Defines the type of the attribute.", json_schema_extra={"update": "migration_required"}
|
|
35
35
|
)
|
|
36
36
|
enum: list | None = Field(
|
|
37
37
|
default=None,
|
|
@@ -2,6 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
from infrahub.core.constants import InfrahubKind
|
|
6
|
+
|
|
5
7
|
from .generated.genericnode_schema import GeneratedGenericSchema
|
|
6
8
|
|
|
7
9
|
if TYPE_CHECKING:
|
|
@@ -28,6 +30,14 @@ class GenericSchema(GeneratedGenericSchema):
|
|
|
28
30
|
def is_template_schema(self) -> bool:
|
|
29
31
|
return False
|
|
30
32
|
|
|
33
|
+
@property
|
|
34
|
+
def is_ip_prefix(self) -> bool:
|
|
35
|
+
return self.kind == InfrahubKind.IPPREFIX
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def is_ip_address(self) -> bool:
|
|
39
|
+
return self.kind == InfrahubKind.IPADDRESS
|
|
40
|
+
|
|
31
41
|
def get_hierarchy_schema(self, db: InfrahubDatabase, branch: Branch | str | None = None) -> GenericSchema: # noqa: ARG002
|
|
32
42
|
if self.hierarchical:
|
|
33
43
|
return self
|
infrahub/core/schema/manager.py
CHANGED
|
@@ -93,6 +93,15 @@ class SchemaManager(NodeManager):
|
|
|
93
93
|
|
|
94
94
|
raise ValueError("The selected node is not of type NodeSchema")
|
|
95
95
|
|
|
96
|
+
def get_generic_schema(
|
|
97
|
+
self, name: str, branch: Branch | str | None = None, duplicate: bool = True
|
|
98
|
+
) -> GenericSchema:
|
|
99
|
+
schema = self.get(name=name, branch=branch, duplicate=duplicate)
|
|
100
|
+
if isinstance(schema, GenericSchema):
|
|
101
|
+
return schema
|
|
102
|
+
|
|
103
|
+
raise ValueError("The selected node is not of type GenericSchema")
|
|
104
|
+
|
|
96
105
|
def get_profile_schema(
|
|
97
106
|
self, name: str, branch: Branch | str | None = None, duplicate: bool = True
|
|
98
107
|
) -> ProfileSchema:
|
|
@@ -122,7 +131,7 @@ class SchemaManager(NodeManager):
|
|
|
122
131
|
|
|
123
132
|
return self._branches[branch_name].get_all(duplicate=duplicate)
|
|
124
133
|
|
|
125
|
-
async def get_full_safe(self, branch: Branch | str | None = None) -> dict[str,
|
|
134
|
+
async def get_full_safe(self, branch: Branch | str | None = None) -> dict[str, MainSchemaTypes]:
|
|
126
135
|
await lock.registry.local_schema_wait()
|
|
127
136
|
|
|
128
137
|
return self.get_full(branch=branch)
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
-
from infrahub.core.constants import AllowOverrideType, InfrahubKind
|
|
5
|
+
from infrahub.core.constants import AllowOverrideType, InfrahubKind, RelationshipKind
|
|
6
6
|
|
|
7
7
|
from .generated.node_schema import GeneratedNodeSchema
|
|
8
8
|
from .generic_schema import GenericSchema
|
|
@@ -29,6 +29,16 @@ class NodeSchema(GeneratedNodeSchema):
|
|
|
29
29
|
def is_template_schema(self) -> bool:
|
|
30
30
|
return False
|
|
31
31
|
|
|
32
|
+
@property
|
|
33
|
+
def is_ip_prefix(self) -> bool:
|
|
34
|
+
"""Return whether a node is a derivative of built-in IP prefixes."""
|
|
35
|
+
return InfrahubKind.IPPREFIX in self.inherit_from
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def is_ip_address(self) -> bool:
|
|
39
|
+
"""Return whether a node is a derivative of built-in IP addreses."""
|
|
40
|
+
return InfrahubKind.IPADDRESS in self.inherit_from
|
|
41
|
+
|
|
32
42
|
def validate_inheritance(self, interface: GenericSchema) -> None:
|
|
33
43
|
"""Perform checks specific to inheritance from Generics.
|
|
34
44
|
|
|
@@ -53,21 +63,19 @@ class NodeSchema(GeneratedNodeSchema):
|
|
|
53
63
|
f"{self.kind}.{attribute.name} inherited from {interface.namespace}{interface.name} must be the same kind "
|
|
54
64
|
f'["{interface_attr.kind}", "{attribute.kind}"]'
|
|
55
65
|
)
|
|
56
|
-
if attribute.optional != interface_attr.optional:
|
|
57
|
-
raise ValueError(
|
|
58
|
-
f"{self.kind}.{attribute.name} inherited from {interface.namespace}{interface.name} must have the same value for property "
|
|
59
|
-
f'"optional" ["{interface_attr.optional}", "{attribute.optional}"]'
|
|
60
|
-
)
|
|
61
66
|
|
|
62
67
|
for relationship in self.relationships:
|
|
63
|
-
if
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
if relationship.name in interface.relationship_names and not relationship.inherited:
|
|
69
|
+
interface_relationship = interface.get_relationship(relationship.name)
|
|
70
|
+
if interface_relationship.allow_override == AllowOverrideType.NONE:
|
|
71
|
+
raise ValueError(
|
|
72
|
+
f"{self.kind}'s relationship {relationship.name} inherited from {interface.kind} cannot be overriden"
|
|
73
|
+
)
|
|
74
|
+
if relationship.kind != RelationshipKind.HIERARCHY and relationship.peer != interface_relationship.peer:
|
|
75
|
+
raise ValueError(
|
|
76
|
+
f"{self.kind}'s relationship {relationship.name} inherited from {interface.kind} must have the same peer "
|
|
77
|
+
f"({interface_relationship.peer} != {relationship.peer})"
|
|
78
|
+
)
|
|
71
79
|
|
|
72
80
|
def inherit_from_interface(self, interface: GenericSchema) -> None:
|
|
73
81
|
existing_inherited_attributes: dict[str, int] = {
|
|
@@ -137,11 +145,3 @@ class NodeSchema(GeneratedNodeSchema):
|
|
|
137
145
|
if self.namespace not in ["Schema", "Internal"] and InfrahubKind.GENERICGROUP not in self.inherit_from:
|
|
138
146
|
labels.append(InfrahubKind.NODE)
|
|
139
147
|
return labels
|
|
140
|
-
|
|
141
|
-
def is_ip_prefix(self) -> bool:
|
|
142
|
-
"""Return whether a node is a derivative of built-in IP prefixes."""
|
|
143
|
-
return InfrahubKind.IPPREFIX in self.inherit_from
|
|
144
|
-
|
|
145
|
-
def is_ip_address(self) -> bool:
|
|
146
|
-
"""Return whether a node is a derivative of built-in IP addreses."""
|
|
147
|
-
return InfrahubKind.IPADDRESS in self.inherit_from
|
|
@@ -28,6 +28,14 @@ class ProfileSchema(BaseNodeSchema):
|
|
|
28
28
|
def is_template_schema(self) -> bool:
|
|
29
29
|
return False
|
|
30
30
|
|
|
31
|
+
@property
|
|
32
|
+
def is_ip_prefix(self) -> bool:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def is_ip_address(self) -> bool:
|
|
37
|
+
return False
|
|
38
|
+
|
|
31
39
|
def get_labels(self) -> list[str]:
|
|
32
40
|
"""Return the labels for this object, composed of the kind
|
|
33
41
|
and the list of Generic this object is inheriting from."""
|
|
@@ -119,7 +119,7 @@ class SchemaBranch:
|
|
|
119
119
|
def template_names(self) -> list[str]:
|
|
120
120
|
return list(self.templates.keys())
|
|
121
121
|
|
|
122
|
-
def get_all_kind_id_map(self, nodes_and_generics_only: bool = False) -> dict[str, str]:
|
|
122
|
+
def get_all_kind_id_map(self, nodes_and_generics_only: bool = False) -> dict[str, str | None]:
|
|
123
123
|
kind_id_map = {}
|
|
124
124
|
if nodes_and_generics_only:
|
|
125
125
|
names = self.node_names + self.generic_names_without_templates
|
|
@@ -226,8 +226,8 @@ class SchemaBranch:
|
|
|
226
226
|
def update(self, schema: SchemaBranch) -> None:
|
|
227
227
|
"""Update another SchemaBranch into this one."""
|
|
228
228
|
|
|
229
|
-
local_kinds =
|
|
230
|
-
other_kinds =
|
|
229
|
+
local_kinds = self.all_names
|
|
230
|
+
other_kinds = schema.all_names
|
|
231
231
|
|
|
232
232
|
in_both, _, other_only = compare_lists(list1=local_kinds, list2=other_kinds)
|
|
233
233
|
|
|
@@ -441,7 +441,7 @@ class SchemaBranch:
|
|
|
441
441
|
return list(all_schemas.values())
|
|
442
442
|
|
|
443
443
|
def get_schemas_by_rel_identifier(self, identifier: str) -> list[MainSchemaTypes]:
|
|
444
|
-
nodes: list[
|
|
444
|
+
nodes: list[MainSchemaTypes] = []
|
|
445
445
|
for node_name in list(self.nodes.keys()) + list(self.generics.keys()):
|
|
446
446
|
node = self.get(name=node_name, duplicate=False)
|
|
447
447
|
rel = node.get_relationship_by_identifier(id=identifier, raise_on_error=False)
|
|
@@ -660,7 +660,7 @@ class SchemaBranch:
|
|
|
660
660
|
and not (
|
|
661
661
|
schema_attribute_path.relationship_schema.name == "ip_namespace"
|
|
662
662
|
and isinstance(node_schema, NodeSchema)
|
|
663
|
-
and (node_schema.is_ip_address
|
|
663
|
+
and (node_schema.is_ip_address or node_schema.is_ip_prefix)
|
|
664
664
|
)
|
|
665
665
|
):
|
|
666
666
|
raise ValueError(
|
|
@@ -1447,7 +1447,8 @@ class SchemaBranch:
|
|
|
1447
1447
|
node.validate_inheritance(interface=generic_kind_schema)
|
|
1448
1448
|
|
|
1449
1449
|
# Store the list of node referencing a specific generics
|
|
1450
|
-
|
|
1450
|
+
if node.namespace != "Internal":
|
|
1451
|
+
generics_used_by[generic_kind].append(node.kind)
|
|
1451
1452
|
node.inherit_from_interface(interface=generic_kind_schema)
|
|
1452
1453
|
|
|
1453
1454
|
if len(generic_with_hierarchical_support) > 1:
|
|
@@ -1925,7 +1926,10 @@ class SchemaBranch:
|
|
|
1925
1926
|
for node_name in self.node_names + self.generic_names:
|
|
1926
1927
|
node = self.get(name=node_name, duplicate=False)
|
|
1927
1928
|
|
|
1928
|
-
if node.namespace in RESTRICTED_NAMESPACES
|
|
1929
|
+
if node.namespace in RESTRICTED_NAMESPACES and node.kind not in (
|
|
1930
|
+
InfrahubKind.IPRANGEAVAILABLE,
|
|
1931
|
+
InfrahubKind.IPPREFIXAVAILABLE,
|
|
1932
|
+
):
|
|
1929
1933
|
continue
|
|
1930
1934
|
|
|
1931
1935
|
profiles_rel_settings: dict[str, Any] = {
|
|
@@ -27,6 +27,14 @@ class TemplateSchema(BaseNodeSchema):
|
|
|
27
27
|
def is_template_schema(self) -> bool:
|
|
28
28
|
return True
|
|
29
29
|
|
|
30
|
+
@property
|
|
31
|
+
def is_ip_prefix(self) -> bool:
|
|
32
|
+
return False
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def is_ip_address(self) -> bool:
|
|
36
|
+
return False
|
|
37
|
+
|
|
30
38
|
def get_labels(self) -> list[str]:
|
|
31
39
|
"""Return the labels for this object, composed of the kind and the list of Generic this object is inheriting from."""
|
|
32
40
|
|
|
@@ -65,8 +65,12 @@ class AttributeKindUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
65
65
|
if value in (None, NULL_VALUE):
|
|
66
66
|
continue
|
|
67
67
|
try:
|
|
68
|
+
attr_value = result.get("attribute_value")
|
|
68
69
|
infrahub_attribute_class.validate_format(
|
|
69
|
-
value=
|
|
70
|
+
value=attr_value, name=self.attribute_schema.name, schema=self.attribute_schema
|
|
71
|
+
)
|
|
72
|
+
infrahub_attribute_class.validate_content(
|
|
73
|
+
value=attr_value, name=self.attribute_schema.name, schema=self.attribute_schema
|
|
70
74
|
)
|
|
71
75
|
except ValidationError:
|
|
72
76
|
grouped_data_paths.add_data_path(
|
|
@@ -6,7 +6,7 @@ from infrahub_sdk.protocols import CoreValidator
|
|
|
6
6
|
from infrahub.context import InfrahubContext
|
|
7
7
|
from infrahub.core.constants import ValidatorConclusion, ValidatorState
|
|
8
8
|
from infrahub.core.timestamp import Timestamp
|
|
9
|
-
from infrahub.services import
|
|
9
|
+
from infrahub.services.adapters.event import InfrahubEventService
|
|
10
10
|
from infrahub.validators.events import send_failed_validator, send_passed_validator
|
|
11
11
|
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ async def run_checks_and_update_validator(
|
|
|
14
14
|
checks: list[Coroutine[Any, None, ValidatorConclusion]],
|
|
15
15
|
validator: CoreValidator,
|
|
16
16
|
context: InfrahubContext,
|
|
17
|
-
|
|
17
|
+
event_service: InfrahubEventService,
|
|
18
18
|
proposed_change_id: str,
|
|
19
19
|
) -> None:
|
|
20
20
|
"""
|
|
@@ -38,7 +38,7 @@ async def run_checks_and_update_validator(
|
|
|
38
38
|
failed_early = True
|
|
39
39
|
await validator.save()
|
|
40
40
|
await send_failed_validator(
|
|
41
|
-
|
|
41
|
+
event_service=event_service, validator=validator, proposed_change_id=proposed_change_id, context=context
|
|
42
42
|
)
|
|
43
43
|
# Continue to iterate to wait for the end of all checks
|
|
44
44
|
|
|
@@ -52,9 +52,9 @@ async def run_checks_and_update_validator(
|
|
|
52
52
|
if not failed_early:
|
|
53
53
|
if validator.conclusion.value == ValidatorConclusion.SUCCESS.value:
|
|
54
54
|
await send_passed_validator(
|
|
55
|
-
|
|
55
|
+
event_service=event_service, validator=validator, proposed_change_id=proposed_change_id, context=context
|
|
56
56
|
)
|
|
57
57
|
else:
|
|
58
58
|
await send_failed_validator(
|
|
59
|
-
|
|
59
|
+
event_service=event_service, validator=validator, proposed_change_id=proposed_change_id, context=context
|
|
60
60
|
)
|
|
@@ -98,7 +98,10 @@ class ConstraintValidatorDeterminer:
|
|
|
98
98
|
continue
|
|
99
99
|
|
|
100
100
|
prop_field_update = prop_field_info.json_schema_extra.get("update")
|
|
101
|
-
if prop_field_update
|
|
101
|
+
if prop_field_update not in (
|
|
102
|
+
UpdateSupport.VALIDATE_CONSTRAINT.value,
|
|
103
|
+
UpdateSupport.MIGRATION_REQUIRED.value,
|
|
104
|
+
):
|
|
102
105
|
continue
|
|
103
106
|
|
|
104
107
|
if getattr(schema, prop_name) is None:
|
|
@@ -112,6 +115,13 @@ class ConstraintValidatorDeterminer:
|
|
|
112
115
|
)
|
|
113
116
|
constraint_name = f"node.{prop_name}.update"
|
|
114
117
|
|
|
118
|
+
do_constraint_validation = prop_field_update == UpdateSupport.VALIDATE_CONSTRAINT.value or (
|
|
119
|
+
prop_field_update == UpdateSupport.MIGRATION_REQUIRED.value
|
|
120
|
+
and CONSTRAINT_VALIDATOR_MAP.get(constraint_name)
|
|
121
|
+
)
|
|
122
|
+
if not do_constraint_validation:
|
|
123
|
+
continue
|
|
124
|
+
|
|
115
125
|
constraints.append(SchemaUpdateConstraintInfo(constraint_name=constraint_name, path=schema_path))
|
|
116
126
|
return constraints
|
|
117
127
|
|
|
@@ -154,7 +164,10 @@ class ConstraintValidatorDeterminer:
|
|
|
154
164
|
continue
|
|
155
165
|
|
|
156
166
|
prop_field_update = prop_field_info.json_schema_extra.get("update")
|
|
157
|
-
if prop_field_update
|
|
167
|
+
if prop_field_update not in (
|
|
168
|
+
UpdateSupport.VALIDATE_CONSTRAINT.value,
|
|
169
|
+
UpdateSupport.MIGRATION_REQUIRED.value,
|
|
170
|
+
):
|
|
158
171
|
continue
|
|
159
172
|
|
|
160
173
|
if prop_value is None:
|
|
@@ -168,6 +181,13 @@ class ConstraintValidatorDeterminer:
|
|
|
168
181
|
path_type = SchemaPathType.RELATIONSHIP
|
|
169
182
|
constraint_name = f"relationship.{prop_name}.update"
|
|
170
183
|
|
|
184
|
+
do_constraint_validation = prop_field_update == UpdateSupport.VALIDATE_CONSTRAINT.value or (
|
|
185
|
+
prop_field_update == UpdateSupport.MIGRATION_REQUIRED.value
|
|
186
|
+
and CONSTRAINT_VALIDATOR_MAP.get(constraint_name)
|
|
187
|
+
)
|
|
188
|
+
if not do_constraint_validation:
|
|
189
|
+
continue
|
|
190
|
+
|
|
171
191
|
schema_path = SchemaPath(
|
|
172
192
|
schema_kind=schema.kind,
|
|
173
193
|
path_type=path_type,
|
|
@@ -13,19 +13,18 @@ from infrahub.core.schema import GenericSchema, NodeSchema
|
|
|
13
13
|
from infrahub.core.validators.aggregated_checker import AggregatedConstraintChecker
|
|
14
14
|
from infrahub.core.validators.model import SchemaConstraintValidatorRequest, SchemaViolation
|
|
15
15
|
from infrahub.dependencies.registry import get_component_registry
|
|
16
|
-
from infrahub.
|
|
16
|
+
from infrahub.workers.dependencies import get_database
|
|
17
17
|
from infrahub.workflows.utils import add_tags
|
|
18
18
|
|
|
19
19
|
from .models.validate_migration import SchemaValidateMigrationData, SchemaValidatorPathResponseData
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
22
|
from infrahub.core.schema.schema_branch import SchemaBranch
|
|
23
|
+
from infrahub.database import InfrahubDatabase
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
@flow(name="schema_validate_migrations", flow_run_name="Validate schema migrations", persist_result=True)
|
|
26
|
-
async def schema_validate_migrations(
|
|
27
|
-
message: SchemaValidateMigrationData, service: InfrahubServices
|
|
28
|
-
) -> list[SchemaValidatorPathResponseData]:
|
|
27
|
+
async def schema_validate_migrations(message: SchemaValidateMigrationData) -> list[SchemaValidatorPathResponseData]:
|
|
29
28
|
batch = InfrahubBatch(return_exceptions=True)
|
|
30
29
|
log = get_run_logger()
|
|
31
30
|
await add_tags(branches=[message.branch.name])
|
|
@@ -47,7 +46,7 @@ async def schema_validate_migrations(
|
|
|
47
46
|
node_schema=schema,
|
|
48
47
|
schema_path=constraint.path,
|
|
49
48
|
schema_branch=message.schema_branch,
|
|
50
|
-
|
|
49
|
+
database=await get_database(),
|
|
51
50
|
)
|
|
52
51
|
|
|
53
52
|
results = [result async for _, result in batch.execute()]
|
|
@@ -67,9 +66,9 @@ async def schema_path_validate(
|
|
|
67
66
|
node_schema: NodeSchema | GenericSchema,
|
|
68
67
|
schema_path: SchemaPath,
|
|
69
68
|
schema_branch: SchemaBranch,
|
|
70
|
-
|
|
69
|
+
database: InfrahubDatabase,
|
|
71
70
|
) -> SchemaValidatorPathResponseData:
|
|
72
|
-
async with
|
|
71
|
+
async with database.start_session(read_only=True) as db:
|
|
73
72
|
constraint_request = SchemaConstraintValidatorRequest(
|
|
74
73
|
branch=branch,
|
|
75
74
|
constraint_name=constraint_name,
|
|
@@ -75,7 +75,7 @@ class UniquenessChecker(ConstraintCheckerInterface):
|
|
|
75
75
|
|
|
76
76
|
async def build_query_request(self, schema: MainSchemaTypes) -> NodeUniquenessQueryRequest:
|
|
77
77
|
unique_attr_paths = {
|
|
78
|
-
QueryAttributePath(attribute_name=attr_schema.name, property_name="value")
|
|
78
|
+
QueryAttributePath(attribute_name=attr_schema.name, attribute_kind=attr_schema.kind, property_name="value")
|
|
79
79
|
for attr_schema in schema.unique_attributes
|
|
80
80
|
}
|
|
81
81
|
relationship_attr_paths = set()
|
|
@@ -92,7 +92,9 @@ class UniquenessChecker(ConstraintCheckerInterface):
|
|
|
92
92
|
sub_schema, property_name = get_attribute_path_from_string(path, schema)
|
|
93
93
|
if isinstance(sub_schema, AttributeSchema):
|
|
94
94
|
unique_attr_paths.add(
|
|
95
|
-
QueryAttributePath(
|
|
95
|
+
QueryAttributePath(
|
|
96
|
+
attribute_name=sub_schema.name, attribute_kind=sub_schema.kind, property_name=property_name
|
|
97
|
+
)
|
|
96
98
|
)
|
|
97
99
|
elif isinstance(sub_schema, RelationshipSchema):
|
|
98
100
|
relationship_attr_paths.add(
|