infrahub-server 1.2.11__py3-none-any.whl → 1.3.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/actions/constants.py +130 -0
- infrahub/actions/gather.py +114 -0
- infrahub/actions/models.py +243 -0
- infrahub/actions/parsers.py +104 -0
- infrahub/actions/schema.py +393 -0
- infrahub/actions/tasks.py +119 -0
- infrahub/actions/triggers.py +21 -0
- infrahub/branch/__init__.py +0 -0
- infrahub/branch/tasks.py +29 -0
- infrahub/branch/triggers.py +22 -0
- infrahub/cli/db.py +3 -4
- infrahub/computed_attribute/gather.py +3 -1
- infrahub/computed_attribute/tasks.py +23 -29
- infrahub/core/account.py +24 -47
- infrahub/core/attribute.py +13 -15
- infrahub/core/constants/__init__.py +10 -0
- infrahub/core/constants/database.py +1 -0
- infrahub/core/constants/infrahubkind.py +9 -0
- infrahub/core/constraint/node/runner.py +3 -1
- infrahub/core/convert_object_type/__init__.py +0 -0
- infrahub/core/convert_object_type/conversion.py +124 -0
- infrahub/core/convert_object_type/schema_mapping.py +56 -0
- infrahub/core/diff/coordinator.py +8 -1
- infrahub/core/diff/query/all_conflicts.py +1 -5
- infrahub/core/diff/query/artifact.py +10 -20
- infrahub/core/diff/query/delete_query.py +8 -4
- infrahub/core/diff/query/diff_get.py +3 -6
- infrahub/core/diff/query/field_specifiers.py +1 -1
- infrahub/core/diff/query/field_summary.py +2 -4
- infrahub/core/diff/query/merge.py +72 -125
- infrahub/core/diff/query/save.py +83 -68
- infrahub/core/diff/query/summary_counts_enricher.py +34 -54
- infrahub/core/diff/query/time_range_query.py +0 -1
- infrahub/core/diff/repository/repository.py +4 -0
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/manager.py +14 -11
- infrahub/core/migrations/graph/__init__.py +6 -0
- infrahub/core/migrations/graph/m003_relationship_parent_optional.py +1 -2
- infrahub/core/migrations/graph/m012_convert_account_generic.py +1 -1
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +2 -6
- infrahub/core/migrations/graph/m015_diff_format_update.py +1 -2
- infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -2
- infrahub/core/migrations/graph/m019_restore_rels_to_time.py +11 -22
- infrahub/core/migrations/graph/m020_duplicate_edges.py +3 -6
- infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +1 -2
- infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +2 -2
- infrahub/core/migrations/graph/m024_missing_hierarchy_backfill.py +1 -2
- infrahub/core/migrations/graph/m028_delete_diffs.py +1 -2
- infrahub/core/migrations/graph/m029_duplicates_cleanup.py +662 -0
- infrahub/core/migrations/graph/m030_illegal_edges.py +82 -0
- infrahub/core/migrations/query/attribute_add.py +14 -11
- infrahub/core/migrations/query/attribute_rename.py +6 -11
- infrahub/core/migrations/query/delete_element_in_schema.py +19 -17
- infrahub/core/migrations/query/node_duplicate.py +19 -21
- infrahub/core/migrations/query/relationship_duplicate.py +19 -18
- infrahub/core/migrations/schema/node_attribute_remove.py +4 -8
- infrahub/core/migrations/schema/node_remove.py +19 -20
- infrahub/core/models.py +29 -2
- infrahub/core/node/__init__.py +131 -28
- infrahub/core/node/base.py +1 -1
- infrahub/core/node/create.py +211 -0
- infrahub/core/node/resource_manager/number_pool.py +31 -5
- infrahub/core/node/standard.py +6 -1
- infrahub/core/path.py +15 -1
- infrahub/core/protocols.py +57 -0
- infrahub/core/protocols_base.py +3 -0
- infrahub/core/query/__init__.py +2 -2
- infrahub/core/query/delete.py +3 -3
- infrahub/core/query/diff.py +19 -32
- infrahub/core/query/ipam.py +10 -20
- infrahub/core/query/node.py +29 -47
- infrahub/core/query/relationship.py +55 -34
- infrahub/core/query/resource_manager.py +1 -2
- infrahub/core/query/standard_node.py +19 -5
- infrahub/core/query/subquery.py +2 -4
- infrahub/core/relationship/constraints/count.py +10 -9
- infrahub/core/relationship/constraints/interface.py +2 -1
- infrahub/core/relationship/constraints/peer_kind.py +2 -1
- infrahub/core/relationship/constraints/peer_parent.py +56 -0
- infrahub/core/relationship/constraints/peer_relatives.py +72 -0
- infrahub/core/relationship/constraints/profiles_kind.py +1 -1
- infrahub/core/relationship/model.py +4 -1
- infrahub/core/schema/__init__.py +2 -1
- infrahub/core/schema/attribute_parameters.py +160 -0
- infrahub/core/schema/attribute_schema.py +130 -7
- infrahub/core/schema/basenode_schema.py +27 -3
- infrahub/core/schema/definitions/core/__init__.py +29 -1
- infrahub/core/schema/definitions/core/group.py +45 -0
- infrahub/core/schema/definitions/core/resource_pool.py +9 -0
- infrahub/core/schema/definitions/internal.py +43 -5
- infrahub/core/schema/generated/attribute_schema.py +16 -3
- infrahub/core/schema/generated/relationship_schema.py +11 -1
- infrahub/core/schema/manager.py +7 -2
- infrahub/core/schema/schema_branch.py +109 -12
- infrahub/core/validators/__init__.py +15 -2
- infrahub/core/validators/attribute/choices.py +1 -3
- infrahub/core/validators/attribute/enum.py +1 -3
- infrahub/core/validators/attribute/kind.py +1 -3
- infrahub/core/validators/attribute/length.py +13 -7
- infrahub/core/validators/attribute/min_max.py +118 -0
- infrahub/core/validators/attribute/number_pool.py +106 -0
- infrahub/core/validators/attribute/optional.py +1 -4
- infrahub/core/validators/attribute/regex.py +5 -6
- infrahub/core/validators/attribute/unique.py +1 -3
- infrahub/core/validators/determiner.py +18 -2
- infrahub/core/validators/enum.py +12 -0
- infrahub/core/validators/node/hierarchy.py +3 -6
- infrahub/core/validators/query.py +1 -3
- infrahub/core/validators/relationship/count.py +6 -12
- infrahub/core/validators/relationship/optional.py +2 -4
- infrahub/core/validators/relationship/peer.py +177 -12
- infrahub/core/validators/tasks.py +1 -1
- infrahub/core/validators/uniqueness/query.py +5 -9
- infrahub/database/__init__.py +12 -4
- infrahub/database/validation.py +100 -0
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +4 -0
- infrahub/dependencies/builder/constraint/relationship_manager/peer_parent.py +8 -0
- infrahub/dependencies/builder/constraint/relationship_manager/peer_relatives.py +8 -0
- infrahub/dependencies/builder/constraint/schema/aggregated.py +2 -0
- infrahub/dependencies/builder/constraint/schema/relationship_peer.py +8 -0
- infrahub/dependencies/builder/diff/deserializer.py +1 -1
- infrahub/dependencies/registry.py +4 -0
- infrahub/events/group_action.py +1 -0
- infrahub/events/models.py +1 -1
- infrahub/git/base.py +5 -3
- infrahub/git/integrator.py +96 -5
- infrahub/git/tasks.py +1 -0
- infrahub/graphql/analyzer.py +139 -18
- infrahub/graphql/manager.py +4 -0
- infrahub/graphql/mutations/action.py +164 -0
- infrahub/graphql/mutations/convert_object_type.py +71 -0
- infrahub/graphql/mutations/main.py +25 -176
- infrahub/graphql/mutations/proposed_change.py +20 -17
- infrahub/graphql/mutations/relationship.py +32 -0
- infrahub/graphql/mutations/resource_manager.py +63 -7
- infrahub/graphql/queries/convert_object_type_mapping.py +34 -0
- infrahub/graphql/queries/resource_manager.py +7 -1
- infrahub/graphql/resolvers/many_relationship.py +1 -1
- infrahub/graphql/resolvers/resolver.py +2 -2
- infrahub/graphql/resolvers/single_relationship.py +1 -1
- infrahub/graphql/schema.py +6 -0
- infrahub/menu/menu.py +34 -2
- infrahub/message_bus/messages/__init__.py +0 -10
- infrahub/message_bus/operations/__init__.py +0 -8
- infrahub/message_bus/operations/refresh/registry.py +4 -7
- infrahub/patch/queries/delete_duplicated_edges.py +45 -39
- infrahub/pools/models.py +14 -0
- infrahub/pools/number.py +5 -3
- infrahub/pools/registration.py +22 -0
- infrahub/pools/tasks.py +126 -0
- infrahub/prefect_server/models.py +1 -19
- infrahub/proposed_change/models.py +68 -3
- infrahub/proposed_change/tasks.py +911 -34
- infrahub/schema/__init__.py +0 -0
- infrahub/schema/tasks.py +27 -0
- infrahub/schema/triggers.py +23 -0
- infrahub/task_manager/models.py +10 -6
- infrahub/trigger/catalogue.py +6 -0
- infrahub/trigger/models.py +23 -6
- infrahub/trigger/setup.py +26 -2
- infrahub/trigger/tasks.py +4 -2
- infrahub/types.py +6 -0
- infrahub/webhook/tasks.py +6 -9
- infrahub/workflows/catalogue.py +103 -1
- infrahub_sdk/client.py +43 -10
- infrahub_sdk/ctl/generator.py +4 -4
- infrahub_sdk/ctl/repository.py +1 -1
- infrahub_sdk/node/__init__.py +39 -0
- infrahub_sdk/node/attribute.py +122 -0
- infrahub_sdk/node/constants.py +21 -0
- infrahub_sdk/{node.py → node/node.py} +158 -803
- infrahub_sdk/node/parsers.py +15 -0
- infrahub_sdk/node/property.py +24 -0
- infrahub_sdk/node/related_node.py +266 -0
- infrahub_sdk/node/relationship.py +302 -0
- infrahub_sdk/protocols.py +112 -0
- infrahub_sdk/protocols_base.py +34 -2
- infrahub_sdk/pytest_plugin/items/python_transform.py +2 -1
- infrahub_sdk/query_groups.py +17 -5
- infrahub_sdk/schema/main.py +1 -0
- infrahub_sdk/schema/repository.py +16 -0
- infrahub_sdk/spec/object.py +1 -1
- infrahub_sdk/store.py +1 -1
- infrahub_sdk/testing/schemas/car_person.py +1 -0
- infrahub_sdk/utils.py +7 -20
- infrahub_sdk/yaml.py +6 -5
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/METADATA +5 -5
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/RECORD +197 -168
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/WHEEL +1 -1
- infrahub_testcontainers/container.py +239 -65
- infrahub_testcontainers/docker-compose-cluster.test.yml +321 -0
- infrahub_testcontainers/docker-compose.test.yml +2 -1
- infrahub_testcontainers/helpers.py +23 -3
- infrahub_testcontainers/plugin.py +9 -0
- infrahub/message_bus/messages/check_generator_run.py +0 -26
- infrahub/message_bus/messages/finalize_validator_execution.py +0 -15
- infrahub/message_bus/messages/proposed_change/base_with_diff.py +0 -16
- infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +0 -11
- infrahub/message_bus/messages/request_generatordefinition_check.py +0 -20
- infrahub/message_bus/messages/request_proposedchange_pipeline.py +0 -23
- infrahub/message_bus/operations/check/__init__.py +0 -3
- infrahub/message_bus/operations/check/generator.py +0 -156
- infrahub/message_bus/operations/finalize/__init__.py +0 -3
- infrahub/message_bus/operations/finalize/validator.py +0 -133
- infrahub/message_bus/operations/requests/__init__.py +0 -9
- infrahub/message_bus/operations/requests/generator_definition.py +0 -140
- infrahub/message_bus/operations/requests/proposed_change.py +0 -629
- infrahub/patch/queries/consolidate_duplicated_nodes.py +0 -109
- /infrahub/{message_bus/messages/proposed_change → actions}/__init__.py +0 -0
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -2,22 +2,44 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
from infrahub.core import registry
|
|
5
6
|
from infrahub.core.query.resource_manager import NumberPoolGetReserved, NumberPoolGetUsed, NumberPoolSetReserved
|
|
7
|
+
from infrahub.core.schema.attribute_parameters import NumberAttributeParameters
|
|
6
8
|
from infrahub.exceptions import PoolExhaustedError
|
|
7
9
|
|
|
8
10
|
from .. import Node
|
|
9
11
|
|
|
10
12
|
if TYPE_CHECKING:
|
|
13
|
+
from infrahub.core.attribute import BaseAttribute
|
|
11
14
|
from infrahub.core.branch import Branch
|
|
12
15
|
from infrahub.database import InfrahubDatabase
|
|
13
16
|
|
|
14
17
|
|
|
15
18
|
class CoreNumberPool(Node):
|
|
19
|
+
def get_attribute_nb_excluded_values(self) -> int:
|
|
20
|
+
"""
|
|
21
|
+
Returns the number of excluded values for the attribute of the number pool.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
pool_node = registry.schema.get(name=self.node.value) # type: ignore [attr-defined]
|
|
25
|
+
attribute = [attribute for attribute in pool_node.attributes if attribute.name == self.node_attribute.value][0] # type: ignore [attr-defined]
|
|
26
|
+
if not isinstance(attribute.parameters, NumberAttributeParameters):
|
|
27
|
+
return 0
|
|
28
|
+
|
|
29
|
+
sum_excluded_values = 0
|
|
30
|
+
excluded_ranges = attribute.parameters.get_excluded_ranges()
|
|
31
|
+
for start_range, end_range in excluded_ranges:
|
|
32
|
+
sum_excluded_values += end_range - start_range + 1
|
|
33
|
+
|
|
34
|
+
res = len(attribute.parameters.get_excluded_single_values()) + sum_excluded_values
|
|
35
|
+
return res
|
|
36
|
+
|
|
16
37
|
async def get_resource(
|
|
17
38
|
self,
|
|
18
39
|
db: InfrahubDatabase,
|
|
19
40
|
branch: Branch,
|
|
20
41
|
node: Node,
|
|
42
|
+
attribute: BaseAttribute,
|
|
21
43
|
identifier: str | None = None,
|
|
22
44
|
) -> int:
|
|
23
45
|
identifier = identifier or node.get_id()
|
|
@@ -31,23 +53,24 @@ class CoreNumberPool(Node):
|
|
|
31
53
|
return reservation
|
|
32
54
|
|
|
33
55
|
# If we have not returned a value we need to find one if avaiable
|
|
34
|
-
number = await self.get_next(db=db, branch=branch)
|
|
56
|
+
number = await self.get_next(db=db, branch=branch, attribute=attribute)
|
|
35
57
|
|
|
36
58
|
query_set = await NumberPoolSetReserved.init(
|
|
37
59
|
db=db, pool_id=self.get_id(), identifier=identifier, reserved=number
|
|
38
60
|
)
|
|
39
61
|
await query_set.execute(db=db)
|
|
40
|
-
|
|
41
62
|
return number
|
|
42
63
|
|
|
43
|
-
async def get_next(self, db: InfrahubDatabase, branch: Branch) -> int:
|
|
64
|
+
async def get_next(self, db: InfrahubDatabase, branch: Branch, attribute: BaseAttribute) -> int:
|
|
44
65
|
query = await NumberPoolGetUsed.init(db=db, branch=branch, pool=self, branch_agnostic=True)
|
|
45
66
|
await query.execute(db=db)
|
|
46
67
|
taken = [result.get_as_optional_type("av.value", return_type=int) for result in query.results]
|
|
68
|
+
parameters = attribute.schema.parameters
|
|
47
69
|
next_number = find_next_free(
|
|
48
70
|
start=self.start_range.value, # type: ignore[attr-defined]
|
|
49
71
|
end=self.end_range.value, # type: ignore[attr-defined]
|
|
50
72
|
taken=taken,
|
|
73
|
+
parameters=parameters if isinstance(parameters, NumberAttributeParameters) else None,
|
|
51
74
|
)
|
|
52
75
|
if next_number is None:
|
|
53
76
|
raise PoolExhaustedError("There are no more values available in this pool.")
|
|
@@ -55,12 +78,15 @@ class CoreNumberPool(Node):
|
|
|
55
78
|
return next_number
|
|
56
79
|
|
|
57
80
|
|
|
58
|
-
def find_next_free(
|
|
81
|
+
def find_next_free(
|
|
82
|
+
start: int, end: int, taken: list[int | None], parameters: NumberAttributeParameters | None
|
|
83
|
+
) -> int | None:
|
|
59
84
|
used_numbers = [number for number in taken if number is not None]
|
|
60
85
|
used_set = set(used_numbers)
|
|
61
86
|
|
|
62
87
|
for num in range(start, end + 1):
|
|
63
88
|
if num not in used_set:
|
|
64
|
-
|
|
89
|
+
if parameters is None or parameters.is_valid_value(num):
|
|
90
|
+
return num
|
|
65
91
|
|
|
66
92
|
return None
|
infrahub/core/node/standard.py
CHANGED
|
@@ -210,7 +210,12 @@ class StandardNode(BaseModel):
|
|
|
210
210
|
|
|
211
211
|
@classmethod
|
|
212
212
|
async def get_list(
|
|
213
|
-
cls,
|
|
213
|
+
cls,
|
|
214
|
+
db: InfrahubDatabase,
|
|
215
|
+
limit: int = 1000,
|
|
216
|
+
ids: list[str] | None = None,
|
|
217
|
+
name: str | None = None,
|
|
218
|
+
**kwargs: dict[str, Any],
|
|
214
219
|
) -> list[Self]:
|
|
215
220
|
query: Query = await StandardNodeGetListQuery.init(
|
|
216
221
|
db=db, node_class=cls, ids=ids, node_name=name, limit=limit, **kwargs
|
infrahub/core/path.py
CHANGED
|
@@ -63,6 +63,20 @@ class DataPath(InfrahubPath):
|
|
|
63
63
|
peer_id: str | None = Field(default=None, description="")
|
|
64
64
|
value: Any | None = Field(default=None, description="Optional value of the resource")
|
|
65
65
|
|
|
66
|
+
def __hash__(self) -> int:
|
|
67
|
+
return hash(
|
|
68
|
+
(
|
|
69
|
+
self.branch,
|
|
70
|
+
self.path_type,
|
|
71
|
+
self.node_id,
|
|
72
|
+
self.kind,
|
|
73
|
+
self.field_name,
|
|
74
|
+
self.property_name,
|
|
75
|
+
self.peer_id,
|
|
76
|
+
str(self.value),
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
|
|
66
80
|
@property
|
|
67
81
|
def resource_type(self) -> PathResourceType:
|
|
68
82
|
return PathResourceType.DATA
|
|
@@ -125,7 +139,7 @@ class SchemaPath(InfrahubPath):
|
|
|
125
139
|
if self.field_name:
|
|
126
140
|
identifier += f"/{self.field_name}"
|
|
127
141
|
|
|
128
|
-
if self.property_name and
|
|
142
|
+
if self.property_name and self.path_type != SchemaPathType.NODE:
|
|
129
143
|
identifier += f"/{self.property_name}"
|
|
130
144
|
|
|
131
145
|
return identifier
|
infrahub/core/protocols.py
CHANGED
|
@@ -62,6 +62,12 @@ class BuiltinIPPrefix(CoreNode):
|
|
|
62
62
|
children: RelationshipManager
|
|
63
63
|
|
|
64
64
|
|
|
65
|
+
class CoreAction(CoreNode):
|
|
66
|
+
name: String
|
|
67
|
+
description: StringOptional
|
|
68
|
+
triggers: RelationshipManager
|
|
69
|
+
|
|
70
|
+
|
|
65
71
|
class CoreArtifactTarget(CoreNode):
|
|
66
72
|
artifacts: RelationshipManager
|
|
67
73
|
|
|
@@ -148,6 +154,10 @@ class CoreMenu(CoreNode):
|
|
|
148
154
|
children: RelationshipManager
|
|
149
155
|
|
|
150
156
|
|
|
157
|
+
class CoreNodeTriggerMatch(CoreNode):
|
|
158
|
+
trigger: RelationshipManager
|
|
159
|
+
|
|
160
|
+
|
|
151
161
|
class CoreObjectComponentTemplate(CoreNode):
|
|
152
162
|
template_name: String
|
|
153
163
|
|
|
@@ -189,6 +199,14 @@ class CoreTransformation(CoreNode):
|
|
|
189
199
|
tags: RelationshipManager
|
|
190
200
|
|
|
191
201
|
|
|
202
|
+
class CoreTriggerRule(CoreNode):
|
|
203
|
+
name: String
|
|
204
|
+
description: StringOptional
|
|
205
|
+
active: Boolean
|
|
206
|
+
branch_scope: Dropdown
|
|
207
|
+
action: RelationshipManager
|
|
208
|
+
|
|
209
|
+
|
|
192
210
|
class CoreValidator(CoreNode):
|
|
193
211
|
label: StringOptional
|
|
194
212
|
state: Enum
|
|
@@ -326,6 +344,10 @@ class CoreFileThread(CoreThread):
|
|
|
326
344
|
repository: RelationshipManager
|
|
327
345
|
|
|
328
346
|
|
|
347
|
+
class CoreGeneratorAction(CoreAction):
|
|
348
|
+
generator: RelationshipManager
|
|
349
|
+
|
|
350
|
+
|
|
329
351
|
class CoreGeneratorCheck(CoreCheck):
|
|
330
352
|
instance: String
|
|
331
353
|
|
|
@@ -380,6 +402,16 @@ class CoreGraphQLQueryGroup(CoreGroup):
|
|
|
380
402
|
query: RelationshipManager
|
|
381
403
|
|
|
382
404
|
|
|
405
|
+
class CoreGroupAction(CoreAction):
|
|
406
|
+
member_action: Dropdown
|
|
407
|
+
group: RelationshipManager
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
class CoreGroupTriggerRule(CoreTriggerRule):
|
|
411
|
+
member_update: Dropdown
|
|
412
|
+
group: RelationshipManager
|
|
413
|
+
|
|
414
|
+
|
|
383
415
|
class CoreIPAddressPool(CoreResourcePool, LineageSource):
|
|
384
416
|
default_address_type: String
|
|
385
417
|
default_prefix_length: IntegerOptional
|
|
@@ -399,11 +431,31 @@ class CoreMenuItem(CoreMenu):
|
|
|
399
431
|
pass
|
|
400
432
|
|
|
401
433
|
|
|
434
|
+
class CoreNodeTriggerAttributeMatch(CoreNodeTriggerMatch):
|
|
435
|
+
attribute_name: String
|
|
436
|
+
value: StringOptional
|
|
437
|
+
value_previous: StringOptional
|
|
438
|
+
value_match: Dropdown
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
class CoreNodeTriggerRelationshipMatch(CoreNodeTriggerMatch):
|
|
442
|
+
relationship_name: String
|
|
443
|
+
modification_type: Dropdown
|
|
444
|
+
peer: StringOptional
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
class CoreNodeTriggerRule(CoreTriggerRule):
|
|
448
|
+
node_kind: String
|
|
449
|
+
mutation_action: Enum
|
|
450
|
+
matches: RelationshipManager
|
|
451
|
+
|
|
452
|
+
|
|
402
453
|
class CoreNumberPool(CoreResourcePool, LineageSource):
|
|
403
454
|
node: String
|
|
404
455
|
node_attribute: String
|
|
405
456
|
start_range: Integer
|
|
406
457
|
end_range: Integer
|
|
458
|
+
pool_type: Enum
|
|
407
459
|
|
|
408
460
|
|
|
409
461
|
class CoreObjectPermission(CoreBasePermission):
|
|
@@ -446,6 +498,11 @@ class CoreRepository(LineageOwner, LineageSource, CoreGenericRepository, CoreTas
|
|
|
446
498
|
commit: StringOptional
|
|
447
499
|
|
|
448
500
|
|
|
501
|
+
class CoreRepositoryGroup(CoreGroup):
|
|
502
|
+
content: Dropdown
|
|
503
|
+
repository: RelationshipManager
|
|
504
|
+
|
|
505
|
+
|
|
449
506
|
class CoreRepositoryValidator(CoreValidator):
|
|
450
507
|
repository: RelationshipManager
|
|
451
508
|
|
infrahub/core/protocols_base.py
CHANGED
|
@@ -7,6 +7,7 @@ from typing_extensions import Self
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
8
|
from neo4j import AsyncResult, AsyncSession, AsyncTransaction, Record
|
|
9
9
|
|
|
10
|
+
from infrahub.core.schema import NonGenericSchemaTypes
|
|
10
11
|
from infrahub.core.schema.schema_branch import SchemaBranch
|
|
11
12
|
|
|
12
13
|
|
|
@@ -70,6 +71,8 @@ class CoreNode(Protocol):
|
|
|
70
71
|
|
|
71
72
|
def get_id(self) -> str: ...
|
|
72
73
|
def get_kind(self) -> str: ...
|
|
74
|
+
def get_schema(self) -> NonGenericSchemaTypes: ...
|
|
75
|
+
|
|
73
76
|
@classmethod
|
|
74
77
|
async def init(
|
|
75
78
|
cls,
|
infrahub/core/query/__init__.py
CHANGED
|
@@ -424,8 +424,8 @@ class Query(ABC):
|
|
|
424
424
|
else:
|
|
425
425
|
self.query_lines.extend([line.strip() for line in query.split("\n") if line.strip()])
|
|
426
426
|
|
|
427
|
-
def add_subquery(self, subquery: str, with_clause: str | None = None) -> None:
|
|
428
|
-
self.add_to_query("CALL {")
|
|
427
|
+
def add_subquery(self, subquery: str, node_alias: str, with_clause: str | None = None) -> None:
|
|
428
|
+
self.add_to_query(f"CALL ({node_alias}) {{")
|
|
429
429
|
self.add_to_query(subquery)
|
|
430
430
|
self.add_to_query("}")
|
|
431
431
|
if with_clause:
|
infrahub/core/query/delete.py
CHANGED
|
@@ -21,7 +21,7 @@ class DeleteAfterTimeQuery(Query):
|
|
|
21
21
|
// ---------------------
|
|
22
22
|
// Reset edges with to time after timestamp
|
|
23
23
|
// ---------------------
|
|
24
|
-
CALL {
|
|
24
|
+
CALL () {
|
|
25
25
|
OPTIONAL MATCH (p)-[r]-(q)
|
|
26
26
|
WHERE r.to > $timestamp
|
|
27
27
|
SET r.to = NULL
|
|
@@ -33,7 +33,7 @@ class DeleteAfterTimeQuery(Query):
|
|
|
33
33
|
// ---------------------
|
|
34
34
|
// Delete edges with from time after timestamp timestamp
|
|
35
35
|
// ---------------------
|
|
36
|
-
CALL {
|
|
36
|
+
CALL () {
|
|
37
37
|
OPTIONAL MATCH (p)-[r]->(q)
|
|
38
38
|
WHERE r.from > $timestamp
|
|
39
39
|
DELETE r
|
|
@@ -49,7 +49,7 @@ class DeleteAfterTimeQuery(Query):
|
|
|
49
49
|
// ---------------------
|
|
50
50
|
// Delete edges with from time after timestamp timestamp
|
|
51
51
|
// ---------------------
|
|
52
|
-
CALL {
|
|
52
|
+
CALL () {
|
|
53
53
|
OPTIONAL MATCH (p)-[r]->(q)
|
|
54
54
|
WHERE r.from > $timestamp
|
|
55
55
|
DELETE r
|
infrahub/core/query/diff.py
CHANGED
|
@@ -121,10 +121,9 @@ class DiffCalculationQuery(DiffQuery):
|
|
|
121
121
|
|
|
122
122
|
previous_base_path_query = """
|
|
123
123
|
WITH DISTINCT diff_path AS diff_path, has_more_data
|
|
124
|
-
CALL {
|
|
125
|
-
WITH diff_path
|
|
126
|
-
WITH
|
|
127
|
-
WITH diff_path, d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop
|
|
124
|
+
CALL (diff_path) {
|
|
125
|
+
WITH nodes(diff_path) AS d_nodes, relationships(diff_path) AS d_rels
|
|
126
|
+
WITH d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop
|
|
128
127
|
// -------------------------------------
|
|
129
128
|
// add base branch paths before branched_from, if they exist
|
|
130
129
|
// -------------------------------------
|
|
@@ -158,10 +157,9 @@ CALL {
|
|
|
158
157
|
WITH diff_path, latest_base_path, has_more_data
|
|
159
158
|
UNWIND [diff_path, latest_base_path] AS penultimate_path
|
|
160
159
|
WITH DISTINCT penultimate_path, has_more_data
|
|
161
|
-
CALL {
|
|
162
|
-
WITH penultimate_path
|
|
163
|
-
WITH
|
|
164
|
-
WITH penultimate_path, d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop
|
|
160
|
+
CALL (penultimate_path) {
|
|
161
|
+
WITH nodes(penultimate_path) AS d_nodes, relationships(penultimate_path) AS d_rels
|
|
162
|
+
WITH d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop
|
|
165
163
|
// -------------------------------------
|
|
166
164
|
// Add peer-side of any relationships to get the peer's ID
|
|
167
165
|
// -------------------------------------
|
|
@@ -299,8 +297,7 @@ WITH one_result[0] AS p, one_result[1] AS q, one_result[2] AS diff_rel, one_resu
|
|
|
299
297
|
// -------------------------------------
|
|
300
298
|
// Exclude nodes added then removed on branch within timeframe
|
|
301
299
|
// -------------------------------------
|
|
302
|
-
CALL {
|
|
303
|
-
WITH p, q, row_from_time
|
|
300
|
+
CALL (p, q, row_from_time) {
|
|
304
301
|
OPTIONAL MATCH (q)<-[is_part_of:IS_PART_OF {branch: $branch_name}]-(p)
|
|
305
302
|
WHERE row_from_time <= is_part_of.from < $to_time
|
|
306
303
|
WITH DISTINCT is_part_of.status AS rel_status
|
|
@@ -312,8 +309,7 @@ WHERE intra_branch_update = FALSE
|
|
|
312
309
|
// -------------------------------------
|
|
313
310
|
// Get every path on this branch under each node
|
|
314
311
|
// -------------------------------------
|
|
315
|
-
CALL {
|
|
316
|
-
WITH p, q, diff_rel, row_from_time
|
|
312
|
+
CALL (p, q, diff_rel, row_from_time) {
|
|
317
313
|
OPTIONAL MATCH path = (
|
|
318
314
|
(q)<-[top_diff_rel:IS_PART_OF]-(p)-[r_node]-(node)-[r_prop]-(prop)
|
|
319
315
|
)
|
|
@@ -340,12 +336,11 @@ CALL {
|
|
|
340
336
|
p.uuid IS NULL OR prop.uuid IS NULL OR p.uuid <> prop.uuid
|
|
341
337
|
OR type(r_node) <> "IS_RELATED" OR type(r_prop) <> "IS_RELATED"
|
|
342
338
|
)
|
|
343
|
-
WITH path,
|
|
339
|
+
WITH path, node, prop, r_prop, r_node, type(r_node) AS rel_type, row_from_time
|
|
344
340
|
// -------------------------------------
|
|
345
341
|
// Exclude attributes/relationships added then removed on branch within timeframe
|
|
346
342
|
// -------------------------------------
|
|
347
|
-
CALL {
|
|
348
|
-
WITH p, rel_type, node, row_from_time
|
|
343
|
+
CALL (p, rel_type, node, row_from_time) {
|
|
349
344
|
OPTIONAL MATCH (p)-[rel_to_check {branch: $branch_name}]-(node)
|
|
350
345
|
WHERE row_from_time <= rel_to_check.from < $to_time
|
|
351
346
|
AND type(rel_to_check) = rel_type
|
|
@@ -484,8 +479,7 @@ END AS row_from_time
|
|
|
484
479
|
// Exclude attributes/relationship under nodes deleted on this branch in the timeframe
|
|
485
480
|
// because those were all handled above at the node level
|
|
486
481
|
// -------------------------------------
|
|
487
|
-
CALL {
|
|
488
|
-
WITH root, p, row_from_time
|
|
482
|
+
CALL (root, p, row_from_time) {
|
|
489
483
|
OPTIONAL MATCH (root)<-[r_root_deleted:IS_PART_OF {branch: $branch_name}]-(p)
|
|
490
484
|
WHERE row_from_time <= r_root_deleted.from < $to_time
|
|
491
485
|
WITH r_root_deleted
|
|
@@ -499,8 +493,7 @@ WHERE node_deleted = FALSE
|
|
|
499
493
|
// Exclude relationships added and deleted within the timeframe
|
|
500
494
|
// -------------------------------------
|
|
501
495
|
WITH root, r_root, p, diff_rel, q, has_more_data, row_from_time, type(diff_rel) AS rel_type
|
|
502
|
-
CALL {
|
|
503
|
-
WITH p, rel_type, q, row_from_time
|
|
496
|
+
CALL (p, rel_type, q, row_from_time) {
|
|
504
497
|
OPTIONAL MATCH (p)-[rel_to_check {branch: $branch_name}]-(q)
|
|
505
498
|
WHERE row_from_time <= rel_to_check.from < $to_time
|
|
506
499
|
AND type(rel_to_check) = rel_type
|
|
@@ -513,8 +506,7 @@ WHERE intra_branch_update = FALSE
|
|
|
513
506
|
// -------------------------------------
|
|
514
507
|
// Get every path on this branch under each attribute/relationship
|
|
515
508
|
// -------------------------------------
|
|
516
|
-
CALL {
|
|
517
|
-
WITH root, r_root, p, diff_rel, q
|
|
509
|
+
CALL (root, r_root, p, diff_rel, q) {
|
|
518
510
|
OPTIONAL MATCH path = (
|
|
519
511
|
(root:Root)<-[mid_r_root:IS_PART_OF]-(p)-[mid_diff_rel]-(q)-[r_prop]-(prop)
|
|
520
512
|
)
|
|
@@ -549,8 +541,7 @@ CALL {
|
|
|
549
541
|
// Exclude properties added and deleted within the timeframe
|
|
550
542
|
// -------------------------------------
|
|
551
543
|
WITH q, nodes(latest_prop_path)[3] AS prop, type(relationships(latest_prop_path)[2]) AS rel_type, latest_prop_path, has_more_data, row_from_time
|
|
552
|
-
CALL {
|
|
553
|
-
WITH q, rel_type, prop, row_from_time
|
|
544
|
+
CALL (q, rel_type, prop, row_from_time) {
|
|
554
545
|
OPTIONAL MATCH (q)-[rel_to_check {branch: $branch_name}]-(prop)
|
|
555
546
|
WHERE row_from_time <= rel_to_check.from < $to_time
|
|
556
547
|
AND type(rel_to_check) = rel_type
|
|
@@ -717,14 +708,12 @@ ORDER BY
|
|
|
717
708
|
r_node.from DESC,
|
|
718
709
|
r_root.from DESC
|
|
719
710
|
WITH n, p, row_from_time, diff_rel, diff_rel_path, has_more_data
|
|
720
|
-
CALL {
|
|
711
|
+
CALL (n, p, row_from_time){
|
|
721
712
|
// -------------------------------------
|
|
722
713
|
// Exclude properties under nodes and attributes/relationships deleted
|
|
723
714
|
// on this branch in the timeframe because those were all handled above
|
|
724
715
|
// -------------------------------------
|
|
725
|
-
|
|
726
|
-
CALL {
|
|
727
|
-
WITH n, row_from_time
|
|
716
|
+
CALL (n, row_from_time) {
|
|
728
717
|
OPTIONAL MATCH (root:Root)<-[r_root_deleted:IS_PART_OF {branch: $branch_name}]-(n)
|
|
729
718
|
WHERE r_root_deleted.from < $to_time
|
|
730
719
|
WITH r_root_deleted
|
|
@@ -732,9 +721,8 @@ CALL {
|
|
|
732
721
|
LIMIT 1
|
|
733
722
|
RETURN COALESCE(r_root_deleted.status = "deleted", FALSE) AS node_deleted
|
|
734
723
|
}
|
|
735
|
-
WITH
|
|
736
|
-
CALL {
|
|
737
|
-
WITH n, p, row_from_time
|
|
724
|
+
WITH node_deleted
|
|
725
|
+
CALL (n, p, row_from_time) {
|
|
738
726
|
OPTIONAL MATCH (n)-[r_node_deleted {branch: $branch_name}]-(p)
|
|
739
727
|
WHERE row_from_time <= r_node_deleted.from < $to_time
|
|
740
728
|
AND type(r_node_deleted) IN ["HAS_ATTRIBUTE", "IS_RELATED"]
|
|
@@ -803,8 +791,7 @@ AND (
|
|
|
803
791
|
// -------------------------------------
|
|
804
792
|
// Ignore node created and deleted on this branch
|
|
805
793
|
// -------------------------------------
|
|
806
|
-
CALL {
|
|
807
|
-
WITH n
|
|
794
|
+
CALL (n) {
|
|
808
795
|
OPTIONAL MATCH (:Root)<-[diff_rel:IS_PART_OF {branch: $branch_name}]-(n)
|
|
809
796
|
WITH diff_rel
|
|
810
797
|
ORDER BY diff_rel.from ASC
|
infrahub/core/query/ipam.py
CHANGED
|
@@ -80,8 +80,7 @@ class IPPrefixSubnetFetch(Query):
|
|
|
80
80
|
// First match on IPNAMESPACE
|
|
81
81
|
MATCH (ns:%(ns_label)s)
|
|
82
82
|
WHERE ns.uuid = $ns_id
|
|
83
|
-
CALL {
|
|
84
|
-
WITH ns
|
|
83
|
+
CALL (ns) {
|
|
85
84
|
MATCH (ns)-[r:IS_PART_OF]-(root:Root)
|
|
86
85
|
WHERE %(branch_filter)s
|
|
87
86
|
RETURN ns as ns1, r as r1
|
|
@@ -104,8 +103,7 @@ class IPPrefixSubnetFetch(Query):
|
|
|
104
103
|
// ---
|
|
105
104
|
// FIND ALL CHILDREN OF THESE PREFIXES
|
|
106
105
|
// ---
|
|
107
|
-
CALL {
|
|
108
|
-
WITH all_prefixes
|
|
106
|
+
CALL (all_prefixes) {
|
|
109
107
|
UNWIND all_prefixes as prefix
|
|
110
108
|
OPTIONAL MATCH (prefix)<-[:IS_RELATED]-(ch_rel:Relationship)<-[:IS_RELATED]-(children:BuiltinIPPrefix)
|
|
111
109
|
WHERE ch_rel.name = "parent__child"
|
|
@@ -171,8 +169,7 @@ class IPPrefixIPAddressFetch(Query):
|
|
|
171
169
|
// First match on IPNAMESPACE
|
|
172
170
|
MATCH (ns:%(ns_label)s)
|
|
173
171
|
WHERE ns.uuid = $ns_id
|
|
174
|
-
CALL {
|
|
175
|
-
WITH ns
|
|
172
|
+
CALL (ns) {
|
|
176
173
|
MATCH (ns)-[r:IS_PART_OF]-(root:Root)
|
|
177
174
|
WHERE %(branch_filter)s
|
|
178
175
|
RETURN ns as ns1, r as r1
|
|
@@ -271,8 +268,7 @@ class IPPrefixUtilization(Query):
|
|
|
271
268
|
query = f"""
|
|
272
269
|
MATCH (pfx:Node)
|
|
273
270
|
WHERE pfx.uuid IN $ids
|
|
274
|
-
CALL {{
|
|
275
|
-
WITH pfx
|
|
271
|
+
CALL (pfx) {{
|
|
276
272
|
MATCH (pfx)-[r_rel1:IS_RELATED]-(rl:Relationship)<-[r_rel2:IS_RELATED]-(child:Node)
|
|
277
273
|
WHERE rl.name IN [{", ".join(self.allocated_kinds_rel)}]
|
|
278
274
|
AND any(l IN labels(child) WHERE l IN [{", ".join(self.allocated_kinds)}])
|
|
@@ -425,8 +421,7 @@ class IPPrefixReconcileQuery(Query):
|
|
|
425
421
|
// ------------------
|
|
426
422
|
// Get prefix node's current parent, if it exists
|
|
427
423
|
// ------------------
|
|
428
|
-
CALL {
|
|
429
|
-
WITH ip_node
|
|
424
|
+
CALL (ip_node) {
|
|
430
425
|
OPTIONAL MATCH parent_prefix_path = (ip_node)-[r1:IS_RELATED]->(:Relationship {name: "parent__child"})-[r2:IS_RELATED]->(current_parent:%(ip_prefix_kind)s)
|
|
431
426
|
WHERE all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
|
|
432
427
|
RETURN current_parent, (r1.status = "active" AND r2.status = "active") AS parent_is_active
|
|
@@ -444,8 +439,7 @@ class IPPrefixReconcileQuery(Query):
|
|
|
444
439
|
// ------------------
|
|
445
440
|
// Get prefix node's current prefix children, if any exist
|
|
446
441
|
// ------------------
|
|
447
|
-
CALL {
|
|
448
|
-
WITH ip_node
|
|
442
|
+
CALL (ip_node) {
|
|
449
443
|
OPTIONAL MATCH child_prefix_path = (ip_node)<-[r1:IS_RELATED]-(:Relationship {name: "parent__child"})<-[r2:IS_RELATED]-(current_prefix_child:%(ip_prefix_kind)s)
|
|
450
444
|
WHERE all(r IN relationships(child_prefix_path) WHERE (%(branch_filter)s))
|
|
451
445
|
WITH current_prefix_child, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -457,8 +451,7 @@ class IPPrefixReconcileQuery(Query):
|
|
|
457
451
|
// ------------------
|
|
458
452
|
// Get prefix node's current address children, if any exist
|
|
459
453
|
// ------------------
|
|
460
|
-
CALL {
|
|
461
|
-
WITH ip_node
|
|
454
|
+
CALL (ip_node) {
|
|
462
455
|
OPTIONAL MATCH child_address_path = (ip_node)-[r1:IS_RELATED]-(:Relationship {name: "ip_prefix__ip_address"})-[r2:IS_RELATED]-(current_address_child:%(ip_address_kind)s)
|
|
463
456
|
WHERE all(r IN relationships(child_address_path) WHERE (%(branch_filter)s))
|
|
464
457
|
WITH current_address_child, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -480,8 +473,7 @@ class IPPrefixReconcileQuery(Query):
|
|
|
480
473
|
// ------------------
|
|
481
474
|
// Identify the correct parent, if any, for the prefix node
|
|
482
475
|
// ------------------
|
|
483
|
-
CALL {
|
|
484
|
-
WITH ip_namespace
|
|
476
|
+
CALL (ip_namespace) {
|
|
485
477
|
OPTIONAL MATCH parent_path = (ip_namespace)-[pr1:IS_RELATED {status: "active"}]-(ns_rel:Relationship {name: "ip_namespace__ip_prefix"})
|
|
486
478
|
-[pr2:IS_RELATED {status: "active"}]-(maybe_new_parent:%(ip_prefix_kind)s)
|
|
487
479
|
-[har:HAS_ATTRIBUTE]->(:Attribute {name: "prefix"})
|
|
@@ -517,9 +509,8 @@ class IPPrefixReconcileQuery(Query):
|
|
|
517
509
|
// ------------------
|
|
518
510
|
// Identify the correct children, if any, for the prefix node
|
|
519
511
|
// ------------------
|
|
520
|
-
CALL {
|
|
512
|
+
CALL (ip_namespace, ip_node) {
|
|
521
513
|
// Get ALL possible children for the prefix node
|
|
522
|
-
WITH ip_namespace, ip_node
|
|
523
514
|
OPTIONAL MATCH child_path = (
|
|
524
515
|
(ip_namespace)-[r1:IS_RELATED]
|
|
525
516
|
-(ns_rel:Relationship)-[r2:IS_RELATED]
|
|
@@ -558,12 +549,11 @@ class IPPrefixReconcileQuery(Query):
|
|
|
558
549
|
WITH ip_namespace, ip_node, current_parent, current_children, new_parent, collect([maybe_new_child, latest_mnc_attribute]) AS maybe_children_ips
|
|
559
550
|
WITH ip_namespace, ip_node, current_parent, current_children, new_parent, maybe_children_ips, range(0, size(maybe_children_ips) - 1) AS child_indices
|
|
560
551
|
UNWIND child_indices as ind
|
|
561
|
-
CALL {
|
|
552
|
+
CALL (ind, maybe_children_ips) {
|
|
562
553
|
// ------------------
|
|
563
554
|
// Filter all possible children to remove those that have a more-specific parent
|
|
564
555
|
// among the list of all possible children
|
|
565
556
|
// ------------------
|
|
566
|
-
WITH ind, maybe_children_ips
|
|
567
557
|
WITH ind, maybe_children_ips AS ips
|
|
568
558
|
RETURN REDUCE(
|
|
569
559
|
has_more_specific_parent = FALSE, potential_parent IN ips |
|