infrahub-server 1.1.0b2__py3-none-any.whl → 1.1.2__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/artifact.py +8 -15
- infrahub/api/dependencies.py +15 -2
- infrahub/api/diff/diff.py +2 -2
- infrahub/api/file.py +2 -7
- infrahub/api/menu.py +9 -7
- infrahub/api/oauth2.py +3 -3
- infrahub/api/oidc.py +3 -3
- infrahub/api/query.py +4 -4
- infrahub/api/schema.py +24 -41
- infrahub/api/transformation.py +3 -3
- infrahub/auth.py +0 -2
- infrahub/cli/db.py +9 -11
- infrahub/cli/tasks.py +3 -1
- infrahub/computed_attribute/constants.py +2 -2
- infrahub/computed_attribute/models.py +20 -8
- infrahub/computed_attribute/tasks.py +136 -61
- infrahub/config.py +18 -4
- infrahub/core/account.py +8 -11
- infrahub/core/attribute.py +15 -0
- infrahub/core/branch/constants.py +2 -0
- infrahub/core/branch/models.py +3 -2
- infrahub/core/branch/tasks.py +150 -52
- infrahub/core/constraint/node/runner.py +11 -10
- infrahub/core/diff/calculator.py +4 -3
- infrahub/core/diff/combiner.py +1 -0
- infrahub/core/diff/coordinator.py +309 -105
- infrahub/core/diff/data_check_synchronizer.py +33 -4
- infrahub/core/diff/enricher/hierarchy.py +2 -0
- infrahub/core/diff/merger/merger.py +1 -1
- infrahub/core/diff/model/path.py +101 -3
- infrahub/core/diff/query/artifact.py +52 -28
- infrahub/core/diff/query/field_specifiers.py +35 -0
- infrahub/core/diff/query/roots_metadata.py +48 -0
- infrahub/core/diff/query/save.py +1 -0
- infrahub/core/diff/query_parser.py +52 -19
- infrahub/core/diff/repository/deserializer.py +7 -3
- infrahub/core/diff/repository/repository.py +98 -7
- infrahub/core/diff/tasks.py +29 -25
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/constraints.py +4 -2
- infrahub/core/integrity/object_conflict/conflict_recorder.py +6 -1
- infrahub/core/manager.py +157 -43
- infrahub/core/merge.py +3 -2
- infrahub/core/migrations/graph/__init__.py +4 -0
- infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -6
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -5
- infrahub/core/migrations/graph/m014_remove_index_attr_value.py +1 -1
- infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
- infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
- infrahub/core/migrations/graph/m017_add_core_profile.py +44 -0
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +101 -0
- infrahub/core/migrations/query/attribute_add.py +2 -1
- infrahub/core/migrations/query/delete_element_in_schema.py +2 -1
- infrahub/core/migrations/query/node_duplicate.py +2 -1
- infrahub/core/migrations/query/relationship_duplicate.py +2 -1
- infrahub/core/migrations/query/schema_attribute_update.py +1 -1
- infrahub/core/migrations/schema/tasks.py +2 -2
- infrahub/core/migrations/shared.py +3 -3
- infrahub/core/node/__init__.py +34 -7
- infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
- infrahub/core/query/__init__.py +12 -6
- infrahub/core/query/diff.py +23 -17
- infrahub/core/query/ipam.py +9 -4
- infrahub/core/query/node.py +161 -65
- infrahub/core/query/relationship.py +19 -17
- infrahub/core/query/resource_manager.py +21 -11
- infrahub/core/query/standard_node.py +13 -19
- infrahub/core/registry.py +0 -1
- infrahub/core/relationship/model.py +17 -5
- infrahub/core/schema/definitions/internal.py +1 -1
- infrahub/core/schema/generated/attribute_schema.py +2 -2
- infrahub/core/schema/generated/base_node_schema.py +2 -2
- infrahub/core/schema/generated/relationship_schema.py +1 -1
- infrahub/core/schema/schema_branch.py +16 -48
- infrahub/core/schema/schema_branch_computed.py +15 -4
- infrahub/core/task/task_log.py +1 -1
- infrahub/core/utils.py +5 -4
- infrahub/core/validators/interface.py +1 -2
- infrahub/core/validators/shared.py +2 -2
- infrahub/core/validators/tasks.py +8 -7
- infrahub/core/validators/uniqueness/index.py +2 -4
- infrahub/core/validators/uniqueness/query.py +2 -1
- infrahub/database/__init__.py +37 -20
- infrahub/database/index.py +1 -1
- infrahub/database/neo4j.py +3 -1
- infrahub/dependencies/builder/diff/data_check_synchronizer.py +2 -0
- infrahub/events/branch_action.py +13 -14
- infrahub/events/node_action.py +10 -10
- infrahub/events/schema_action.py +6 -5
- infrahub/exceptions.py +29 -16
- infrahub/generators/tasks.py +2 -1
- infrahub/git/base.py +106 -32
- infrahub/git/integrator.py +34 -3
- infrahub/git/models.py +5 -1
- infrahub/git/repository.py +19 -65
- infrahub/git/tasks.py +43 -22
- infrahub/graphql/app.py +2 -2
- infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +2 -17
- infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +1 -12
- infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +6 -40
- infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -8
- infrahub/graphql/enums.py +2 -2
- infrahub/graphql/initialization.py +30 -8
- infrahub/graphql/loaders/node.py +82 -0
- infrahub/graphql/manager.py +10 -4
- infrahub/graphql/models.py +6 -0
- infrahub/graphql/mutations/account.py +10 -6
- infrahub/graphql/mutations/branch.py +0 -2
- infrahub/graphql/mutations/computed_attribute.py +14 -23
- infrahub/graphql/mutations/diff.py +2 -0
- infrahub/graphql/mutations/ipam.py +13 -8
- infrahub/graphql/mutations/main.py +83 -8
- infrahub/graphql/mutations/proposed_change.py +11 -20
- infrahub/graphql/mutations/repository.py +3 -0
- infrahub/graphql/mutations/resource_manager.py +3 -0
- infrahub/graphql/mutations/schema.py +8 -7
- infrahub/graphql/mutations/tasks.py +36 -37
- infrahub/graphql/permissions.py +3 -4
- infrahub/graphql/queries/account.py +2 -11
- infrahub/graphql/queries/task.py +2 -12
- infrahub/graphql/query.py +3 -1
- infrahub/graphql/{resolver.py → resolvers/resolver.py} +14 -61
- infrahub/graphql/resolvers/single_relationship.py +169 -0
- infrahub/graphql/schema.py +0 -6
- infrahub/graphql/subscription/graphql_query.py +7 -1
- infrahub/graphql/types/task.py +14 -2
- infrahub/groups/tasks.py +9 -3
- infrahub/log.py +4 -0
- infrahub/menu/generator.py +6 -18
- infrahub/message_bus/messages/check_generator_run.py +1 -0
- infrahub/message_bus/messages/event_node_mutated.py +2 -2
- infrahub/message_bus/messages/refresh_git_fetch.py +1 -0
- infrahub/message_bus/messages/request_repository_userchecks.py +2 -1
- infrahub/message_bus/operations/check/artifact.py +3 -1
- infrahub/message_bus/operations/check/generator.py +20 -2
- infrahub/message_bus/operations/check/repository.py +31 -21
- infrahub/message_bus/operations/event/branch.py +2 -4
- infrahub/message_bus/operations/git/file.py +1 -3
- infrahub/message_bus/operations/git/repository.py +7 -2
- infrahub/message_bus/operations/requests/artifact_definition.py +6 -5
- infrahub/message_bus/operations/requests/generator_definition.py +10 -6
- infrahub/message_bus/operations/requests/proposed_change.py +31 -13
- infrahub/message_bus/operations/requests/repository.py +15 -13
- infrahub/message_bus/types.py +1 -1
- infrahub/permissions/__init__.py +12 -3
- infrahub/permissions/backend.py +2 -17
- infrahub/permissions/constants.py +12 -8
- infrahub/permissions/local_backend.py +5 -102
- infrahub/permissions/manager.py +135 -0
- infrahub/permissions/report.py +14 -25
- infrahub/permissions/types.py +6 -0
- infrahub/proposed_change/tasks.py +12 -9
- infrahub/server.py +3 -1
- infrahub/services/scheduler.py +1 -3
- infrahub/task_manager/models.py +34 -5
- infrahub/task_manager/task.py +10 -6
- infrahub/tasks/dummy.py +3 -0
- infrahub/tasks/telemetry.py +26 -24
- infrahub/transformations/tasks.py +2 -0
- infrahub/visuals.py +1 -3
- infrahub/webhook/models.py +6 -2
- infrahub/webhook/tasks.py +1 -1
- infrahub/workers/infrahub_async.py +14 -0
- infrahub/workflows/catalogue.py +24 -5
- infrahub/workflows/utils.py +11 -3
- infrahub_sdk/_importer.py +13 -4
- infrahub_sdk/analyzer.py +9 -7
- infrahub_sdk/batch.py +54 -8
- infrahub_sdk/branch.py +22 -20
- infrahub_sdk/checks.py +14 -41
- infrahub_sdk/client.py +769 -575
- infrahub_sdk/code_generator.py +21 -17
- infrahub_sdk/config.py +15 -13
- infrahub_sdk/ctl/branch.py +1 -1
- infrahub_sdk/ctl/check.py +15 -11
- infrahub_sdk/ctl/cli_commands.py +122 -21
- infrahub_sdk/ctl/client.py +18 -16
- infrahub_sdk/ctl/config.py +6 -7
- infrahub_sdk/ctl/exporter.py +2 -3
- infrahub_sdk/ctl/generator.py +11 -8
- infrahub_sdk/ctl/render.py +1 -1
- infrahub_sdk/ctl/repository.py +9 -7
- infrahub_sdk/ctl/schema.py +8 -4
- infrahub_sdk/ctl/transform.py +1 -1
- infrahub_sdk/ctl/utils.py +13 -9
- infrahub_sdk/ctl/validate.py +3 -2
- infrahub_sdk/data.py +5 -4
- infrahub_sdk/exceptions.py +14 -14
- infrahub_sdk/generator.py +9 -10
- infrahub_sdk/graphql.py +9 -4
- infrahub_sdk/groups.py +1 -3
- infrahub_sdk/node.py +188 -152
- infrahub_sdk/object_store.py +5 -5
- infrahub_sdk/playback.py +11 -7
- infrahub_sdk/protocols_base.py +30 -30
- infrahub_sdk/pytest_plugin/items/base.py +21 -7
- infrahub_sdk/pytest_plugin/items/check.py +11 -7
- infrahub_sdk/pytest_plugin/items/graphql_query.py +2 -2
- infrahub_sdk/pytest_plugin/items/jinja2_transform.py +5 -5
- infrahub_sdk/pytest_plugin/items/python_transform.py +12 -7
- infrahub_sdk/pytest_plugin/loader.py +2 -2
- infrahub_sdk/pytest_plugin/models.py +10 -10
- infrahub_sdk/pytest_plugin/plugin.py +3 -2
- infrahub_sdk/pytest_plugin/utils.py +1 -1
- infrahub_sdk/queries.py +69 -0
- infrahub_sdk/query_groups.py +17 -17
- infrahub_sdk/schema/__init__.py +687 -0
- infrahub_sdk/schema/main.py +343 -0
- infrahub_sdk/schema/repository.py +237 -0
- infrahub_sdk/spec/menu.py +2 -2
- infrahub_sdk/spec/object.py +14 -10
- infrahub_sdk/store.py +21 -23
- infrahub_sdk/task_report.py +20 -22
- infrahub_sdk/testing/__init__.py +0 -0
- infrahub_sdk/testing/docker.py +18 -0
- infrahub_sdk/testing/repository.py +107 -0
- infrahub_sdk/testing/schemas/__init__.py +0 -0
- infrahub_sdk/testing/schemas/animal.py +182 -0
- infrahub_sdk/testing/schemas/car_person.py +252 -0
- infrahub_sdk/timestamp.py +1 -2
- infrahub_sdk/transfer/exporter/interface.py +3 -2
- infrahub_sdk/transfer/exporter/json.py +13 -10
- infrahub_sdk/transfer/importer/json.py +9 -6
- infrahub_sdk/transfer/schema_sorter.py +8 -4
- infrahub_sdk/transforms.py +5 -46
- infrahub_sdk/types.py +19 -10
- infrahub_sdk/utils.py +22 -5
- infrahub_sdk/uuidt.py +5 -6
- infrahub_sdk/yaml.py +8 -6
- {infrahub_server-1.1.0b2.dist-info → infrahub_server-1.1.2.dist-info}/METADATA +3 -2
- {infrahub_server-1.1.0b2.dist-info → infrahub_server-1.1.2.dist-info}/RECORD +240 -225
- infrahub_testcontainers/__init__.py +6 -0
- {infrahub/testing → infrahub_testcontainers}/container.py +28 -22
- {infrahub/testing → infrahub_testcontainers}/docker-compose.test.yml +33 -40
- {infrahub/testing → infrahub_testcontainers}/helpers.py +31 -26
- infrahub/core/diff/query/empty_roots.py +0 -33
- infrahub/graphql/mutations/task.py +0 -147
- infrahub/testing/schemas/car_person.py +0 -125
- infrahub_sdk/schema.py +0 -1080
- /infrahub/{testing → graphql/loaders}/__init__.py +0 -0
- /infrahub/{testing/schemas → graphql/resolvers}/__init__.py +0 -0
- {infrahub_server-1.1.0b2.dist-info → infrahub_server-1.1.2.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.1.0b2.dist-info → infrahub_server-1.1.2.dist-info}/WHEEL +0 -0
- {infrahub_server-1.1.0b2.dist-info → infrahub_server-1.1.2.dist-info}/entry_points.txt +0 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from datetime import timedelta
|
|
2
4
|
from typing import TYPE_CHECKING, Any
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
import ujson
|
|
7
|
+
from infrahub_sdk.protocols import CoreNode # noqa: TC002
|
|
5
8
|
from prefect import flow
|
|
6
9
|
from prefect.automations import AutomationCore
|
|
7
10
|
from prefect.client.orchestration import get_client
|
|
@@ -25,7 +28,6 @@ from infrahub.workflows.catalogue import (
|
|
|
25
28
|
TRIGGER_UPDATE_PYTHON_COMPUTED_ATTRIBUTES,
|
|
26
29
|
UPDATE_COMPUTED_ATTRIBUTE_TRANSFORM,
|
|
27
30
|
)
|
|
28
|
-
from infrahub.workflows.constants import TAG_NAMESPACE, WorkflowTag
|
|
29
31
|
from infrahub.workflows.utils import add_tags, wait_for_schema_to_converge
|
|
30
32
|
|
|
31
33
|
from .constants import (
|
|
@@ -38,7 +40,10 @@ from .constants import (
|
|
|
38
40
|
from .models import ComputedAttributeAutomations, PythonTransformComputedAttribute, PythonTransformTarget
|
|
39
41
|
|
|
40
42
|
if TYPE_CHECKING:
|
|
43
|
+
import logging
|
|
44
|
+
|
|
41
45
|
from infrahub.core.schema.computed_attribute import ComputedAttribute
|
|
46
|
+
from infrahub.services import InfrahubServices
|
|
42
47
|
|
|
43
48
|
UPDATE_ATTRIBUTE = """
|
|
44
49
|
mutation UpdateAttribute(
|
|
@@ -104,10 +109,12 @@ async def process_transform(
|
|
|
104
109
|
name=transform.repository.peer.name.value,
|
|
105
110
|
service=service,
|
|
106
111
|
repository_kind=transform.repository.peer.typename,
|
|
112
|
+
commit=repo_node.commit.value,
|
|
107
113
|
)
|
|
108
114
|
|
|
109
115
|
data = await service.client.query_gql_query(
|
|
110
116
|
name=transform.query.peer.name.value,
|
|
117
|
+
branch_name=branch_name,
|
|
111
118
|
variables={"id": object_id},
|
|
112
119
|
update_group=True,
|
|
113
120
|
subscribers=[object_id],
|
|
@@ -170,7 +177,7 @@ async def update_computed_attribute_value_jinja2(
|
|
|
170
177
|
log = get_run_logger()
|
|
171
178
|
service = services.service
|
|
172
179
|
|
|
173
|
-
await add_tags(branches=[branch_name], nodes=[obj.id],
|
|
180
|
+
await add_tags(branches=[branch_name], nodes=[obj.id], db_change=True)
|
|
174
181
|
|
|
175
182
|
macro_definition = MacroDefinition(macro=template_value)
|
|
176
183
|
my_filter = {}
|
|
@@ -221,12 +228,15 @@ async def process_jinja2(
|
|
|
221
228
|
object_id: str,
|
|
222
229
|
computed_attribute_name: str,
|
|
223
230
|
computed_attribute_kind: str,
|
|
224
|
-
updated_fields:
|
|
231
|
+
updated_fields: str | None = None,
|
|
225
232
|
) -> None:
|
|
226
233
|
log = get_run_logger()
|
|
227
234
|
service = services.service
|
|
228
235
|
|
|
229
236
|
await add_tags(branches=[branch_name])
|
|
237
|
+
updates: list[str] = []
|
|
238
|
+
if isinstance(updated_fields, str):
|
|
239
|
+
updates = ujson.loads(updated_fields)
|
|
230
240
|
|
|
231
241
|
target_branch_schema = (
|
|
232
242
|
branch_name if branch_name in registry.get_altered_schema_branches() else registry.default_branch
|
|
@@ -236,9 +246,7 @@ async def process_jinja2(
|
|
|
236
246
|
|
|
237
247
|
computed_macros = [
|
|
238
248
|
attrib
|
|
239
|
-
for attrib in schema_branch.computed_attributes.get_impacted_jinja2_targets(
|
|
240
|
-
kind=node_kind, updates=updated_fields
|
|
241
|
-
)
|
|
249
|
+
for attrib in schema_branch.computed_attributes.get_impacted_jinja2_targets(kind=node_kind, updates=updates)
|
|
242
250
|
if attrib.kind == computed_attribute_kind and attrib.attribute.name == computed_attribute_name
|
|
243
251
|
]
|
|
244
252
|
for computed_macro in computed_macros:
|
|
@@ -363,6 +371,7 @@ async def computed_attribute_setup(branch_name: str | None = None) -> None: # p
|
|
|
363
371
|
"object_id": "{{ event.resource['infrahub.node.id'] }}",
|
|
364
372
|
"computed_attribute_name": computed_attribute.attribute.name,
|
|
365
373
|
"computed_attribute_kind": computed_attribute.kind,
|
|
374
|
+
"updated_fields": "{{ event.payload['fields'] | tojson }}",
|
|
366
375
|
},
|
|
367
376
|
job_variables={},
|
|
368
377
|
)
|
|
@@ -426,6 +435,7 @@ async def computed_attribute_setup(branch_name: str | None = None) -> None: # p
|
|
|
426
435
|
"object_id": "{{ event.resource['infrahub.node.id'] }}",
|
|
427
436
|
"computed_attribute_name": computed_attribute.attribute.name,
|
|
428
437
|
"computed_attribute_kind": computed_attribute.kind,
|
|
438
|
+
"updated_fields": "{{ event.payload['fields'] | tojson }}",
|
|
429
439
|
},
|
|
430
440
|
job_variables={},
|
|
431
441
|
)
|
|
@@ -464,51 +474,20 @@ async def computed_attribute_setup(branch_name: str | None = None) -> None: # p
|
|
|
464
474
|
flow_run_name="Setup computed attributes for Python transforms in task-manager",
|
|
465
475
|
)
|
|
466
476
|
async def computed_attribute_setup_python(
|
|
467
|
-
branch_name: str | None = None,
|
|
477
|
+
branch_name: str | None = None,
|
|
478
|
+
commit: str | None = None, # pylint: disable=unused-argument
|
|
479
|
+
trigger_updates: bool = True,
|
|
468
480
|
) -> None:
|
|
469
481
|
log = get_run_logger()
|
|
470
482
|
service = services.service
|
|
471
483
|
|
|
472
|
-
|
|
473
|
-
await add_tags(branches=[branch_name])
|
|
474
|
-
|
|
475
|
-
await wait_for_schema_to_converge(branch_name=registry.default_branch, service=service, log=log)
|
|
476
|
-
|
|
477
|
-
schema_branch = registry.schema.get_schema_branch(name=registry.default_branch)
|
|
478
|
-
|
|
479
|
-
transform_attributes = schema_branch.computed_attributes.python_attributes_by_transform
|
|
480
|
-
|
|
481
|
-
transform_names = list(transform_attributes.keys())
|
|
484
|
+
branch_name = branch_name or registry.default_branch
|
|
482
485
|
|
|
483
|
-
|
|
484
|
-
kind="CoreTransformPython",
|
|
485
|
-
branch=registry.default_branch,
|
|
486
|
-
prefetch_relationships=True,
|
|
487
|
-
populate_store=True,
|
|
488
|
-
name__values=transform_names,
|
|
489
|
-
)
|
|
486
|
+
await add_tags(branches=[branch_name])
|
|
490
487
|
|
|
491
|
-
|
|
492
|
-
for transform_name in transform_names:
|
|
493
|
-
if transform_name not in found_transforms_names:
|
|
494
|
-
log.warning(
|
|
495
|
-
msg=f"The transform {transform_name} is assigned to a computed attribute but the transform could not be found in the database."
|
|
496
|
-
)
|
|
488
|
+
await wait_for_schema_to_converge(branch_name=branch_name, service=service, log=log)
|
|
497
489
|
|
|
498
|
-
computed_attributes
|
|
499
|
-
for transform in transforms:
|
|
500
|
-
for attribute in transform_attributes[transform.name.value]:
|
|
501
|
-
computed_attributes.append(
|
|
502
|
-
PythonTransformComputedAttribute(
|
|
503
|
-
name=transform.name.value,
|
|
504
|
-
repository_id=transform.repository.peer.id,
|
|
505
|
-
repository_name=transform.repository.peer.name.value,
|
|
506
|
-
repository_kind=transform.repository.peer.typename,
|
|
507
|
-
query_name=transform.query.peer.name.value,
|
|
508
|
-
query_models=transform.query.peer.models.value,
|
|
509
|
-
computed_attribute=attribute,
|
|
510
|
-
)
|
|
511
|
-
)
|
|
490
|
+
computed_attributes = await _gather_python_transform_attributes(branch_name=branch_name, service=service, log=log)
|
|
512
491
|
|
|
513
492
|
async with get_client(sync_client=False) as client:
|
|
514
493
|
deployments = {
|
|
@@ -531,15 +510,16 @@ async def computed_attribute_setup_python(
|
|
|
531
510
|
|
|
532
511
|
automations = await client.read_automations()
|
|
533
512
|
existing_computed_attr_process_automations = ComputedAttributeAutomations.from_prefect(
|
|
534
|
-
automations=automations, prefix=PROCESS_PYTHON_AUTOMATION_NAME_PREFIX
|
|
513
|
+
automations=automations, prefix=f"{PROCESS_PYTHON_AUTOMATION_NAME_PREFIX}::{branch_name}::"
|
|
535
514
|
)
|
|
536
515
|
existing_computed_attr_query_automations = ComputedAttributeAutomations.from_prefect(
|
|
537
|
-
automations=automations, prefix=QUERY_AUTOMATION_NAME_PREFIX
|
|
516
|
+
automations=automations, prefix=f"{QUERY_AUTOMATION_NAME_PREFIX}::{branch_name}::"
|
|
538
517
|
)
|
|
539
518
|
|
|
519
|
+
automations_to_keep = []
|
|
540
520
|
for computed_attribute in computed_attributes:
|
|
541
521
|
log.info(f"processing {computed_attribute.computed_attribute.key_name}")
|
|
542
|
-
scope =
|
|
522
|
+
scope = branch_name
|
|
543
523
|
|
|
544
524
|
automation = AutomationCore(
|
|
545
525
|
name=PROCESS_AUTOMATION_NAME.format(
|
|
@@ -553,7 +533,12 @@ async def computed_attribute_setup_python(
|
|
|
553
533
|
posture=Posture.Reactive,
|
|
554
534
|
expect={"infrahub.node.*"},
|
|
555
535
|
within=timedelta(0),
|
|
556
|
-
match=ResourceSpecification(
|
|
536
|
+
match=ResourceSpecification(
|
|
537
|
+
{
|
|
538
|
+
"infrahub.node.kind": [computed_attribute.computed_attribute.kind],
|
|
539
|
+
"infrahub.branch.name": branch_name,
|
|
540
|
+
}
|
|
541
|
+
),
|
|
557
542
|
threshold=1,
|
|
558
543
|
),
|
|
559
544
|
actions=[
|
|
@@ -580,8 +565,10 @@ async def computed_attribute_setup_python(
|
|
|
580
565
|
)
|
|
581
566
|
await client.update_automation(automation_id=existing.id, automation=automation)
|
|
582
567
|
log.info(f"Process {computed_attribute.computed_attribute.key_name} Updated")
|
|
568
|
+
automations_to_keep.append(existing.id)
|
|
583
569
|
else:
|
|
584
|
-
await client.create_automation(automation=automation)
|
|
570
|
+
automation_id = await client.create_automation(automation=automation)
|
|
571
|
+
automations_to_keep.append(automation_id)
|
|
585
572
|
log.info(f"Process {computed_attribute.computed_attribute.key_name} Created")
|
|
586
573
|
|
|
587
574
|
automation = AutomationCore(
|
|
@@ -596,7 +583,12 @@ async def computed_attribute_setup_python(
|
|
|
596
583
|
posture=Posture.Reactive,
|
|
597
584
|
expect={"infrahub.node.*"},
|
|
598
585
|
within=timedelta(0),
|
|
599
|
-
match=ResourceSpecification(
|
|
586
|
+
match=ResourceSpecification(
|
|
587
|
+
{
|
|
588
|
+
"infrahub.node.kind": computed_attribute.query_models,
|
|
589
|
+
"infrahub.branch.name": branch_name,
|
|
590
|
+
}
|
|
591
|
+
),
|
|
600
592
|
threshold=1,
|
|
601
593
|
),
|
|
602
594
|
actions=[
|
|
@@ -620,19 +612,53 @@ async def computed_attribute_setup_python(
|
|
|
620
612
|
identifier=computed_attribute.computed_attribute.key_name, scope=scope
|
|
621
613
|
)
|
|
622
614
|
await client.update_automation(automation_id=existing.id, automation=automation)
|
|
615
|
+
automations_to_keep.append(existing.id)
|
|
623
616
|
log.info(f"Query {computed_attribute.computed_attribute.key_name} Updated")
|
|
624
617
|
else:
|
|
625
|
-
await client.create_automation(automation=automation)
|
|
618
|
+
automation_id = await client.create_automation(automation=automation)
|
|
619
|
+
automations_to_keep.append(automation_id)
|
|
626
620
|
log.info(f"Query {computed_attribute.computed_attribute.key_name} Created")
|
|
627
621
|
|
|
628
|
-
|
|
629
|
-
workflow
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
622
|
+
if trigger_updates:
|
|
623
|
+
await service.workflow.submit_workflow(
|
|
624
|
+
workflow=TRIGGER_UPDATE_PYTHON_COMPUTED_ATTRIBUTES,
|
|
625
|
+
parameters={
|
|
626
|
+
"branch_name": branch_name,
|
|
627
|
+
"computed_attribute_name": computed_attribute.computed_attribute.attribute.name,
|
|
628
|
+
"computed_attribute_kind": computed_attribute.computed_attribute.kind,
|
|
629
|
+
},
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
automations_to_remove = existing_computed_attr_process_automations.return_obsolete(keep=automations_to_keep)
|
|
633
|
+
for automation_to_remove in automations_to_remove:
|
|
634
|
+
await client.delete_automation(automation_id=automation_to_remove)
|
|
635
|
+
|
|
636
|
+
automations_to_remove = existing_computed_attr_query_automations.return_obsolete(keep=automations_to_keep)
|
|
637
|
+
for automation_to_remove in automations_to_remove:
|
|
638
|
+
await client.delete_automation(automation_id=automation_to_remove)
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
@flow(
|
|
642
|
+
name="computed-attribute-remove-python",
|
|
643
|
+
flow_run_name="Remove Python based computed attributes on branch={branch_name}",
|
|
644
|
+
)
|
|
645
|
+
async def computed_attribute_remove_python(
|
|
646
|
+
branch_name: str,
|
|
647
|
+
) -> None:
|
|
648
|
+
async with get_client(sync_client=False) as client:
|
|
649
|
+
automations = await client.read_automations()
|
|
650
|
+
existing_computed_attr_process_automations = ComputedAttributeAutomations.from_prefect(
|
|
651
|
+
automations=automations, prefix=f"{PROCESS_PYTHON_AUTOMATION_NAME_PREFIX}::{branch_name}::"
|
|
652
|
+
)
|
|
653
|
+
existing_computed_attr_query_automations = ComputedAttributeAutomations.from_prefect(
|
|
654
|
+
automations=automations, prefix=f"{QUERY_AUTOMATION_NAME_PREFIX}::{branch_name}::"
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
for automation_id in existing_computed_attr_process_automations.all_automation_ids:
|
|
658
|
+
await client.delete_automation(automation_id=automation_id)
|
|
659
|
+
|
|
660
|
+
for automation_id in existing_computed_attr_query_automations.all_automation_ids:
|
|
661
|
+
await client.delete_automation(automation_id=automation_id)
|
|
636
662
|
|
|
637
663
|
|
|
638
664
|
@flow(
|
|
@@ -648,7 +674,7 @@ async def query_transform_targets(
|
|
|
648
674
|
service = services.service
|
|
649
675
|
schema_branch = registry.schema.get_schema_branch(name=branch_name)
|
|
650
676
|
targets = await service.client.execute_graphql(
|
|
651
|
-
query=GATHER_GRAPHQL_QUERY_SUBSCRIBERS, variables={"members": [object_id]}
|
|
677
|
+
query=GATHER_GRAPHQL_QUERY_SUBSCRIBERS, variables={"members": [object_id]}, branch_name=branch_name
|
|
652
678
|
)
|
|
653
679
|
|
|
654
680
|
subscribers: list[PythonTransformTarget] = []
|
|
@@ -675,6 +701,55 @@ async def query_transform_targets(
|
|
|
675
701
|
)
|
|
676
702
|
|
|
677
703
|
|
|
704
|
+
async def _gather_python_transform_attributes(
|
|
705
|
+
branch_name: str, service: InfrahubServices, log: logging.Logger | logging.LoggerAdapter
|
|
706
|
+
) -> list[PythonTransformComputedAttribute]:
|
|
707
|
+
schema_branch = registry.schema.get_schema_branch(name=branch_name)
|
|
708
|
+
branches_with_diff_from_main = registry.get_altered_schema_branches()
|
|
709
|
+
|
|
710
|
+
transform_attributes = schema_branch.computed_attributes.python_attributes_by_transform
|
|
711
|
+
|
|
712
|
+
transform_names = list(transform_attributes.keys())
|
|
713
|
+
if not transform_names:
|
|
714
|
+
return []
|
|
715
|
+
|
|
716
|
+
transforms = await service.client.filters(
|
|
717
|
+
kind="CoreTransformPython",
|
|
718
|
+
branch=branch_name,
|
|
719
|
+
prefetch_relationships=True,
|
|
720
|
+
populate_store=True,
|
|
721
|
+
name__values=transform_names,
|
|
722
|
+
)
|
|
723
|
+
|
|
724
|
+
found_transforms_names = [transform.name.value for transform in transforms]
|
|
725
|
+
for transform_name in transform_names:
|
|
726
|
+
if transform_name not in found_transforms_names:
|
|
727
|
+
log.warning(
|
|
728
|
+
msg=f"The transform {transform_name} is assigned to a computed attribute but the transform could not be found in the database."
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
repositories = await service.client.get_list_repositories()
|
|
732
|
+
computed_attributes: list[PythonTransformComputedAttribute] = []
|
|
733
|
+
for transform in transforms:
|
|
734
|
+
for attribute in transform_attributes[transform.name.value]:
|
|
735
|
+
python_transform_computed_attribute = PythonTransformComputedAttribute(
|
|
736
|
+
name=transform.name.value,
|
|
737
|
+
repository_id=transform.repository.peer.id,
|
|
738
|
+
repository_name=transform.repository.peer.name.value,
|
|
739
|
+
repository_kind=transform.repository.peer.typename,
|
|
740
|
+
query_name=transform.query.peer.name.value,
|
|
741
|
+
query_models=transform.query.peer.models.value,
|
|
742
|
+
computed_attribute=attribute,
|
|
743
|
+
default_schema=branch_name not in branches_with_diff_from_main,
|
|
744
|
+
)
|
|
745
|
+
python_transform_computed_attribute.populate_branch_commit(
|
|
746
|
+
repository_data=repositories.get(transform.repository.peer.name.value)
|
|
747
|
+
)
|
|
748
|
+
computed_attributes.append(python_transform_computed_attribute)
|
|
749
|
+
|
|
750
|
+
return computed_attributes
|
|
751
|
+
|
|
752
|
+
|
|
678
753
|
GATHER_GRAPHQL_QUERY_SUBSCRIBERS = """
|
|
679
754
|
query GatherGraphQLQuerySubscribers($members: [ID!]) {
|
|
680
755
|
CoreGraphQLQueryGroup(members__ids: $members) {
|
infrahub/config.py
CHANGED
|
@@ -126,6 +126,14 @@ class WorkflowDriver(str, Enum):
|
|
|
126
126
|
WORKER = "worker"
|
|
127
127
|
|
|
128
128
|
|
|
129
|
+
class ExtraLogLevel(str, Enum):
|
|
130
|
+
CRITICAL = "CRITICAL"
|
|
131
|
+
ERROR = "ERROR"
|
|
132
|
+
WARNING = "WARNING"
|
|
133
|
+
INFO = "INFO"
|
|
134
|
+
DEBUG = "DEBUG"
|
|
135
|
+
|
|
136
|
+
|
|
129
137
|
class MainSettings(BaseSettings):
|
|
130
138
|
model_config = SettingsConfigDict(env_prefix="INFRAHUB_")
|
|
131
139
|
docs_index_path: Path = Field(
|
|
@@ -145,6 +153,10 @@ class MainSettings(BaseSettings):
|
|
|
145
153
|
default=["infrahub.permissions.LocalPermissionBackend"],
|
|
146
154
|
description="List of modules to handle permissions, they will be run in the given order",
|
|
147
155
|
)
|
|
156
|
+
public_url: Optional[str] = Field(
|
|
157
|
+
default=None,
|
|
158
|
+
description="Define the public URL of the Infrahub, might be required for OAuth2 and OIDC depending on your infrastructure.",
|
|
159
|
+
)
|
|
148
160
|
|
|
149
161
|
@field_validator("docs_index_path", mode="before")
|
|
150
162
|
@classmethod
|
|
@@ -248,10 +260,6 @@ class DevelopmentSettings(BaseSettings):
|
|
|
248
260
|
|
|
249
261
|
model_config = SettingsConfigDict(env_prefix="INFRAHUB_DEV_")
|
|
250
262
|
|
|
251
|
-
frontend_url: Optional[str] = Field(
|
|
252
|
-
default=None,
|
|
253
|
-
description="Define the URL of the frontend, useful for OAuth2 development when the frontend and backend use different ports.",
|
|
254
|
-
)
|
|
255
263
|
frontend_redirect_sso: bool = Field(
|
|
256
264
|
default=False,
|
|
257
265
|
description="Indicates of the frontend should be responsible for the SSO redirection",
|
|
@@ -318,6 +326,12 @@ class WorkflowSettings(BaseSettings):
|
|
|
318
326
|
tls_enabled: bool = Field(default=False, description="Indicates if TLS is enabled for the connection")
|
|
319
327
|
driver: WorkflowDriver = WorkflowDriver.WORKER
|
|
320
328
|
default_worker_type: str = "infrahubasync"
|
|
329
|
+
extra_loggers: list[str] = Field(
|
|
330
|
+
default_factory=list, description="A list of additional logger that will be captured during task execution."
|
|
331
|
+
)
|
|
332
|
+
extra_log_level: ExtraLogLevel = Field(
|
|
333
|
+
default=ExtraLogLevel.INFO, description="Log level applied to all extra loggers."
|
|
334
|
+
)
|
|
321
335
|
worker_polling_interval: int = Field(
|
|
322
336
|
default=2, ge=1, le=30, description="Specify how often the worker should poll the server for tasks (sec)"
|
|
323
337
|
)
|
infrahub/core/account.py
CHANGED
|
@@ -6,13 +6,13 @@ from typing import TYPE_CHECKING, Any, Optional, Union
|
|
|
6
6
|
from typing_extensions import Self
|
|
7
7
|
|
|
8
8
|
from infrahub.core.constants import InfrahubKind, PermissionDecision
|
|
9
|
-
from infrahub.core.query import Query
|
|
9
|
+
from infrahub.core.query import Query, QueryType
|
|
10
10
|
from infrahub.core.registry import registry
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
13
|
from infrahub.core.branch import Branch
|
|
14
14
|
from infrahub.database import InfrahubDatabase
|
|
15
|
-
from infrahub.permissions
|
|
15
|
+
from infrahub.permissions import AssignedPermissions
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
# pylint: disable=redefined-builtin
|
|
@@ -35,15 +35,7 @@ class GlobalPermission:
|
|
|
35
35
|
if len(parts) != 3 and parts[0] != "global":
|
|
36
36
|
raise ValueError(f"{input} is not a valid format for a Global permission")
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
decision = PermissionDecision.DENY
|
|
40
|
-
if parts[2] == "allow_default":
|
|
41
|
-
decision = PermissionDecision.ALLOW_DEFAULT
|
|
42
|
-
elif parts[2] == "allow_all":
|
|
43
|
-
decision = PermissionDecision.ALLOW_ALL
|
|
44
|
-
elif parts[2] == "allow_other":
|
|
45
|
-
decision = PermissionDecision.ALLOW_OTHER
|
|
46
|
-
return cls(action=str(parts[1]), decision=decision)
|
|
38
|
+
return cls(action=parts[1], decision=PermissionDecision[parts[2].upper()])
|
|
47
39
|
|
|
48
40
|
|
|
49
41
|
@dataclass
|
|
@@ -62,6 +54,7 @@ class ObjectPermission:
|
|
|
62
54
|
|
|
63
55
|
class AccountGlobalPermissionQuery(Query):
|
|
64
56
|
name: str = "account_global_permissions"
|
|
57
|
+
type: QueryType = QueryType.READ
|
|
65
58
|
|
|
66
59
|
def __init__(self, account_id: str, **kwargs: Any):
|
|
67
60
|
self.account_id = account_id
|
|
@@ -176,6 +169,7 @@ class AccountGlobalPermissionQuery(Query):
|
|
|
176
169
|
|
|
177
170
|
class AccountObjectPermissionQuery(Query):
|
|
178
171
|
name: str = "account_object_permissions"
|
|
172
|
+
type: QueryType = QueryType.READ
|
|
179
173
|
|
|
180
174
|
def __init__(self, account_id: str, **kwargs: Any):
|
|
181
175
|
self.account_id = account_id
|
|
@@ -327,6 +321,7 @@ async def fetch_permissions(account_id: str, db: InfrahubDatabase, branch: Branc
|
|
|
327
321
|
|
|
328
322
|
class AccountRoleGlobalPermissionQuery(Query):
|
|
329
323
|
name: str = "account_role_global_permissions"
|
|
324
|
+
type: QueryType = QueryType.READ
|
|
330
325
|
|
|
331
326
|
def __init__(self, role_id: str, **kwargs: Any):
|
|
332
327
|
self.role_id = role_id
|
|
@@ -416,6 +411,7 @@ class AccountRoleGlobalPermissionQuery(Query):
|
|
|
416
411
|
|
|
417
412
|
class AccountRoleObjectPermissionQuery(Query):
|
|
418
413
|
name: str = "account_role_object_permissions"
|
|
414
|
+
type: QueryType = QueryType.READ
|
|
419
415
|
|
|
420
416
|
def __init__(self, role_id: str, **kwargs: Any):
|
|
421
417
|
self.role_id = role_id
|
|
@@ -542,6 +538,7 @@ async def fetch_role_permissions(role_id: str, db: InfrahubDatabase, branch: Bra
|
|
|
542
538
|
|
|
543
539
|
class AccountTokenValidateQuery(Query):
|
|
544
540
|
name: str = "account_token_validate"
|
|
541
|
+
type: QueryType = QueryType.READ
|
|
545
542
|
|
|
546
543
|
def __init__(self, token: str, **kwargs: Any):
|
|
547
544
|
self.token = token
|
infrahub/core/attribute.py
CHANGED
|
@@ -666,6 +666,21 @@ class Integer(BaseAttribute):
|
|
|
666
666
|
value: int
|
|
667
667
|
from_pool: Optional[str] = None
|
|
668
668
|
|
|
669
|
+
@classmethod
|
|
670
|
+
def validate_format(cls, value: Any, name: str, schema: AttributeSchema) -> None:
|
|
671
|
+
"""
|
|
672
|
+
Make sure boolean objects are not accepted as value. Need to override `validate_format`
|
|
673
|
+
as `isinstance(True, int)` is True.
|
|
674
|
+
"""
|
|
675
|
+
|
|
676
|
+
value_to_check = value
|
|
677
|
+
if schema.enum and isinstance(value, Enum):
|
|
678
|
+
value_to_check = value.value
|
|
679
|
+
|
|
680
|
+
# Note that we might want to do this check directly in parent function.
|
|
681
|
+
if value_to_check.__class__ != cls.type:
|
|
682
|
+
raise ValidationError({name: f"{value} is not a valid {schema.kind}"})
|
|
683
|
+
|
|
669
684
|
|
|
670
685
|
class IntegerOptional(Integer):
|
|
671
686
|
value: Optional[int]
|
infrahub/core/branch/models.py
CHANGED
|
@@ -8,8 +8,9 @@ from pydantic import Field, field_validator
|
|
|
8
8
|
from infrahub.core.constants import (
|
|
9
9
|
GLOBAL_BRANCH_NAME,
|
|
10
10
|
)
|
|
11
|
-
from infrahub.core.models import SchemaBranchHash # noqa:
|
|
11
|
+
from infrahub.core.models import SchemaBranchHash # noqa: TC001
|
|
12
12
|
from infrahub.core.node.standard import StandardNode
|
|
13
|
+
from infrahub.core.query import QueryType
|
|
13
14
|
from infrahub.core.query.branch import (
|
|
14
15
|
DeleteBranchRelationshipsQuery,
|
|
15
16
|
GetAllBranchInternalRelationshipQuery,
|
|
@@ -139,7 +140,7 @@ class Branch(StandardNode): # pylint: disable=too-many-public-methods
|
|
|
139
140
|
|
|
140
141
|
params = {"name": name}
|
|
141
142
|
|
|
142
|
-
results = await db.execute_query(query=query, params=params, name="branch_get_by_name")
|
|
143
|
+
results = await db.execute_query(query=query, params=params, name="branch_get_by_name", type=QueryType.READ)
|
|
143
144
|
|
|
144
145
|
if len(results) == 0:
|
|
145
146
|
raise BranchNotFoundError(identifier=name)
|