infrahub-server 1.3.6__py3-none-any.whl → 1.4.0b1__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 -41
- infrahub/cli/upgrade.py +7 -29
- infrahub/computed_attribute/tasks.py +36 -46
- infrahub/config.py +53 -2
- infrahub/constants/environment.py +1 -0
- infrahub/core/attribute.py +9 -7
- infrahub/core/branch/tasks.py +43 -41
- infrahub/core/constants/__init__.py +20 -6
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/diff/coordinator.py +3 -1
- 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 +62 -33
- infrahub/core/ipam/tasks.py +4 -3
- infrahub/core/manager.py +2 -2
- infrahub/core/merge.py +8 -10
- infrahub/core/migrations/graph/__init__.py +4 -0
- infrahub/core/migrations/graph/m035_drop_attr_value_index.py +45 -0
- infrahub/core/migrations/graph/m036_index_attr_vals.py +577 -0
- infrahub/core/migrations/query/attribute_add.py +27 -2
- infrahub/core/migrations/query/node_duplicate.py +3 -26
- infrahub/core/migrations/schema/tasks.py +6 -5
- 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 -23
- infrahub/core/query/resource_manager.py +3 -3
- infrahub/core/relationship/model.py +13 -13
- 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/generic_schema.py +10 -0
- infrahub/core/schema/manager.py +10 -1
- infrahub/core/schema/node_schema.py +22 -17
- infrahub/core/schema/profile_schema.py +8 -0
- infrahub/core/schema/schema_branch.py +9 -5
- infrahub/core/schema/template_schema.py +8 -0
- infrahub/core/validators/checks_runner.py +5 -5
- 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 +18 -0
- infrahub/events/constants.py +7 -0
- infrahub/events/generator.py +29 -2
- infrahub/events/proposed_change_action.py +181 -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/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 +225 -8
- infrahub/graphql/mutations/relationship.py +6 -1
- 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 +3 -3
- 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 +60 -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/globals.py +1 -4
- 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/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 +52 -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 +6 -6
- infrahub_sdk/ctl/repository.py +51 -0
- infrahub_sdk/ctl/schema.py +9 -9
- infrahub_sdk/protocols.py +40 -6
- {infrahub_server-1.3.6.dist-info → infrahub_server-1.4.0b1.dist-info}/METADATA +6 -4
- {infrahub_server-1.3.6.dist-info → infrahub_server-1.4.0b1.dist-info}/RECORD +162 -149
- 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/cli/db_commands/check_inheritance.py +0 -284
- /infrahub/{cli/db_commands/__init__.py → py.typed} +0 -0
- {infrahub_server-1.3.6.dist-info → infrahub_server-1.4.0b1.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.3.6.dist-info → infrahub_server-1.4.0b1.dist-info}/WHEEL +0 -0
- {infrahub_server-1.3.6.dist-info → infrahub_server-1.4.0b1.dist-info}/entry_points.txt +0 -0
|
@@ -10,17 +10,18 @@ from prefect.logging import get_run_logger
|
|
|
10
10
|
from infrahub.core.branch import Branch # noqa: TC001
|
|
11
11
|
from infrahub.core.migrations import MIGRATION_MAP
|
|
12
12
|
from infrahub.core.path import SchemaPath # noqa: TC001
|
|
13
|
-
from infrahub.
|
|
13
|
+
from infrahub.workers.dependencies import get_database
|
|
14
14
|
from infrahub.workflows.utils import add_branch_tag
|
|
15
15
|
|
|
16
16
|
from .models import SchemaApplyMigrationData, SchemaMigrationPathResponseData
|
|
17
17
|
|
|
18
18
|
if TYPE_CHECKING:
|
|
19
19
|
from infrahub.core.schema import MainSchemaTypes
|
|
20
|
+
from infrahub.database import InfrahubDatabase
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
@flow(name="schema_apply_migrations", flow_run_name="Apply schema migrations", persist_result=True)
|
|
23
|
-
async def schema_apply_migrations(message: SchemaApplyMigrationData
|
|
24
|
+
async def schema_apply_migrations(message: SchemaApplyMigrationData) -> list[str]:
|
|
24
25
|
await add_branch_tag(branch_name=message.branch.name)
|
|
25
26
|
log = get_run_logger()
|
|
26
27
|
|
|
@@ -55,7 +56,7 @@ async def schema_apply_migrations(message: SchemaApplyMigrationData, service: In
|
|
|
55
56
|
new_node_schema=new_node_schema,
|
|
56
57
|
previous_node_schema=previous_node_schema,
|
|
57
58
|
schema_path=migration.path,
|
|
58
|
-
|
|
59
|
+
database=await get_database(),
|
|
59
60
|
)
|
|
60
61
|
|
|
61
62
|
async for _, result in batch.execute():
|
|
@@ -75,13 +76,13 @@ async def schema_path_migrate(
|
|
|
75
76
|
branch: Branch,
|
|
76
77
|
migration_name: str,
|
|
77
78
|
schema_path: SchemaPath,
|
|
78
|
-
|
|
79
|
+
database: InfrahubDatabase,
|
|
79
80
|
new_node_schema: MainSchemaTypes | None = None,
|
|
80
81
|
previous_node_schema: MainSchemaTypes | None = None,
|
|
81
82
|
) -> SchemaMigrationPathResponseData:
|
|
82
83
|
log = get_run_logger()
|
|
83
84
|
|
|
84
|
-
async with
|
|
85
|
+
async with database.start_session() as db:
|
|
85
86
|
node_kind = None
|
|
86
87
|
if new_node_schema:
|
|
87
88
|
node_kind = new_node_schema.kind
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from typing import cast
|
|
2
|
+
|
|
3
|
+
from infrahub.core.constants.infrahubkind import THREADCOMMENT
|
|
4
|
+
from infrahub.core.manager import NodeManager
|
|
5
|
+
from infrahub.core.node import Node
|
|
6
|
+
from infrahub.core.protocols import CoreProposedChange as CoreProposedChangeProtocol
|
|
7
|
+
from infrahub.database import InfrahubDatabase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CoreProposedChange(Node):
|
|
11
|
+
async def to_graphql(
|
|
12
|
+
self,
|
|
13
|
+
db: InfrahubDatabase,
|
|
14
|
+
fields: dict | None = None,
|
|
15
|
+
related_node_ids: set | None = None,
|
|
16
|
+
filter_sensitive: bool = False,
|
|
17
|
+
permissions: dict | None = None,
|
|
18
|
+
include_properties: bool = True,
|
|
19
|
+
) -> dict:
|
|
20
|
+
response = await super().to_graphql(
|
|
21
|
+
db,
|
|
22
|
+
fields=fields,
|
|
23
|
+
related_node_ids=related_node_ids,
|
|
24
|
+
filter_sensitive=filter_sensitive,
|
|
25
|
+
permissions=permissions,
|
|
26
|
+
include_properties=include_properties,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
if fields:
|
|
30
|
+
if "total_comments" in fields:
|
|
31
|
+
total_comments = 0
|
|
32
|
+
proposed_change = cast(CoreProposedChangeProtocol, self)
|
|
33
|
+
change_comments = await proposed_change.comments.get_relationships(db=db)
|
|
34
|
+
total_comments += len(change_comments)
|
|
35
|
+
|
|
36
|
+
threads = await proposed_change.threads.get_peers(db=db)
|
|
37
|
+
thread_comments = await NodeManager.query(
|
|
38
|
+
db=db, schema=THREADCOMMENT, filters={"thread__ids": list(threads.keys())}
|
|
39
|
+
)
|
|
40
|
+
total_comments += len(thread_comments)
|
|
41
|
+
response["total_comments"] = {"value": total_comments}
|
|
42
|
+
|
|
43
|
+
return response
|
infrahub/core/protocols.py
CHANGED
|
@@ -319,6 +319,7 @@ class CoreCheckDefinition(CoreTaskTarget):
|
|
|
319
319
|
|
|
320
320
|
|
|
321
321
|
class CoreCustomWebhook(CoreWebhook, CoreTaskTarget):
|
|
322
|
+
shared_key: StringOptional
|
|
322
323
|
transformation: RelationshipManager
|
|
323
324
|
|
|
324
325
|
|
|
@@ -480,7 +481,10 @@ class CoreProposedChange(CoreTaskTarget):
|
|
|
480
481
|
source_branch: String
|
|
481
482
|
destination_branch: String
|
|
482
483
|
state: Enum
|
|
484
|
+
is_draft: Boolean
|
|
485
|
+
total_comments: IntegerOptional
|
|
483
486
|
approved_by: RelationshipManager
|
|
487
|
+
rejected_by: RelationshipManager
|
|
484
488
|
reviewers: RelationshipManager
|
|
485
489
|
created_by: RelationshipManager
|
|
486
490
|
comments: RelationshipManager
|
|
@@ -554,6 +558,14 @@ class InternalAccountToken(CoreNode):
|
|
|
554
558
|
account: RelationshipManager
|
|
555
559
|
|
|
556
560
|
|
|
561
|
+
class InternalIPPrefixAvailable(BuiltinIPPrefix):
|
|
562
|
+
pass
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
class InternalIPRangeAvailable(BuiltinIPAddress):
|
|
566
|
+
last_address: IPHost
|
|
567
|
+
|
|
568
|
+
|
|
557
569
|
class InternalRefreshToken(CoreNode):
|
|
558
570
|
expiration: DateTime
|
|
559
571
|
account: RelationshipManager
|
infrahub/core/query/attribute.py
CHANGED
|
@@ -5,9 +5,16 @@ from typing import TYPE_CHECKING, Any
|
|
|
5
5
|
from infrahub.core.constants import AttributeDBNodeType
|
|
6
6
|
from infrahub.core.constants.relationship_label import RELATIONSHIP_TO_NODE_LABEL, RELATIONSHIP_TO_VALUE_LABEL
|
|
7
7
|
from infrahub.core.constants.schema import FlagProperty, NodeProperty
|
|
8
|
+
from infrahub.core.graph.schema import (
|
|
9
|
+
GraphAttributeIPHostNode,
|
|
10
|
+
GraphAttributeIPNetworkNode,
|
|
11
|
+
GraphAttributeValueIndexedNode,
|
|
12
|
+
GraphAttributeValueNode,
|
|
13
|
+
)
|
|
8
14
|
from infrahub.core.query import Query, QueryNode, QueryRel, QueryType
|
|
9
15
|
from infrahub.core.timestamp import Timestamp
|
|
10
16
|
from infrahub.core.utils import build_regex_attrs
|
|
17
|
+
from infrahub.types import is_large_attribute_type
|
|
11
18
|
|
|
12
19
|
if TYPE_CHECKING:
|
|
13
20
|
from infrahub.core.attribute import BaseAttribute
|
|
@@ -56,12 +63,14 @@ class AttributeUpdateValueQuery(AttributeQuery):
|
|
|
56
63
|
|
|
57
64
|
prop_list = [f"{key}: ${key}" for key in content.keys()]
|
|
58
65
|
|
|
59
|
-
labels = [
|
|
66
|
+
labels = [GraphAttributeValueNode.get_default_label()]
|
|
60
67
|
node_type = self.attr.get_db_node_type()
|
|
61
|
-
if
|
|
62
|
-
labels.append(
|
|
63
|
-
|
|
64
|
-
labels.append(
|
|
68
|
+
if AttributeDBNodeType.INDEXED in node_type:
|
|
69
|
+
labels.append(GraphAttributeValueIndexedNode.get_default_label())
|
|
70
|
+
if AttributeDBNodeType.IPHOST in node_type:
|
|
71
|
+
labels.append(GraphAttributeIPHostNode.get_default_label())
|
|
72
|
+
if AttributeDBNodeType.IPNETWORK in node_type:
|
|
73
|
+
labels.append(GraphAttributeIPNetworkNode.get_default_label())
|
|
65
74
|
|
|
66
75
|
query = """
|
|
67
76
|
MATCH (a:Attribute { uuid: $attr_uuid })
|
|
@@ -198,6 +207,9 @@ async def default_attribute_query_filter(
|
|
|
198
207
|
support_profiles: bool = False,
|
|
199
208
|
) -> tuple[list[QueryElement], dict[str, Any], list[str]]:
|
|
200
209
|
"""Generate Query String Snippet to filter the right node."""
|
|
210
|
+
attribute_value_label = GraphAttributeValueNode.get_default_label()
|
|
211
|
+
if attribute_kind and not is_large_attribute_type(attribute_kind):
|
|
212
|
+
attribute_value_label = GraphAttributeValueIndexedNode.get_default_label()
|
|
201
213
|
|
|
202
214
|
query_filter: list[QueryElement] = []
|
|
203
215
|
query_params: dict[str, Any] = {}
|
|
@@ -226,33 +238,35 @@ async def default_attribute_query_filter(
|
|
|
226
238
|
query_filter.append(QueryRel(labels=[RELATIONSHIP_TO_VALUE_LABEL]))
|
|
227
239
|
|
|
228
240
|
if filter_value is None:
|
|
229
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
241
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
230
242
|
else:
|
|
231
243
|
if partial_match:
|
|
232
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
244
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
233
245
|
query_where.append(
|
|
234
246
|
f"toLower(toString(av.{filter_name})) CONTAINS toLower(toString(${param_prefix}_{filter_name}))"
|
|
235
247
|
)
|
|
236
248
|
elif attribute_kind and attribute_kind == "List" and not isinstance(filter_value, list):
|
|
237
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
249
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
238
250
|
filter_value = build_regex_attrs(values=[filter_value])
|
|
239
251
|
query_where.append(f"toString(av.{filter_name}) =~ ${param_prefix}_{filter_name}")
|
|
240
252
|
elif filter_name == "isnull":
|
|
241
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
253
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
242
254
|
elif support_profiles:
|
|
243
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
255
|
+
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
244
256
|
query_where.append(f"(av.{filter_name} = ${param_prefix}_{filter_name} OR av.is_default)")
|
|
245
257
|
else:
|
|
246
258
|
query_filter.append(
|
|
247
259
|
QueryNode(
|
|
248
|
-
name="av",
|
|
260
|
+
name="av",
|
|
261
|
+
labels=[attribute_value_label],
|
|
262
|
+
params={filter_name: f"${param_prefix}_{filter_name}"},
|
|
249
263
|
)
|
|
250
264
|
)
|
|
251
265
|
query_params[f"{param_prefix}_{filter_name}"] = filter_value
|
|
252
266
|
|
|
253
267
|
elif filter_name == "values" and isinstance(filter_value, list):
|
|
254
268
|
query_filter.extend(
|
|
255
|
-
(QueryRel(labels=[RELATIONSHIP_TO_VALUE_LABEL]), QueryNode(name="av", labels=[
|
|
269
|
+
(QueryRel(labels=[RELATIONSHIP_TO_VALUE_LABEL]), QueryNode(name="av", labels=[attribute_value_label]))
|
|
256
270
|
)
|
|
257
271
|
if attribute_kind and attribute_kind == "List":
|
|
258
272
|
query_params[f"{param_prefix}_{filter_name}"] = build_regex_attrs(values=filter_value)
|
|
@@ -267,10 +281,14 @@ async def default_attribute_query_filter(
|
|
|
267
281
|
query_filter.append(QueryRel(labels=[RELATIONSHIP_TO_VALUE_LABEL]))
|
|
268
282
|
|
|
269
283
|
if filter_value is None:
|
|
270
|
-
query_filter.append(QueryNode(name="av", labels=[
|
|
284
|
+
query_filter.append(QueryNode(name="av", labels=[GraphAttributeValueNode.get_default_label()]))
|
|
271
285
|
else:
|
|
272
286
|
query_filter.append(
|
|
273
|
-
QueryNode(
|
|
287
|
+
QueryNode(
|
|
288
|
+
name="av",
|
|
289
|
+
labels=[GraphAttributeValueNode.get_default_label()],
|
|
290
|
+
params={filter_name: f"${param_prefix}_{filter_name}"},
|
|
291
|
+
)
|
|
274
292
|
)
|
|
275
293
|
query_params[f"{param_prefix}_{filter_name}"] = filter_value
|
|
276
294
|
|
infrahub/core/query/diff.py
CHANGED
|
@@ -100,6 +100,17 @@ class DiffCountChanges(Query):
|
|
|
100
100
|
return branch_count_map
|
|
101
101
|
|
|
102
102
|
|
|
103
|
+
async def get_num_changes_in_time_range_by_branch(
|
|
104
|
+
branch_names: list[str],
|
|
105
|
+
from_time: Timestamp,
|
|
106
|
+
to_time: Timestamp,
|
|
107
|
+
db: InfrahubDatabase,
|
|
108
|
+
) -> dict[str, int]:
|
|
109
|
+
query = await DiffCountChanges.init(db=db, branch_names=branch_names, diff_from=from_time, diff_to=to_time)
|
|
110
|
+
await query.execute(db=db)
|
|
111
|
+
return query.get_num_changes_by_branch()
|
|
112
|
+
|
|
113
|
+
|
|
103
114
|
class DiffCalculationQuery(DiffQuery):
|
|
104
115
|
type = QueryType.READ
|
|
105
116
|
insert_limit = False
|
infrahub/core/query/ipam.py
CHANGED
|
@@ -5,6 +5,7 @@ from dataclasses import dataclass
|
|
|
5
5
|
from typing import TYPE_CHECKING, Iterable
|
|
6
6
|
|
|
7
7
|
from infrahub.core.constants import InfrahubKind
|
|
8
|
+
from infrahub.core.graph.schema import GraphAttributeIPHostNode, GraphAttributeIPNetworkNode
|
|
8
9
|
from infrahub.core.ipam.constants import AllIPTypes, IPAddressType, IPNetworkType
|
|
9
10
|
from infrahub.core.query import QueryType
|
|
10
11
|
from infrahub.core.registry import registry
|
|
@@ -21,8 +22,8 @@ if TYPE_CHECKING:
|
|
|
21
22
|
from infrahub.database import InfrahubDatabase
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
PREFIX_ATTRIBUTE_LABEL =
|
|
25
|
-
ADDRESS_ATTRIBUTE_LABEL =
|
|
25
|
+
PREFIX_ATTRIBUTE_LABEL = GraphAttributeIPNetworkNode.get_default_label()
|
|
26
|
+
ADDRESS_ATTRIBUTE_LABEL = GraphAttributeIPHostNode.get_default_label()
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
@dataclass
|
|
@@ -280,14 +281,13 @@ class IPPrefixUtilization(Query):
|
|
|
280
281
|
MATCH path = (
|
|
281
282
|
(pfx)-[r_1:IS_RELATED]-(rl:Relationship)-[r_2:IS_RELATED]-(child:Node)
|
|
282
283
|
-[r_attr:HAS_ATTRIBUTE]->(attr:Attribute)
|
|
283
|
-
-[r_attr_val:HAS_VALUE]->(av:
|
|
284
|
+
-[r_attr_val:HAS_VALUE]->(av:{PREFIX_ATTRIBUTE_LABEL}|{ADDRESS_ATTRIBUTE_LABEL})
|
|
284
285
|
)
|
|
285
286
|
WHERE %(id_func)s(r_1) = %(id_func)s(r_rel1)
|
|
286
287
|
AND %(id_func)s(r_2) = %(id_func)s(r_rel2)
|
|
287
288
|
AND ({rel_filter("r_attr")})
|
|
288
289
|
AND ({rel_filter("r_attr_val")})
|
|
289
290
|
AND attr.name IN ["prefix", "address"]
|
|
290
|
-
AND any(l in labels(av) WHERE l in ["{PREFIX_ATTRIBUTE_LABEL}", "{ADDRESS_ATTRIBUTE_LABEL}"])
|
|
291
291
|
WITH
|
|
292
292
|
path,
|
|
293
293
|
pfx,
|
|
@@ -478,6 +478,7 @@ class IPPrefixReconcileQuery(Query):
|
|
|
478
478
|
-[pr2:IS_RELATED {status: "active"}]-(maybe_new_parent:%(ip_prefix_kind)s)
|
|
479
479
|
-[har:HAS_ATTRIBUTE]->(:Attribute {name: "prefix"})
|
|
480
480
|
-[hvr:HAS_VALUE]->(av:%(ip_prefix_attribute_kind)s)
|
|
481
|
+
USING INDEX av:%(ip_prefix_attribute_kind)s(binary_address)
|
|
481
482
|
WHERE all(r IN relationships(parent_path) WHERE (%(branch_filter)s))
|
|
482
483
|
AND av.version = $ip_version
|
|
483
484
|
AND av.binary_address IN $possible_prefix_list
|
|
@@ -514,15 +515,16 @@ class IPPrefixReconcileQuery(Query):
|
|
|
514
515
|
OPTIONAL MATCH child_path = (
|
|
515
516
|
(ip_namespace)-[r1:IS_RELATED]
|
|
516
517
|
-(ns_rel:Relationship)-[r2:IS_RELATED]
|
|
517
|
-
-(maybe_new_child
|
|
518
|
+
-(maybe_new_child:%(ip_prefix_kind)s|%(ip_address_kind)s)-[har:HAS_ATTRIBUTE]
|
|
518
519
|
->(a:Attribute)-[hvr:HAS_VALUE]
|
|
519
|
-
->(av
|
|
520
|
+
->(av:%(ip_prefix_attribute_kind)s|%(ip_address_attribute_kind)s)
|
|
520
521
|
)
|
|
522
|
+
USING INDEX av:%(ip_prefix_attribute_kind)s(binary_address)
|
|
523
|
+
USING INDEX av:%(ip_address_attribute_kind)s(binary_address)
|
|
521
524
|
WHERE $is_prefix // only prefix nodes can have children
|
|
522
525
|
AND ns_rel.name IN ["ip_namespace__ip_prefix", "ip_namespace__ip_address"]
|
|
523
526
|
AND any(child_kind IN [$ip_prefix_kind, $ip_address_kind] WHERE child_kind IN labels(maybe_new_child))
|
|
524
527
|
AND a.name in ["prefix", "address"]
|
|
525
|
-
AND any(attr_kind IN [$ip_prefix_attribute_kind, $ip_address_attribute_kind] WHERE attr_kind IN labels(av))
|
|
526
528
|
AND (ip_node IS NULL OR maybe_new_child.uuid <> ip_node.uuid)
|
|
527
529
|
AND (
|
|
528
530
|
($ip_prefix_kind IN labels(maybe_new_child) AND av.prefixlen > $prefixlen)
|
|
@@ -580,6 +582,10 @@ class IPPrefixReconcileQuery(Query):
|
|
|
580
582
|
collect(new_child) as new_children
|
|
581
583
|
""" % {
|
|
582
584
|
"branch_filter": branch_filter,
|
|
585
|
+
"ip_prefix_kind": InfrahubKind.IPPREFIX,
|
|
586
|
+
"ip_address_kind": InfrahubKind.IPADDRESS,
|
|
587
|
+
"ip_prefix_attribute_kind": PREFIX_ATTRIBUTE_LABEL,
|
|
588
|
+
"ip_address_attribute_kind": ADDRESS_ATTRIBUTE_LABEL,
|
|
583
589
|
}
|
|
584
590
|
self.add_to_query(get_new_children_query)
|
|
585
591
|
self.return_labels = ["ip_node", "current_parent", "current_children", "new_parent", "new_children"]
|
infrahub/core/query/node.py
CHANGED
|
@@ -140,15 +140,19 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
140
140
|
attributes: list[AttributeCreateData] = []
|
|
141
141
|
attributes_iphost: list[AttributeCreateData] = []
|
|
142
142
|
attributes_ipnetwork: list[AttributeCreateData] = []
|
|
143
|
+
attributes_indexed: list[AttributeCreateData] = []
|
|
143
144
|
|
|
144
145
|
for attr_name in self.node._attributes:
|
|
145
146
|
attr: BaseAttribute = getattr(self.node, attr_name)
|
|
146
147
|
attr_data = attr.get_create_data()
|
|
148
|
+
node_type = attr.get_db_node_type()
|
|
147
149
|
|
|
148
|
-
if
|
|
150
|
+
if AttributeDBNodeType.IPHOST in node_type:
|
|
149
151
|
attributes_iphost.append(attr_data)
|
|
150
|
-
elif
|
|
152
|
+
elif AttributeDBNodeType.IPNETWORK in node_type:
|
|
151
153
|
attributes_ipnetwork.append(attr_data)
|
|
154
|
+
elif AttributeDBNodeType.INDEXED in node_type:
|
|
155
|
+
attributes_indexed.append(attr_data)
|
|
152
156
|
else:
|
|
153
157
|
attributes.append(attr_data)
|
|
154
158
|
|
|
@@ -157,20 +161,7 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
157
161
|
relationships: list[RelationshipCreateData] = []
|
|
158
162
|
for rel_name in self.node._relationships:
|
|
159
163
|
rel_manager: RelationshipManager = getattr(self.node, rel_name)
|
|
160
|
-
# Fetch all relationship peers through a single database call for performances.
|
|
161
|
-
peers = await rel_manager.get_peers(db=db, branch_agnostic=self.branch_agnostic)
|
|
162
|
-
|
|
163
164
|
for rel in rel_manager._relationships:
|
|
164
|
-
try:
|
|
165
|
-
rel.set_peer(value=peers[rel.get_peer_id()])
|
|
166
|
-
except KeyError:
|
|
167
|
-
pass
|
|
168
|
-
except ValueError:
|
|
169
|
-
# Relationship has not been initialized yet, it means the peer does not exist in db yet
|
|
170
|
-
# typically because it will be allocated from a ressource pool. In that case, the peer
|
|
171
|
-
# will be fetched using `rel.resolve` later.
|
|
172
|
-
pass
|
|
173
|
-
|
|
174
165
|
rel_create_data = await rel.get_create_data(db=db, at=at)
|
|
175
166
|
if rel_create_data.peer_branch_level > deepest_branch_level or (
|
|
176
167
|
deepest_branch_name == GLOBAL_BRANCH_NAME and rel_create_data.peer_branch == registry.default_branch
|
|
@@ -180,6 +171,7 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
180
171
|
relationships.append(rel_create_data)
|
|
181
172
|
|
|
182
173
|
self.params["attrs"] = [attr.model_dump() for attr in attributes]
|
|
174
|
+
self.params["attrs_indexed"] = [attr.model_dump() for attr in attributes_indexed]
|
|
183
175
|
self.params["attrs_iphost"] = [attr.model_dump() for attr in attributes_iphost]
|
|
184
176
|
self.params["attrs_ipnetwork"] = [attr.model_dump() for attr in attributes_ipnetwork]
|
|
185
177
|
self.params["rels_bidir"] = [
|
|
@@ -222,24 +214,59 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
222
214
|
"binary_address": "attr.content.binary_address",
|
|
223
215
|
"version": "attr.content.version",
|
|
224
216
|
"prefixlen": "attr.content.prefixlen",
|
|
225
|
-
# "num_addresses": "attr.content.num_addresses",
|
|
226
217
|
}
|
|
227
218
|
ipnetwork_prop_list = [f"{key}: {value}" for key, value in ipnetwork_prop.items()]
|
|
228
219
|
|
|
229
|
-
|
|
220
|
+
attrs_nonindexed_query = """
|
|
230
221
|
WITH distinct n
|
|
231
222
|
UNWIND $attrs AS attr
|
|
223
|
+
// Try to find a matching vertex
|
|
224
|
+
OPTIONAL MATCH (existing_av:AttributeValue {value: attr.content.value, is_default: attr.content.is_default})
|
|
225
|
+
WHERE NOT existing_av:AttributeValueIndexed
|
|
226
|
+
CALL (attr, existing_av) {
|
|
227
|
+
// If none found, create a new one
|
|
228
|
+
WITH existing_av
|
|
229
|
+
WHERE existing_av IS NULL
|
|
230
|
+
CREATE (:AttributeValue {value: attr.content.value, is_default: attr.content.is_default})
|
|
231
|
+
}
|
|
232
|
+
CALL (attr) {
|
|
233
|
+
MATCH (av:AttributeValue {value: attr.content.value, is_default: attr.content.is_default})
|
|
234
|
+
WHERE NOT av:AttributeValueIndexed
|
|
235
|
+
RETURN av
|
|
236
|
+
LIMIT 1
|
|
237
|
+
}
|
|
238
|
+
CALL (n, attr, av) {
|
|
239
|
+
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
240
|
+
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
241
|
+
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
242
|
+
MERGE (ip:Boolean { value: attr.is_protected })
|
|
243
|
+
MERGE (iv:Boolean { value: attr.is_visible })
|
|
244
|
+
WITH a, ip, iv
|
|
245
|
+
LIMIT 1
|
|
246
|
+
CREATE (a)-[:IS_PROTECTED { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(ip)
|
|
247
|
+
CREATE (a)-[:IS_VISIBLE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(iv)
|
|
248
|
+
FOREACH ( prop IN attr.source_prop |
|
|
249
|
+
MERGE (peer:Node { uuid: prop.peer_id })
|
|
250
|
+
CREATE (a)-[:HAS_SOURCE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
|
|
251
|
+
)
|
|
252
|
+
FOREACH ( prop IN attr.owner_prop |
|
|
253
|
+
MERGE (peer:Node { uuid: prop.peer_id })
|
|
254
|
+
CREATE (a)-[:HAS_OWNER { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
|
|
255
|
+
)
|
|
256
|
+
}"""
|
|
257
|
+
|
|
258
|
+
attrs_indexed_query = """
|
|
259
|
+
WITH distinct n
|
|
260
|
+
UNWIND $attrs_indexed AS attr
|
|
232
261
|
CALL (n, attr) {
|
|
233
262
|
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
234
263
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
235
|
-
MERGE (av:AttributeValue { value: attr.content.value, is_default: attr.content.is_default })
|
|
264
|
+
MERGE (av:AttributeValue:AttributeValueIndexed { value: attr.content.value, is_default: attr.content.is_default })
|
|
236
265
|
WITH av, a
|
|
237
266
|
LIMIT 1
|
|
238
267
|
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
239
268
|
MERGE (ip:Boolean { value: attr.is_protected })
|
|
240
269
|
MERGE (iv:Boolean { value: attr.is_visible })
|
|
241
|
-
WITH a, ip, iv
|
|
242
|
-
LIMIT 1
|
|
243
270
|
CREATE (a)-[:IS_PROTECTED { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(ip)
|
|
244
271
|
CREATE (a)-[:IS_VISIBLE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(iv)
|
|
245
272
|
FOREACH ( prop IN attr.source_prop |
|
|
@@ -258,7 +285,7 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
258
285
|
CALL (n, attr) {
|
|
259
286
|
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
260
287
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
261
|
-
MERGE (av:AttributeValue:AttributeIPHost { %(iphost_prop)s })
|
|
288
|
+
MERGE (av:AttributeValue:AttributeValueIndexed:AttributeIPHost { %(iphost_prop)s })
|
|
262
289
|
WITH attr, av, a
|
|
263
290
|
LIMIT 1
|
|
264
291
|
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
@@ -285,7 +312,7 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
285
312
|
CALL (n, attr) {
|
|
286
313
|
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
287
314
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
288
|
-
MERGE (av:AttributeValue:AttributeIPNetwork { %(ipnetwork_prop)s })
|
|
315
|
+
MERGE (av:AttributeValue:AttributeValueIndexed:AttributeIPNetwork { %(ipnetwork_prop)s })
|
|
289
316
|
WITH attr, av, a
|
|
290
317
|
LIMIT 1
|
|
291
318
|
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
@@ -422,7 +449,8 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
422
449
|
MATCH (root:Root)
|
|
423
450
|
CREATE (n:Node:%(labels)s $node_prop )
|
|
424
451
|
CREATE (n)-[r:IS_PART_OF $node_branch_prop ]->(root)
|
|
425
|
-
{
|
|
452
|
+
{attrs_nonindexed_query if self.params["attrs"] else ""}
|
|
453
|
+
{attrs_indexed_query if self.params["attrs_indexed"] else ""}
|
|
426
454
|
{attrs_iphost_query if self.params["attrs_iphost"] else ""}
|
|
427
455
|
{attrs_ipnetwork_query if self.params["attrs_ipnetwork"] else ""}
|
|
428
456
|
{rels_bidir_query if self.params["rels_bidir"] else ""}
|
|
@@ -140,7 +140,7 @@ class NumberPoolGetAllocated(Query):
|
|
|
140
140
|
self.params.update(branch_params)
|
|
141
141
|
|
|
142
142
|
query = """
|
|
143
|
-
MATCH (n:%(node)s)-[ha:HAS_ATTRIBUTE]-(a:Attribute {name: $node_attribute})-[hv:HAS_VALUE]-(av:
|
|
143
|
+
MATCH (n:%(node)s)-[ha:HAS_ATTRIBUTE]-(a:Attribute {name: $node_attribute})-[hv:HAS_VALUE]-(av:AttributeValueIndexed)
|
|
144
144
|
MATCH (a)-[hs:HAS_SOURCE]-(pool:%(number_pool_kind)s)
|
|
145
145
|
WHERE
|
|
146
146
|
pool.uuid = $pool_id
|
|
@@ -306,7 +306,7 @@ class NumberPoolGetUsed(Query):
|
|
|
306
306
|
self.params["attribute_name"] = self.pool.node_attribute.value
|
|
307
307
|
|
|
308
308
|
query = """
|
|
309
|
-
MATCH (pool:%(number_pool)s { uuid: $pool_id })-[res:IS_RESERVED]->(av:
|
|
309
|
+
MATCH (pool:%(number_pool)s { uuid: $pool_id })-[res:IS_RESERVED]->(av:AttributeValueIndexed)
|
|
310
310
|
WHERE toInteger(av.value) >= $start_range and toInteger(av.value) <= $end_range
|
|
311
311
|
CALL (pool, res, av) {
|
|
312
312
|
MATCH (pool)-[res]->(av)<-[hv:HAS_VALUE]-(attr:Attribute)<-[ha:HAS_ATTRIBUTE]-(n:%(node)s)
|
|
@@ -371,7 +371,7 @@ class NumberPoolSetReserved(Query):
|
|
|
371
371
|
|
|
372
372
|
query = """
|
|
373
373
|
MATCH (pool:%(number_pool)s { uuid: $pool_id })
|
|
374
|
-
MERGE (value:AttributeValue { value: $reserved, is_default: false })
|
|
374
|
+
MERGE (value:AttributeValue:AttributeValueIndexed { value: $reserved, is_default: false })
|
|
375
375
|
WITH value, pool
|
|
376
376
|
LIMIT 1
|
|
377
377
|
CREATE (pool)-[rel:IS_RESERVED $rel_prop]->(value)
|
|
@@ -166,11 +166,11 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
|
|
|
166
166
|
return registry.get_global_branch()
|
|
167
167
|
return self.branch
|
|
168
168
|
|
|
169
|
-
def _process_data(self, data: dict | RelationshipPeerData | str) -> None:
|
|
169
|
+
async def _process_data(self, data: dict | RelationshipPeerData | str) -> None:
|
|
170
170
|
self.data = data
|
|
171
171
|
|
|
172
172
|
if isinstance(data, RelationshipPeerData):
|
|
173
|
-
self.set_peer(value=str(data.peer_id))
|
|
173
|
+
await self.set_peer(value=str(data.peer_id))
|
|
174
174
|
|
|
175
175
|
if not self.id and data.rel_node_id:
|
|
176
176
|
self.id = data.rel_node_id
|
|
@@ -187,7 +187,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
|
|
|
187
187
|
elif isinstance(data, dict):
|
|
188
188
|
for key, value in data.items():
|
|
189
189
|
if key in ["peer", "id"]:
|
|
190
|
-
self.set_peer(value=data.get(key, None))
|
|
190
|
+
await self.set_peer(value=data.get(key, None))
|
|
191
191
|
elif key == "hfid" and self.peer_id is None:
|
|
192
192
|
self.peer_hfid = value
|
|
193
193
|
elif key.startswith(PREFIX_PROPERTY) and key.replace(PREFIX_PROPERTY, "") in self._flag_properties:
|
|
@@ -198,7 +198,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
|
|
|
198
198
|
self.from_pool = value
|
|
199
199
|
|
|
200
200
|
else:
|
|
201
|
-
self.set_peer(value=data)
|
|
201
|
+
await self.set_peer(value=data)
|
|
202
202
|
|
|
203
203
|
async def new(
|
|
204
204
|
self,
|
|
@@ -206,11 +206,11 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
|
|
|
206
206
|
data: dict | RelationshipPeerData | Any = None,
|
|
207
207
|
**kwargs: Any, # noqa: ARG002
|
|
208
208
|
) -> Relationship:
|
|
209
|
-
self._process_data(data=data)
|
|
209
|
+
await self._process_data(data=data)
|
|
210
210
|
|
|
211
211
|
return self
|
|
212
212
|
|
|
213
|
-
def load(
|
|
213
|
+
async def load(
|
|
214
214
|
self,
|
|
215
215
|
db: InfrahubDatabase, # noqa: ARG002
|
|
216
216
|
id: UUID | None = None,
|
|
@@ -223,7 +223,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
|
|
|
223
223
|
self.id = id or self.id
|
|
224
224
|
self.db_id = db_id or self.db_id
|
|
225
225
|
|
|
226
|
-
self._process_data(data=data)
|
|
226
|
+
await self._process_data(data=data)
|
|
227
227
|
|
|
228
228
|
if updated_at and hash(self) != hash_before:
|
|
229
229
|
self.updated_at = Timestamp(updated_at)
|
|
@@ -252,7 +252,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
|
|
|
252
252
|
self._node_id = self._node.id
|
|
253
253
|
return node
|
|
254
254
|
|
|
255
|
-
def set_peer(self, value: str | Node) -> None:
|
|
255
|
+
async def set_peer(self, value: str | Node) -> None:
|
|
256
256
|
if isinstance(value, str):
|
|
257
257
|
self.peer_id = value
|
|
258
258
|
else:
|
|
@@ -433,7 +433,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
|
|
|
433
433
|
db=db, id=self.peer_id, branch=self.branch, kind=self.schema.peer, fields={"display_label": None}
|
|
434
434
|
)
|
|
435
435
|
if peer:
|
|
436
|
-
self.set_peer(value=peer)
|
|
436
|
+
await self.set_peer(value=peer)
|
|
437
437
|
|
|
438
438
|
if not self.peer_id and self.peer_hfid:
|
|
439
439
|
peer_schema = db.schema.get(name=self.schema.peer, branch=self.branch)
|
|
@@ -450,7 +450,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
|
|
|
450
450
|
fields={"display_label": None},
|
|
451
451
|
raise_on_error=True,
|
|
452
452
|
)
|
|
453
|
-
self.set_peer(value=peer)
|
|
453
|
+
await self.set_peer(value=peer)
|
|
454
454
|
|
|
455
455
|
if not self.peer_id and self.from_pool and "id" in self.from_pool:
|
|
456
456
|
pool_id = str(self.from_pool.get("id"))
|
|
@@ -473,7 +473,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
|
|
|
473
473
|
data_from_pool["identifier"] = f"hfid={hfid_str} rel={self.name}"
|
|
474
474
|
|
|
475
475
|
assigned_peer: Node = await pool.get_resource(db=db, branch=self.branch, at=at, **data_from_pool) # type: ignore[attr-defined]
|
|
476
|
-
self.set_peer(value=assigned_peer)
|
|
476
|
+
await self.set_peer(value=assigned_peer)
|
|
477
477
|
self.set_source(value=pool.id)
|
|
478
478
|
|
|
479
479
|
async def save(self, db: InfrahubDatabase, at: Timestamp | None = None) -> Self:
|
|
@@ -962,7 +962,7 @@ class RelationshipManager:
|
|
|
962
962
|
|
|
963
963
|
for peer_id in details.peer_ids_present_database_only:
|
|
964
964
|
self._relationships.append(
|
|
965
|
-
Relationship(
|
|
965
|
+
await Relationship(
|
|
966
966
|
schema=self.schema,
|
|
967
967
|
branch=self.branch,
|
|
968
968
|
at=at or self.at,
|
|
@@ -1050,7 +1050,7 @@ class RelationshipManager:
|
|
|
1050
1050
|
if isinstance(item, dict) and item.get("id", None) in previous_relationships:
|
|
1051
1051
|
rel = previous_relationships[item["id"]]
|
|
1052
1052
|
hash_before = hash(rel)
|
|
1053
|
-
rel.load(data=item, db=db)
|
|
1053
|
+
await rel.load(data=item, db=db)
|
|
1054
1054
|
if hash(rel) != hash_before:
|
|
1055
1055
|
changed = True
|
|
1056
1056
|
self._relationships.append(rel)
|
|
@@ -55,6 +55,14 @@ class BaseNodeSchema(GeneratedBaseNodeSchema):
|
|
|
55
55
|
def is_profile_schema(self) -> bool:
|
|
56
56
|
return False
|
|
57
57
|
|
|
58
|
+
@property
|
|
59
|
+
def is_ip_prefix(self) -> bool:
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def is_ip_address(self) -> bool:
|
|
64
|
+
return False
|
|
65
|
+
|
|
58
66
|
@property
|
|
59
67
|
def kind(self) -> str:
|
|
60
68
|
if self.namespace == "Attribute":
|
|
@@ -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
|
|