infrahub-server 1.2.9rc0__py3-none-any.whl → 1.3.0a0__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 +86 -0
- infrahub/actions/gather.py +114 -0
- infrahub/actions/models.py +241 -0
- infrahub/actions/parsers.py +104 -0
- infrahub/actions/schema.py +382 -0
- infrahub/actions/tasks.py +126 -0
- infrahub/actions/triggers.py +21 -0
- infrahub/cli/db.py +1 -2
- infrahub/computed_attribute/models.py +13 -0
- infrahub/computed_attribute/tasks.py +48 -26
- infrahub/config.py +9 -0
- infrahub/core/account.py +24 -47
- infrahub/core/attribute.py +53 -14
- infrahub/core/branch/models.py +8 -9
- infrahub/core/branch/tasks.py +0 -2
- infrahub/core/constants/infrahubkind.py +8 -0
- infrahub/core/constraint/node/runner.py +1 -1
- infrahub/core/convert_object_type/__init__.py +0 -0
- infrahub/core/convert_object_type/conversion.py +122 -0
- infrahub/core/convert_object_type/schema_mapping.py +56 -0
- infrahub/core/diff/calculator.py +65 -11
- infrahub/core/diff/combiner.py +38 -31
- infrahub/core/diff/coordinator.py +44 -28
- infrahub/core/diff/data_check_synchronizer.py +3 -2
- infrahub/core/diff/enricher/hierarchy.py +36 -27
- infrahub/core/diff/ipam_diff_parser.py +5 -4
- infrahub/core/diff/merger/merger.py +46 -16
- infrahub/core/diff/merger/serializer.py +1 -0
- infrahub/core/diff/model/field_specifiers_map.py +64 -0
- infrahub/core/diff/model/path.py +58 -58
- infrahub/core/diff/parent_node_adder.py +14 -16
- infrahub/core/diff/query/all_conflicts.py +1 -5
- infrahub/core/diff/query/artifact.py +10 -20
- infrahub/core/diff/query/diff_get.py +3 -6
- infrahub/core/diff/query/drop_nodes.py +42 -0
- infrahub/core/diff/query/field_specifiers.py +8 -7
- infrahub/core/diff/query/field_summary.py +2 -4
- infrahub/core/diff/query/filters.py +15 -1
- infrahub/core/diff/query/merge.py +284 -101
- infrahub/core/diff/query/save.py +26 -34
- infrahub/core/diff/query/summary_counts_enricher.py +34 -54
- infrahub/core/diff/query_parser.py +55 -65
- infrahub/core/diff/repository/deserializer.py +38 -24
- infrahub/core/diff/repository/repository.py +31 -12
- infrahub/core/diff/tasks.py +3 -3
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/manager.py +14 -11
- infrahub/core/migrations/graph/__init__.py +2 -0
- infrahub/core/migrations/graph/m003_relationship_parent_optional.py +1 -2
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +2 -4
- 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/m024_missing_hierarchy_backfill.py +1 -2
- infrahub/core/migrations/graph/m027_delete_isolated_nodes.py +50 -0
- infrahub/core/migrations/graph/m028_delete_diffs.py +38 -0
- infrahub/core/migrations/query/attribute_add.py +1 -2
- infrahub/core/migrations/query/attribute_rename.py +3 -6
- infrahub/core/migrations/query/delete_element_in_schema.py +3 -6
- infrahub/core/migrations/query/node_duplicate.py +3 -6
- infrahub/core/migrations/query/relationship_duplicate.py +3 -6
- infrahub/core/migrations/schema/node_attribute_remove.py +3 -6
- infrahub/core/migrations/schema/node_remove.py +3 -6
- infrahub/core/models.py +29 -2
- infrahub/core/node/__init__.py +18 -4
- infrahub/core/node/create.py +211 -0
- infrahub/core/protocols.py +51 -0
- infrahub/core/protocols_base.py +3 -0
- infrahub/core/query/__init__.py +2 -2
- infrahub/core/query/branch.py +27 -17
- infrahub/core/query/diff.py +186 -81
- infrahub/core/query/ipam.py +10 -20
- infrahub/core/query/node.py +65 -49
- infrahub/core/query/relationship.py +156 -58
- infrahub/core/query/resource_manager.py +1 -2
- infrahub/core/query/subquery.py +4 -6
- infrahub/core/relationship/model.py +4 -1
- infrahub/core/schema/__init__.py +2 -1
- infrahub/core/schema/attribute_parameters.py +36 -0
- infrahub/core/schema/attribute_schema.py +83 -8
- infrahub/core/schema/basenode_schema.py +25 -1
- infrahub/core/schema/definitions/core/__init__.py +21 -0
- infrahub/core/schema/definitions/internal.py +13 -3
- infrahub/core/schema/generated/attribute_schema.py +9 -3
- infrahub/core/schema/schema_branch.py +15 -7
- infrahub/core/validators/__init__.py +5 -1
- infrahub/core/validators/attribute/choices.py +1 -2
- infrahub/core/validators/attribute/enum.py +1 -2
- infrahub/core/validators/attribute/kind.py +1 -2
- infrahub/core/validators/attribute/length.py +13 -6
- infrahub/core/validators/attribute/optional.py +1 -2
- infrahub/core/validators/attribute/regex.py +5 -5
- infrahub/core/validators/attribute/unique.py +1 -3
- infrahub/core/validators/determiner.py +18 -2
- infrahub/core/validators/enum.py +7 -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 +3 -8
- infrahub/core/validators/tasks.py +1 -1
- infrahub/core/validators/uniqueness/query.py +12 -9
- infrahub/database/__init__.py +1 -3
- infrahub/events/group_action.py +1 -0
- infrahub/graphql/analyzer.py +139 -18
- infrahub/graphql/app.py +1 -1
- infrahub/graphql/loaders/node.py +1 -1
- infrahub/graphql/loaders/peers.py +1 -1
- infrahub/graphql/manager.py +4 -0
- infrahub/graphql/mutations/action.py +164 -0
- infrahub/graphql/mutations/convert_object_type.py +62 -0
- infrahub/graphql/mutations/main.py +24 -175
- infrahub/graphql/mutations/proposed_change.py +21 -18
- infrahub/graphql/queries/convert_object_type_mapping.py +36 -0
- infrahub/graphql/queries/diff/tree.py +2 -1
- infrahub/graphql/queries/relationship.py +1 -1
- infrahub/graphql/resolvers/many_relationship.py +4 -4
- infrahub/graphql/resolvers/resolver.py +4 -4
- infrahub/graphql/resolvers/single_relationship.py +2 -2
- infrahub/graphql/schema.py +6 -0
- infrahub/graphql/subscription/graphql_query.py +2 -2
- infrahub/graphql/types/branch.py +1 -1
- infrahub/menu/menu.py +31 -0
- infrahub/message_bus/messages/__init__.py +0 -10
- infrahub/message_bus/operations/__init__.py +0 -8
- infrahub/message_bus/operations/refresh/registry.py +1 -1
- infrahub/patch/queries/consolidate_duplicated_nodes.py +3 -6
- infrahub/patch/queries/delete_duplicated_edges.py +5 -10
- infrahub/prefect_server/models.py +1 -19
- infrahub/proposed_change/models.py +68 -3
- infrahub/proposed_change/tasks.py +907 -30
- infrahub/task_manager/models.py +10 -6
- infrahub/telemetry/database.py +1 -1
- infrahub/telemetry/tasks.py +1 -1
- infrahub/trigger/catalogue.py +2 -0
- infrahub/trigger/models.py +29 -3
- infrahub/trigger/setup.py +51 -15
- infrahub/trigger/tasks.py +4 -5
- infrahub/types.py +1 -1
- infrahub/webhook/models.py +2 -1
- infrahub/workflows/catalogue.py +85 -0
- infrahub/workflows/initialization.py +1 -3
- infrahub_sdk/timestamp.py +2 -2
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/METADATA +4 -4
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/RECORD +153 -146
- infrahub_testcontainers/container.py +0 -1
- infrahub_testcontainers/docker-compose.test.yml +4 -4
- infrahub_testcontainers/helpers.py +8 -2
- infrahub_testcontainers/performance_test.py +6 -3
- 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/{message_bus/messages/proposed_change → actions}/__init__.py +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/entry_points.txt +0 -0
|
@@ -14,7 +14,7 @@ from infrahub.core.registry import registry
|
|
|
14
14
|
from infrahub.events import BranchDeletedEvent
|
|
15
15
|
from infrahub.git.repository import get_initialized_repo
|
|
16
16
|
from infrahub.services import InfrahubServices # noqa: TC001 needed for prefect flow
|
|
17
|
-
from infrahub.trigger.models import TriggerType
|
|
17
|
+
from infrahub.trigger.models import TriggerSetupReport, TriggerType
|
|
18
18
|
from infrahub.trigger.setup import setup_triggers
|
|
19
19
|
from infrahub.workflows.catalogue import (
|
|
20
20
|
COMPUTED_ATTRIBUTE_PROCESS_JINJA2,
|
|
@@ -25,7 +25,11 @@ from infrahub.workflows.catalogue import (
|
|
|
25
25
|
from infrahub.workflows.utils import add_tags, wait_for_schema_to_converge
|
|
26
26
|
|
|
27
27
|
from .gather import gather_trigger_computed_attribute_jinja2, gather_trigger_computed_attribute_python
|
|
28
|
-
from .models import
|
|
28
|
+
from .models import (
|
|
29
|
+
ComputedAttrJinja2GraphQL,
|
|
30
|
+
ComputedAttrJinja2GraphQLResponse,
|
|
31
|
+
PythonTransformTarget,
|
|
32
|
+
)
|
|
29
33
|
|
|
30
34
|
if TYPE_CHECKING:
|
|
31
35
|
from infrahub.core.schema.computed_attribute import ComputedAttribute
|
|
@@ -159,10 +163,10 @@ async def trigger_update_python_computed_attributes(
|
|
|
159
163
|
|
|
160
164
|
|
|
161
165
|
@flow(
|
|
162
|
-
name="
|
|
163
|
-
flow_run_name="Update value for computed attribute {attribute_name}",
|
|
166
|
+
name="computed-attribute-jinja2-update-value",
|
|
167
|
+
flow_run_name="Update value for computed attribute {node_kind}:{attribute_name}",
|
|
164
168
|
)
|
|
165
|
-
async def
|
|
169
|
+
async def computed_attribute_jinja2_update_value(
|
|
166
170
|
branch_name: str,
|
|
167
171
|
obj: ComputedAttrJinja2GraphQLResponse,
|
|
168
172
|
node_kind: str,
|
|
@@ -246,7 +250,7 @@ async def process_jinja2(
|
|
|
246
250
|
batch = await service.client.create_batch()
|
|
247
251
|
for node in found:
|
|
248
252
|
batch.add(
|
|
249
|
-
task=
|
|
253
|
+
task=computed_attribute_jinja2_update_value,
|
|
250
254
|
branch_name=branch_name,
|
|
251
255
|
obj=node,
|
|
252
256
|
node_kind=node_schema.kind,
|
|
@@ -302,26 +306,33 @@ async def computed_attribute_setup_jinja2(
|
|
|
302
306
|
|
|
303
307
|
triggers = await gather_trigger_computed_attribute_jinja2()
|
|
304
308
|
|
|
305
|
-
for trigger in triggers:
|
|
306
|
-
if event_name != BranchDeletedEvent.event_name and trigger.branch == branch_name:
|
|
307
|
-
await service.workflow.submit_workflow(
|
|
308
|
-
workflow=TRIGGER_UPDATE_JINJA_COMPUTED_ATTRIBUTES,
|
|
309
|
-
context=context,
|
|
310
|
-
parameters={
|
|
311
|
-
"branch_name": trigger.branch,
|
|
312
|
-
"computed_attribute_name": trigger.computed_attribute.attribute.name,
|
|
313
|
-
"computed_attribute_kind": trigger.computed_attribute.kind,
|
|
314
|
-
},
|
|
315
|
-
)
|
|
316
|
-
|
|
317
309
|
# Configure all ComputedAttrJinja2Trigger in Prefect
|
|
318
310
|
async with get_client(sync_client=False) as prefect_client:
|
|
319
|
-
await setup_triggers(
|
|
311
|
+
report: TriggerSetupReport = await setup_triggers(
|
|
320
312
|
client=prefect_client,
|
|
321
313
|
triggers=triggers,
|
|
322
314
|
trigger_type=TriggerType.COMPUTED_ATTR_JINJA2,
|
|
315
|
+
force_update=False,
|
|
323
316
|
) # type: ignore[misc]
|
|
324
317
|
|
|
318
|
+
# Since we can have multiple trigger per NodeKind
|
|
319
|
+
# we need to extract the list of unique node that should be processed
|
|
320
|
+
unique_nodes: set[tuple[str, str, str]] = {
|
|
321
|
+
(trigger.branch, trigger.computed_attribute.kind, trigger.computed_attribute.attribute.name) # type: ignore[attr-defined]
|
|
322
|
+
for trigger in report.updated + report.created
|
|
323
|
+
}
|
|
324
|
+
for branch, kind, attribute_name in unique_nodes:
|
|
325
|
+
if event_name != BranchDeletedEvent.event_name and branch == branch_name:
|
|
326
|
+
await service.workflow.submit_workflow(
|
|
327
|
+
workflow=TRIGGER_UPDATE_JINJA_COMPUTED_ATTRIBUTES,
|
|
328
|
+
context=context,
|
|
329
|
+
parameters={
|
|
330
|
+
"branch_name": branch,
|
|
331
|
+
"computed_attribute_name": attribute_name,
|
|
332
|
+
"computed_attribute_kind": kind,
|
|
333
|
+
},
|
|
334
|
+
)
|
|
335
|
+
|
|
325
336
|
log.info(f"{len(triggers)} Computed Attribute for Jinja2 automation configuration completed")
|
|
326
337
|
|
|
327
338
|
|
|
@@ -347,18 +358,29 @@ async def computed_attribute_setup_python(
|
|
|
347
358
|
|
|
348
359
|
triggers_python, triggers_python_query = await gather_trigger_computed_attribute_python(db=db)
|
|
349
360
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
361
|
+
# Since we can have multiple trigger per NodeKind
|
|
362
|
+
# we need to extract the list of unique node that should be processed
|
|
363
|
+
# also
|
|
364
|
+
# Because the automation in Prefect doesn't capture all information about the computed attribute
|
|
365
|
+
# we can't tell right now if a given computed attribute has changed and need to be updated
|
|
366
|
+
unique_nodes: set[tuple[str, str, str]] = {
|
|
367
|
+
(
|
|
368
|
+
trigger.branch,
|
|
369
|
+
trigger.computed_attribute.computed_attribute.kind,
|
|
370
|
+
trigger.computed_attribute.computed_attribute.attribute.name,
|
|
371
|
+
)
|
|
372
|
+
for trigger in triggers_python
|
|
373
|
+
}
|
|
374
|
+
for branch, kind, attribute_name in unique_nodes:
|
|
375
|
+
if event_name != BranchDeletedEvent.event_name and branch == branch_name:
|
|
376
|
+
log.info(f"Triggering update for {kind}.{attribute_name} on {branch}")
|
|
355
377
|
await service.workflow.submit_workflow(
|
|
356
378
|
workflow=TRIGGER_UPDATE_PYTHON_COMPUTED_ATTRIBUTES,
|
|
357
379
|
context=context,
|
|
358
380
|
parameters={
|
|
359
381
|
"branch_name": branch_name,
|
|
360
|
-
"computed_attribute_name":
|
|
361
|
-
"computed_attribute_kind":
|
|
382
|
+
"computed_attribute_name": attribute_name,
|
|
383
|
+
"computed_attribute_kind": kind,
|
|
362
384
|
},
|
|
363
385
|
)
|
|
364
386
|
|
infrahub/config.py
CHANGED
|
@@ -269,6 +269,7 @@ class DatabaseSettings(BaseSettings):
|
|
|
269
269
|
address: str = "localhost"
|
|
270
270
|
port: int = 7687
|
|
271
271
|
database: str | None = Field(default=None, pattern=VALID_DATABASE_NAME_REGEX, description="Name of the database")
|
|
272
|
+
policy: str | None = Field(default=None, description="Routing policy for database connections")
|
|
272
273
|
tls_enabled: bool = Field(default=False, description="Indicates if TLS is enabled for the connection")
|
|
273
274
|
tls_insecure: bool = Field(default=False, description="Indicates if TLS certificates are verified")
|
|
274
275
|
tls_ca_file: str | None = Field(default=None, description="File path to CA cert or bundle in PEM format")
|
|
@@ -293,6 +294,14 @@ class DatabaseSettings(BaseSettings):
|
|
|
293
294
|
default=0.01, ge=0, description="Delay to add when max_concurrent_queries is reached."
|
|
294
295
|
)
|
|
295
296
|
|
|
297
|
+
@property
|
|
298
|
+
def database_uri(self) -> str:
|
|
299
|
+
"""Constructs the database URI based on the configuration settings."""
|
|
300
|
+
base_uri = f"{self.protocol}://{self.address}:{self.port}"
|
|
301
|
+
if self.policy is not None:
|
|
302
|
+
return f"{base_uri}?policy={self.policy}"
|
|
303
|
+
return base_uri
|
|
304
|
+
|
|
296
305
|
@property
|
|
297
306
|
def database_name(self) -> str:
|
|
298
307
|
return self.database or self.db_type.value
|
infrahub/core/account.py
CHANGED
|
@@ -69,8 +69,7 @@ class AccountGlobalPermissionQuery(Query):
|
|
|
69
69
|
query = """
|
|
70
70
|
MATCH (account:%(generic_account_node)s)
|
|
71
71
|
WHERE account.uuid = $account_id
|
|
72
|
-
CALL {
|
|
73
|
-
WITH account
|
|
72
|
+
CALL (account) {
|
|
74
73
|
MATCH (account)-[r:IS_PART_OF]-(root:Root)
|
|
75
74
|
WHERE %(branch_filter)s
|
|
76
75
|
RETURN account as account1, r as r1
|
|
@@ -80,8 +79,7 @@ class AccountGlobalPermissionQuery(Query):
|
|
|
80
79
|
WITH account, r1 as r
|
|
81
80
|
WHERE r.status = "active"
|
|
82
81
|
WITH account
|
|
83
|
-
CALL {
|
|
84
|
-
WITH account
|
|
82
|
+
CALL (account) {
|
|
85
83
|
MATCH (account)-[r1:IS_RELATED]->(:Relationship {name: "group_member"})<-[r2:IS_RELATED]-(account_group:%(account_group_node)s)
|
|
86
84
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
87
85
|
WITH account_group, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -92,8 +90,7 @@ class AccountGlobalPermissionQuery(Query):
|
|
|
92
90
|
}
|
|
93
91
|
WITH account_group
|
|
94
92
|
|
|
95
|
-
CALL {
|
|
96
|
-
WITH account_group
|
|
93
|
+
CALL (account_group) {
|
|
97
94
|
MATCH (account_group)-[r1:IS_RELATED]->(:Relationship {name: "role__accountgroups"})<-[r2:IS_RELATED]-(account_role:%(account_role_node)s)
|
|
98
95
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
99
96
|
WITH account_role, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -104,8 +101,7 @@ class AccountGlobalPermissionQuery(Query):
|
|
|
104
101
|
}
|
|
105
102
|
WITH account_role
|
|
106
103
|
|
|
107
|
-
CALL {
|
|
108
|
-
WITH account_role
|
|
104
|
+
CALL (account_role) {
|
|
109
105
|
MATCH (account_role)-[r1:IS_RELATED]->(:Relationship {name: "role__permissions"})<-[r2:IS_RELATED]-(global_permission:%(global_permission_node)s)
|
|
110
106
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
111
107
|
WITH global_permission, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -116,7 +112,7 @@ class AccountGlobalPermissionQuery(Query):
|
|
|
116
112
|
}
|
|
117
113
|
WITH global_permission
|
|
118
114
|
|
|
119
|
-
CALL {
|
|
115
|
+
CALL (global_permission) {
|
|
120
116
|
WITH global_permission
|
|
121
117
|
MATCH (global_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[r2:HAS_VALUE]->(global_permission_action:AttributeValue)
|
|
122
118
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
@@ -127,8 +123,7 @@ class AccountGlobalPermissionQuery(Query):
|
|
|
127
123
|
WITH global_permission, global_permission_action, is_active AS gpa_is_active
|
|
128
124
|
WHERE gpa_is_active = TRUE
|
|
129
125
|
|
|
130
|
-
CALL {
|
|
131
|
-
WITH global_permission
|
|
126
|
+
CALL (global_permission) {
|
|
132
127
|
MATCH (global_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[r2:HAS_VALUE]->(global_permission_decision:AttributeValue)
|
|
133
128
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
134
129
|
RETURN global_permission_decision, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -183,8 +178,7 @@ class AccountObjectPermissionQuery(Query):
|
|
|
183
178
|
query = """
|
|
184
179
|
MATCH (account:%(generic_account_node)s)
|
|
185
180
|
WHERE account.uuid = $account_id
|
|
186
|
-
CALL {
|
|
187
|
-
WITH account
|
|
181
|
+
CALL (account) {
|
|
188
182
|
MATCH (account)-[r:IS_PART_OF]-(root:Root)
|
|
189
183
|
WHERE %(branch_filter)s
|
|
190
184
|
RETURN account as account1, r as r1
|
|
@@ -194,8 +188,7 @@ class AccountObjectPermissionQuery(Query):
|
|
|
194
188
|
WITH account, r1 as r
|
|
195
189
|
WHERE r.status = "active"
|
|
196
190
|
WITH account
|
|
197
|
-
CALL {
|
|
198
|
-
WITH account
|
|
191
|
+
CALL (account) {
|
|
199
192
|
MATCH (account)-[r1:IS_RELATED]->(:Relationship {name: "group_member"})<-[r2:IS_RELATED]-(account_group:%(account_group_node)s)
|
|
200
193
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
201
194
|
WITH account_group, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -206,8 +199,7 @@ class AccountObjectPermissionQuery(Query):
|
|
|
206
199
|
}
|
|
207
200
|
WITH account_group
|
|
208
201
|
|
|
209
|
-
CALL {
|
|
210
|
-
WITH account_group
|
|
202
|
+
CALL (account_group) {
|
|
211
203
|
MATCH (account_group)-[r1:IS_RELATED]->(:Relationship {name: "role__accountgroups"})<-[r2:IS_RELATED]-(account_role:%(account_role_node)s)
|
|
212
204
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
213
205
|
WITH account_role, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -218,8 +210,7 @@ class AccountObjectPermissionQuery(Query):
|
|
|
218
210
|
}
|
|
219
211
|
WITH account_role
|
|
220
212
|
|
|
221
|
-
CALL {
|
|
222
|
-
WITH account_role
|
|
213
|
+
CALL (account_role) {
|
|
223
214
|
MATCH (account_role)-[r1:IS_RELATED]->(:Relationship {name: "role__permissions"})<-[r2:IS_RELATED]-(object_permission:%(object_permission_node)s)
|
|
224
215
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
225
216
|
WITH object_permission, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -230,8 +221,7 @@ class AccountObjectPermissionQuery(Query):
|
|
|
230
221
|
}
|
|
231
222
|
WITH object_permission
|
|
232
223
|
|
|
233
|
-
CALL {
|
|
234
|
-
WITH object_permission
|
|
224
|
+
CALL (object_permission) {
|
|
235
225
|
MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "namespace"})-[r2:HAS_VALUE]->(object_permission_namespace:AttributeValue)
|
|
236
226
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
237
227
|
RETURN object_permission_namespace, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -240,8 +230,7 @@ class AccountObjectPermissionQuery(Query):
|
|
|
240
230
|
}
|
|
241
231
|
WITH object_permission, object_permission_namespace, is_active AS opn_is_active
|
|
242
232
|
WHERE opn_is_active = TRUE
|
|
243
|
-
CALL {
|
|
244
|
-
WITH object_permission
|
|
233
|
+
CALL (object_permission) {
|
|
245
234
|
MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[r2:HAS_VALUE]->(object_permission_name:AttributeValue)
|
|
246
235
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
247
236
|
RETURN object_permission_name, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -250,8 +239,7 @@ class AccountObjectPermissionQuery(Query):
|
|
|
250
239
|
}
|
|
251
240
|
WITH object_permission, object_permission_namespace, object_permission_name, is_active AS opn_is_active
|
|
252
241
|
WHERE opn_is_active = TRUE
|
|
253
|
-
CALL {
|
|
254
|
-
WITH object_permission
|
|
242
|
+
CALL (object_permission) {
|
|
255
243
|
MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[r2:HAS_VALUE]->(object_permission_action:AttributeValue)
|
|
256
244
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
257
245
|
RETURN object_permission_action, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -260,8 +248,7 @@ class AccountObjectPermissionQuery(Query):
|
|
|
260
248
|
}
|
|
261
249
|
WITH object_permission, object_permission_namespace, object_permission_name, object_permission_action, is_active AS opa_is_active
|
|
262
250
|
WHERE opa_is_active = TRUE
|
|
263
|
-
CALL {
|
|
264
|
-
WITH object_permission
|
|
251
|
+
CALL (object_permission) {
|
|
265
252
|
MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[r2:HAS_VALUE]->(object_permission_decision:AttributeValue)
|
|
266
253
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
267
254
|
RETURN object_permission_decision, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -336,8 +323,7 @@ class AccountRoleGlobalPermissionQuery(Query):
|
|
|
336
323
|
query = """
|
|
337
324
|
MATCH (account_role:%(account_role_node)s)
|
|
338
325
|
WHERE account_role.uuid = $role_id
|
|
339
|
-
CALL {
|
|
340
|
-
WITH account_role
|
|
326
|
+
CALL (account_role) {
|
|
341
327
|
MATCH (account_role)-[r:IS_PART_OF]-(root:Root)
|
|
342
328
|
WHERE %(branch_filter)s
|
|
343
329
|
RETURN account_role as account_role1, r as r1
|
|
@@ -348,8 +334,7 @@ class AccountRoleGlobalPermissionQuery(Query):
|
|
|
348
334
|
WHERE r.status = "active"
|
|
349
335
|
WITH account_role
|
|
350
336
|
|
|
351
|
-
CALL {
|
|
352
|
-
WITH account_role
|
|
337
|
+
CALL (account_role) {
|
|
353
338
|
MATCH (account_role)-[r1:IS_RELATED]->(:Relationship {name: "role__permissions"})<-[r2:IS_RELATED]-(global_permission:%(global_permission_node)s)
|
|
354
339
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
355
340
|
WITH global_permission, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -360,8 +345,7 @@ class AccountRoleGlobalPermissionQuery(Query):
|
|
|
360
345
|
}
|
|
361
346
|
WITH global_permission
|
|
362
347
|
|
|
363
|
-
CALL {
|
|
364
|
-
WITH global_permission
|
|
348
|
+
CALL (global_permission) {
|
|
365
349
|
MATCH (global_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[r2:HAS_VALUE]->(global_permission_action:AttributeValue)
|
|
366
350
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
367
351
|
RETURN global_permission_action, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -371,8 +355,7 @@ class AccountRoleGlobalPermissionQuery(Query):
|
|
|
371
355
|
WITH global_permission, global_permission_action, is_active AS gpa_is_active
|
|
372
356
|
WHERE gpa_is_active = TRUE
|
|
373
357
|
|
|
374
|
-
CALL {
|
|
375
|
-
WITH global_permission
|
|
358
|
+
CALL (global_permission) {
|
|
376
359
|
MATCH (global_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[r2:HAS_VALUE]->(global_permission_decision:AttributeValue)
|
|
377
360
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
378
361
|
RETURN global_permission_decision, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -425,8 +408,7 @@ class AccountRoleObjectPermissionQuery(Query):
|
|
|
425
408
|
query = """
|
|
426
409
|
MATCH (account_role:%(account_role_node)s)
|
|
427
410
|
WHERE account_role.uuid = $role_id
|
|
428
|
-
CALL {
|
|
429
|
-
WITH account_role
|
|
411
|
+
CALL (account_role) {
|
|
430
412
|
MATCH (account_role)-[r:IS_PART_OF]-(root:Root)
|
|
431
413
|
WHERE %(branch_filter)s
|
|
432
414
|
RETURN account_role as account_role1, r as r1
|
|
@@ -437,8 +419,7 @@ class AccountRoleObjectPermissionQuery(Query):
|
|
|
437
419
|
WHERE r.status = "active"
|
|
438
420
|
WITH account_role
|
|
439
421
|
|
|
440
|
-
CALL {
|
|
441
|
-
WITH account_role
|
|
422
|
+
CALL (account_role) {
|
|
442
423
|
MATCH (account_role)-[r1:IS_RELATED]->(:Relationship {name: "role__permissions"})<-[r2:IS_RELATED]-(object_permission:%(object_permission_node)s)
|
|
443
424
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
444
425
|
WITH object_permission, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -449,8 +430,7 @@ class AccountRoleObjectPermissionQuery(Query):
|
|
|
449
430
|
}
|
|
450
431
|
WITH object_permission
|
|
451
432
|
|
|
452
|
-
CALL {
|
|
453
|
-
WITH object_permission
|
|
433
|
+
CALL (object_permission) {
|
|
454
434
|
MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "namespace"})-[r2:HAS_VALUE]->(object_permission_namespace:AttributeValue)
|
|
455
435
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
456
436
|
RETURN object_permission_namespace, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -459,8 +439,7 @@ class AccountRoleObjectPermissionQuery(Query):
|
|
|
459
439
|
}
|
|
460
440
|
WITH object_permission, object_permission_namespace, is_active AS opn_is_active
|
|
461
441
|
WHERE opn_is_active = TRUE
|
|
462
|
-
CALL {
|
|
463
|
-
WITH object_permission
|
|
442
|
+
CALL (object_permission) {
|
|
464
443
|
MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[r2:HAS_VALUE]->(object_permission_name:AttributeValue)
|
|
465
444
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
466
445
|
RETURN object_permission_name, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -469,8 +448,7 @@ class AccountRoleObjectPermissionQuery(Query):
|
|
|
469
448
|
}
|
|
470
449
|
WITH object_permission, object_permission_namespace, object_permission_name, is_active AS opn_is_active
|
|
471
450
|
WHERE opn_is_active = TRUE
|
|
472
|
-
CALL {
|
|
473
|
-
WITH object_permission
|
|
451
|
+
CALL (object_permission) {
|
|
474
452
|
MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[r2:HAS_VALUE]->(object_permission_action:AttributeValue)
|
|
475
453
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
476
454
|
RETURN object_permission_action, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
@@ -479,8 +457,7 @@ class AccountRoleObjectPermissionQuery(Query):
|
|
|
479
457
|
}
|
|
480
458
|
WITH object_permission, object_permission_namespace, object_permission_name, object_permission_action, is_active AS opa_is_active
|
|
481
459
|
WHERE opa_is_active = TRUE
|
|
482
|
-
CALL {
|
|
483
|
-
WITH object_permission
|
|
460
|
+
CALL (object_permission) {
|
|
484
461
|
MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[r2:HAS_VALUE]->(object_permission_decision:AttributeValue)
|
|
485
462
|
WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s))
|
|
486
463
|
RETURN object_permission_decision, (r1.status = "active" AND r2.status = "active") AS is_active
|
infrahub/core/attribute.py
CHANGED
|
@@ -232,7 +232,7 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
|
|
|
232
232
|
Raises:
|
|
233
233
|
ValidationError: Content of the attribute value is not valid
|
|
234
234
|
"""
|
|
235
|
-
if schema.
|
|
235
|
+
if regex := schema.get_regex():
|
|
236
236
|
if schema.kind == "List":
|
|
237
237
|
validation_values = [str(entry) for entry in value]
|
|
238
238
|
else:
|
|
@@ -240,22 +240,20 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
|
|
|
240
240
|
|
|
241
241
|
for validation_value in validation_values:
|
|
242
242
|
try:
|
|
243
|
-
is_valid = re.match(pattern=
|
|
243
|
+
is_valid = re.match(pattern=regex, string=str(validation_value))
|
|
244
244
|
except re.error as exc:
|
|
245
|
-
raise ValidationError(
|
|
246
|
-
{name: f"The regex defined in the schema is not valid ({schema.regex!r})"}
|
|
247
|
-
) from exc
|
|
245
|
+
raise ValidationError({name: f"The regex defined in the schema is not valid ({regex!r})"}) from exc
|
|
248
246
|
|
|
249
247
|
if not is_valid:
|
|
250
|
-
raise ValidationError({name: f"{validation_value} must conform with the regex: {
|
|
248
|
+
raise ValidationError({name: f"{validation_value} must conform with the regex: {regex!r}"})
|
|
251
249
|
|
|
252
|
-
if schema.
|
|
253
|
-
if len(value) <
|
|
254
|
-
raise ValidationError({name: f"{value} must have a minimum length of {
|
|
250
|
+
if min_length := schema.get_min_length():
|
|
251
|
+
if len(value) < min_length:
|
|
252
|
+
raise ValidationError({name: f"{value} must have a minimum length of {min_length!r}"})
|
|
255
253
|
|
|
256
|
-
if schema.
|
|
257
|
-
if len(value) >
|
|
258
|
-
raise ValidationError({name: f"{value} must have a maximum length of {
|
|
254
|
+
if max_length := schema.get_max_length():
|
|
255
|
+
if len(value) > max_length:
|
|
256
|
+
raise ValidationError({name: f"{value} must have a maximum length of {max_length!r}"})
|
|
259
257
|
|
|
260
258
|
if schema.enum:
|
|
261
259
|
try:
|
|
@@ -782,6 +780,10 @@ class Dropdown(BaseAttribute):
|
|
|
782
780
|
|
|
783
781
|
return ""
|
|
784
782
|
|
|
783
|
+
@staticmethod
|
|
784
|
+
def get_allowed_property_in_path() -> list[str]:
|
|
785
|
+
return ["color", "description", "label", "value"]
|
|
786
|
+
|
|
785
787
|
@classmethod
|
|
786
788
|
def validate_content(cls, value: Any, name: str, schema: AttributeSchema) -> None:
|
|
787
789
|
"""Validate the content of the dropdown."""
|
|
@@ -817,7 +819,18 @@ class IPNetwork(BaseAttribute):
|
|
|
817
819
|
|
|
818
820
|
@staticmethod
|
|
819
821
|
def get_allowed_property_in_path() -> list[str]:
|
|
820
|
-
return [
|
|
822
|
+
return [
|
|
823
|
+
"binary_address",
|
|
824
|
+
"broadcast_address",
|
|
825
|
+
"hostmask",
|
|
826
|
+
"netmask",
|
|
827
|
+
"num_addresses",
|
|
828
|
+
"prefixlen",
|
|
829
|
+
"value",
|
|
830
|
+
"version",
|
|
831
|
+
"with_hostmask",
|
|
832
|
+
"with_netmask",
|
|
833
|
+
]
|
|
821
834
|
|
|
822
835
|
@property
|
|
823
836
|
def obj(self) -> ipaddress.IPv4Network | ipaddress.IPv6Network:
|
|
@@ -950,7 +963,17 @@ class IPHost(BaseAttribute):
|
|
|
950
963
|
|
|
951
964
|
@staticmethod
|
|
952
965
|
def get_allowed_property_in_path() -> list[str]:
|
|
953
|
-
return [
|
|
966
|
+
return [
|
|
967
|
+
"binary_address",
|
|
968
|
+
"hostmask",
|
|
969
|
+
"ip",
|
|
970
|
+
"netmask",
|
|
971
|
+
"prefixlen",
|
|
972
|
+
"value",
|
|
973
|
+
"version",
|
|
974
|
+
"with_hostmask",
|
|
975
|
+
"with_netmask",
|
|
976
|
+
]
|
|
954
977
|
|
|
955
978
|
@property
|
|
956
979
|
def obj(self) -> ipaddress.IPv4Interface | ipaddress.IPv6Interface:
|
|
@@ -1170,6 +1193,22 @@ class MacAddress(BaseAttribute):
|
|
|
1170
1193
|
"""Serialize the value as standard EUI-48 or EUI-64 before storing it in the database."""
|
|
1171
1194
|
return str(netaddr.EUI(addr=self.value))
|
|
1172
1195
|
|
|
1196
|
+
@staticmethod
|
|
1197
|
+
def get_allowed_property_in_path() -> list[str]:
|
|
1198
|
+
return [
|
|
1199
|
+
"bare",
|
|
1200
|
+
"binary",
|
|
1201
|
+
"dot_notation",
|
|
1202
|
+
"ei",
|
|
1203
|
+
"eui48",
|
|
1204
|
+
"eui64",
|
|
1205
|
+
"oui",
|
|
1206
|
+
"semicolon_notation",
|
|
1207
|
+
"split_notation",
|
|
1208
|
+
"value",
|
|
1209
|
+
"version",
|
|
1210
|
+
]
|
|
1211
|
+
|
|
1173
1212
|
|
|
1174
1213
|
class MacAddressOptional(MacAddress):
|
|
1175
1214
|
value: str | None
|
infrahub/core/branch/models.py
CHANGED
|
@@ -295,6 +295,7 @@ class Branch(StandardNode):
|
|
|
295
295
|
is_isolated: bool = True,
|
|
296
296
|
branch_agnostic: bool = False,
|
|
297
297
|
variable_name: str = "r",
|
|
298
|
+
params_prefix: str = "",
|
|
298
299
|
) -> tuple[str, dict]:
|
|
299
300
|
"""
|
|
300
301
|
Generate a CYPHER Query filter based on a path to query a part of the graph at a specific time and on a specific branch.
|
|
@@ -306,30 +307,28 @@ class Branch(StandardNode):
|
|
|
306
307
|
|
|
307
308
|
There is a currently an assumption that the relationship in the path will be named 'r'
|
|
308
309
|
"""
|
|
309
|
-
|
|
310
|
+
pp = params_prefix
|
|
310
311
|
params: dict[str, Any] = {}
|
|
311
312
|
at = Timestamp(at)
|
|
312
313
|
at_str = at.to_string()
|
|
313
314
|
if branch_agnostic:
|
|
314
|
-
filter_str = (
|
|
315
|
-
|
|
316
|
-
)
|
|
317
|
-
params["time1"] = at_str
|
|
315
|
+
filter_str = f"{variable_name}.from <= ${pp}time1 AND ({variable_name}.to IS NULL or {variable_name}.to >= ${pp}time1)"
|
|
316
|
+
params[f"{pp}time1"] = at_str
|
|
318
317
|
return filter_str, params
|
|
319
318
|
|
|
320
319
|
branches_times = self.get_branches_and_times_to_query_global(at=at_str, is_isolated=is_isolated)
|
|
321
320
|
|
|
322
321
|
for idx, (branch_name, time_to_query) in enumerate(branches_times.items()):
|
|
323
|
-
params[f"branch{idx}"] = list(branch_name)
|
|
324
|
-
params[f"time{idx}"] = time_to_query
|
|
322
|
+
params[f"{pp}branch{idx}"] = list(branch_name)
|
|
323
|
+
params[f"{pp}time{idx}"] = time_to_query
|
|
325
324
|
|
|
326
325
|
filters = []
|
|
327
326
|
for idx in range(len(branches_times)):
|
|
328
327
|
filters.append(
|
|
329
|
-
f"({variable_name}.branch IN $branch{idx} AND {variable_name}.from <= $time{idx} AND {variable_name}.to IS NULL)"
|
|
328
|
+
f"({variable_name}.branch IN ${pp}branch{idx} AND {variable_name}.from <= ${pp}time{idx} AND {variable_name}.to IS NULL)"
|
|
330
329
|
)
|
|
331
330
|
filters.append(
|
|
332
|
-
f"({variable_name}.branch IN $branch{idx} AND {variable_name}.from <= $time{idx} AND {variable_name}.to >= $time{idx})"
|
|
331
|
+
f"({variable_name}.branch IN ${pp}branch{idx} AND {variable_name}.from <= ${pp}time{idx} AND {variable_name}.to >= ${pp}time{idx})"
|
|
333
332
|
)
|
|
334
333
|
|
|
335
334
|
filter_str = "(" + "\n OR ".join(filters) + ")"
|
infrahub/core/branch/tasks.py
CHANGED
|
@@ -212,8 +212,6 @@ async def merge_branch(
|
|
|
212
212
|
|
|
213
213
|
merger: BranchMerger | None = None
|
|
214
214
|
async with lock.registry.global_graph_lock():
|
|
215
|
-
# await update_diff(model=RequestDiffUpdate(branch_name=obj.name))
|
|
216
|
-
|
|
217
215
|
diff_repository = await component_registry.get_component(DiffRepository, db=db, branch=obj)
|
|
218
216
|
diff_coordinator = await component_registry.get_component(DiffCoordinator, db=db, branch=obj)
|
|
219
217
|
diff_merger = await component_registry.get_component(DiffMerger, db=db, branch=obj)
|
|
@@ -2,6 +2,7 @@ ACCOUNT = "CoreAccount"
|
|
|
2
2
|
ACCOUNTGROUP = "CoreAccountGroup"
|
|
3
3
|
ACCOUNTROLE = "CoreAccountRole"
|
|
4
4
|
ACCOUNTTOKEN = "InternalAccountToken"
|
|
5
|
+
ACTION = "CoreAction"
|
|
5
6
|
ARTIFACT = "CoreArtifact"
|
|
6
7
|
ARTIFACTCHECK = "CoreArtifactCheck"
|
|
7
8
|
ARTIFACTDEFINITION = "CoreArtifactDefinition"
|
|
@@ -21,6 +22,7 @@ DATAVALIDATOR = "CoreDataValidator"
|
|
|
21
22
|
FILECHECK = "CoreFileCheck"
|
|
22
23
|
FILETHREAD = "CoreFileThread"
|
|
23
24
|
GENERICACCOUNT = "CoreGenericAccount"
|
|
25
|
+
GENERATORACTION = "CoreGeneratorAction"
|
|
24
26
|
GENERATORCHECK = "CoreGeneratorCheck"
|
|
25
27
|
GENERATORDEFINITION = "CoreGeneratorDefinition"
|
|
26
28
|
GENERATORINSTANCE = "CoreGeneratorInstance"
|
|
@@ -30,6 +32,8 @@ GENERICGROUP = "CoreGroup"
|
|
|
30
32
|
GLOBALPERMISSION = "CoreGlobalPermission"
|
|
31
33
|
GRAPHQLQUERY = "CoreGraphQLQuery"
|
|
32
34
|
GRAPHQLQUERYGROUP = "CoreGraphQLQueryGroup"
|
|
35
|
+
GROUPACTION = "CoreGroupAction"
|
|
36
|
+
GROUPTRIGGERRULE = "CoreGroupTriggerRule"
|
|
33
37
|
IPNAMESPACE = "BuiltinIPNamespace"
|
|
34
38
|
IPADDRESS = "BuiltinIPAddress"
|
|
35
39
|
IPADDRESSPOOL = "CoreIPAddressPool"
|
|
@@ -39,6 +43,9 @@ MENU = "CoreMenu"
|
|
|
39
43
|
MENUITEM = "CoreMenuItem"
|
|
40
44
|
NAMESPACE = "IpamNamespace"
|
|
41
45
|
NODE = "CoreNode"
|
|
46
|
+
NODETRIGGERRULE = "CoreNodeTriggerRule"
|
|
47
|
+
NODETRIGGERATTRIBUTEMATCH = "CoreNodeTriggerAttributeMatch"
|
|
48
|
+
NODETRIGGERRELATIONSHIPMATCH = "CoreNodeTriggerRelationshipMatch"
|
|
42
49
|
NUMBERPOOL = "CoreNumberPool"
|
|
43
50
|
LINEAGEOWNER = "LineageOwner"
|
|
44
51
|
LINEAGESOURCE = "LineageSource"
|
|
@@ -67,6 +74,7 @@ THREADCOMMENT = "CoreThreadComment"
|
|
|
67
74
|
TRANSFORM = "CoreTransformation"
|
|
68
75
|
TRANSFORMJINJA2 = "CoreTransformJinja2"
|
|
69
76
|
TRANSFORMPYTHON = "CoreTransformPython"
|
|
77
|
+
TRIGGERRULE = "CoreTriggerRule"
|
|
70
78
|
USERVALIDATOR = "CoreUserValidator"
|
|
71
79
|
VALIDATOR = "CoreValidator"
|
|
72
80
|
WEBHOOK = "CoreWebhook"
|
|
@@ -26,7 +26,7 @@ class NodeConstraintRunner:
|
|
|
26
26
|
async def check(
|
|
27
27
|
self, node: Node, field_filters: list[str] | None = None, skip_uniqueness_check: bool = False
|
|
28
28
|
) -> None:
|
|
29
|
-
async with self.db.start_session() as db:
|
|
29
|
+
async with self.db.start_session(read_only=False) as db:
|
|
30
30
|
await node.resolve_relationships(db=db)
|
|
31
31
|
|
|
32
32
|
if not skip_uniqueness_check:
|
|
File without changes
|