infrahub-server 1.4.10__py3-none-any.whl → 1.5.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/actions/tasks.py +208 -16
- infrahub/api/artifact.py +3 -0
- infrahub/api/diff/diff.py +1 -1
- infrahub/api/query.py +2 -0
- infrahub/api/schema.py +3 -0
- infrahub/auth.py +5 -5
- infrahub/cli/db.py +26 -2
- infrahub/cli/db_commands/clean_duplicate_schema_fields.py +212 -0
- infrahub/config.py +7 -2
- infrahub/core/attribute.py +25 -22
- infrahub/core/branch/models.py +2 -2
- infrahub/core/branch/needs_rebase_status.py +11 -0
- infrahub/core/branch/tasks.py +4 -3
- infrahub/core/changelog/models.py +4 -12
- infrahub/core/constants/__init__.py +1 -0
- infrahub/core/constants/infrahubkind.py +1 -0
- infrahub/core/convert_object_type/object_conversion.py +201 -0
- infrahub/core/convert_object_type/repository_conversion.py +89 -0
- infrahub/core/convert_object_type/schema_mapping.py +27 -3
- infrahub/core/diff/model/path.py +4 -0
- infrahub/core/diff/payload_builder.py +1 -1
- infrahub/core/diff/query/artifact.py +1 -1
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/initialization.py +2 -2
- infrahub/core/ipam/utilization.py +1 -1
- infrahub/core/manager.py +9 -84
- infrahub/core/migrations/graph/__init__.py +6 -0
- infrahub/core/migrations/graph/m040_profile_attrs_in_db.py +166 -0
- infrahub/core/migrations/graph/m041_create_hfid_display_label_in_db.py +97 -0
- infrahub/core/migrations/graph/m042_backfill_hfid_display_label_in_db.py +86 -0
- infrahub/core/migrations/schema/node_attribute_add.py +5 -2
- infrahub/core/migrations/shared.py +5 -6
- infrahub/core/node/__init__.py +165 -42
- infrahub/core/node/constraints/attribute_uniqueness.py +3 -1
- infrahub/core/node/create.py +67 -35
- infrahub/core/node/lock_utils.py +98 -0
- infrahub/core/node/node_property_attribute.py +230 -0
- infrahub/core/node/standard.py +1 -1
- infrahub/core/property.py +11 -0
- infrahub/core/protocols.py +8 -1
- infrahub/core/query/attribute.py +27 -15
- infrahub/core/query/node.py +61 -185
- infrahub/core/query/relationship.py +43 -26
- infrahub/core/query/subquery.py +0 -8
- infrahub/core/registry.py +2 -2
- infrahub/core/relationship/constraints/count.py +1 -1
- infrahub/core/relationship/model.py +60 -20
- infrahub/core/schema/attribute_schema.py +0 -2
- infrahub/core/schema/basenode_schema.py +42 -2
- infrahub/core/schema/definitions/core/__init__.py +2 -0
- infrahub/core/schema/definitions/core/generator.py +2 -0
- infrahub/core/schema/definitions/core/group.py +16 -2
- infrahub/core/schema/definitions/core/repository.py +7 -0
- infrahub/core/schema/definitions/internal.py +14 -1
- infrahub/core/schema/generated/base_node_schema.py +6 -1
- infrahub/core/schema/node_schema.py +5 -2
- infrahub/core/schema/relationship_schema.py +0 -1
- infrahub/core/schema/schema_branch.py +137 -2
- infrahub/core/schema/schema_branch_display.py +123 -0
- infrahub/core/schema/schema_branch_hfid.py +114 -0
- infrahub/core/validators/aggregated_checker.py +1 -1
- infrahub/core/validators/determiner.py +12 -1
- infrahub/core/validators/relationship/peer.py +1 -1
- infrahub/core/validators/tasks.py +1 -1
- infrahub/display_labels/__init__.py +0 -0
- infrahub/display_labels/gather.py +48 -0
- infrahub/display_labels/models.py +240 -0
- infrahub/display_labels/tasks.py +186 -0
- infrahub/display_labels/triggers.py +22 -0
- infrahub/events/group_action.py +1 -1
- infrahub/events/node_action.py +1 -1
- infrahub/generators/constants.py +7 -0
- infrahub/generators/models.py +38 -12
- infrahub/generators/tasks.py +34 -16
- infrahub/git/base.py +38 -1
- infrahub/git/integrator.py +22 -14
- infrahub/graphql/analyzer.py +1 -1
- infrahub/graphql/api/dependencies.py +2 -4
- infrahub/graphql/api/endpoints.py +2 -2
- infrahub/graphql/app.py +2 -4
- infrahub/graphql/initialization.py +2 -3
- infrahub/graphql/manager.py +212 -137
- infrahub/graphql/middleware.py +12 -0
- infrahub/graphql/mutations/branch.py +11 -0
- infrahub/graphql/mutations/computed_attribute.py +110 -3
- infrahub/graphql/mutations/convert_object_type.py +34 -13
- infrahub/graphql/mutations/display_label.py +111 -0
- infrahub/graphql/mutations/generator.py +25 -7
- infrahub/graphql/mutations/hfid.py +118 -0
- infrahub/graphql/mutations/ipam.py +21 -8
- infrahub/graphql/mutations/main.py +37 -153
- infrahub/graphql/mutations/profile.py +195 -0
- infrahub/graphql/mutations/proposed_change.py +2 -1
- infrahub/graphql/mutations/relationship.py +2 -2
- infrahub/graphql/mutations/repository.py +22 -83
- infrahub/graphql/mutations/resource_manager.py +2 -2
- infrahub/graphql/mutations/schema.py +5 -5
- infrahub/graphql/mutations/webhook.py +1 -1
- infrahub/graphql/queries/resource_manager.py +1 -1
- infrahub/graphql/registry.py +173 -0
- infrahub/graphql/resolvers/resolver.py +2 -0
- infrahub/graphql/schema.py +8 -1
- infrahub/groups/tasks.py +1 -1
- infrahub/hfid/__init__.py +0 -0
- infrahub/hfid/gather.py +48 -0
- infrahub/hfid/models.py +240 -0
- infrahub/hfid/tasks.py +185 -0
- infrahub/hfid/triggers.py +22 -0
- infrahub/lock.py +67 -30
- infrahub/locks/__init__.py +0 -0
- infrahub/locks/tasks.py +37 -0
- infrahub/middleware.py +26 -1
- infrahub/patch/plan_writer.py +2 -2
- infrahub/profiles/__init__.py +0 -0
- infrahub/profiles/node_applier.py +101 -0
- infrahub/profiles/queries/__init__.py +0 -0
- infrahub/profiles/queries/get_profile_data.py +99 -0
- infrahub/profiles/tasks.py +63 -0
- infrahub/proposed_change/tasks.py +10 -1
- infrahub/repositories/__init__.py +0 -0
- infrahub/repositories/create_repository.py +113 -0
- infrahub/server.py +16 -3
- infrahub/services/__init__.py +8 -5
- infrahub/tasks/registry.py +6 -4
- infrahub/trigger/catalogue.py +4 -0
- infrahub/trigger/models.py +2 -0
- infrahub/trigger/tasks.py +3 -0
- infrahub/webhook/models.py +1 -1
- infrahub/workflows/catalogue.py +110 -3
- infrahub/workflows/initialization.py +16 -0
- infrahub/workflows/models.py +17 -2
- infrahub_sdk/branch.py +5 -8
- infrahub_sdk/checks.py +1 -1
- infrahub_sdk/client.py +364 -84
- infrahub_sdk/convert_object_type.py +61 -0
- infrahub_sdk/ctl/check.py +2 -3
- infrahub_sdk/ctl/cli_commands.py +18 -12
- infrahub_sdk/ctl/config.py +8 -2
- infrahub_sdk/ctl/generator.py +6 -3
- infrahub_sdk/ctl/graphql.py +184 -0
- infrahub_sdk/ctl/repository.py +39 -1
- infrahub_sdk/ctl/schema.py +18 -3
- infrahub_sdk/ctl/utils.py +4 -0
- infrahub_sdk/ctl/validate.py +5 -3
- infrahub_sdk/diff.py +4 -5
- infrahub_sdk/exceptions.py +2 -0
- infrahub_sdk/generator.py +7 -1
- infrahub_sdk/graphql/__init__.py +12 -0
- infrahub_sdk/graphql/constants.py +1 -0
- infrahub_sdk/graphql/plugin.py +85 -0
- infrahub_sdk/graphql/query.py +77 -0
- infrahub_sdk/{graphql.py → graphql/renderers.py} +88 -75
- infrahub_sdk/graphql/utils.py +40 -0
- infrahub_sdk/node/attribute.py +2 -0
- infrahub_sdk/node/node.py +28 -20
- infrahub_sdk/playback.py +1 -2
- infrahub_sdk/protocols.py +54 -6
- infrahub_sdk/pytest_plugin/plugin.py +7 -4
- infrahub_sdk/pytest_plugin/utils.py +40 -0
- infrahub_sdk/repository.py +1 -2
- infrahub_sdk/schema/__init__.py +38 -0
- infrahub_sdk/schema/main.py +1 -0
- infrahub_sdk/schema/repository.py +8 -0
- infrahub_sdk/spec/object.py +120 -7
- infrahub_sdk/spec/range_expansion.py +118 -0
- infrahub_sdk/timestamp.py +18 -6
- infrahub_sdk/transforms.py +1 -1
- {infrahub_server-1.4.10.dist-info → infrahub_server-1.5.0b1.dist-info}/METADATA +9 -11
- {infrahub_server-1.4.10.dist-info → infrahub_server-1.5.0b1.dist-info}/RECORD +177 -134
- infrahub_testcontainers/container.py +1 -1
- infrahub_testcontainers/docker-compose-cluster.test.yml +1 -1
- infrahub_testcontainers/docker-compose.test.yml +1 -1
- infrahub_testcontainers/models.py +2 -2
- infrahub_testcontainers/performance_test.py +4 -4
- infrahub/core/convert_object_type/conversion.py +0 -134
- {infrahub_server-1.4.10.dist-info → infrahub_server-1.5.0b1.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.4.10.dist-info → infrahub_server-1.5.0b1.dist-info}/WHEEL +0 -0
- {infrahub_server-1.4.10.dist-info → infrahub_server-1.5.0b1.dist-info}/entry_points.txt +0 -0
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import hashlib
|
|
4
3
|
from dataclasses import dataclass, field
|
|
5
4
|
from typing import TYPE_CHECKING, Any
|
|
6
5
|
|
|
7
6
|
from graphene import InputObjectType, Mutation
|
|
8
7
|
from graphene.types.mutation import MutationOptions
|
|
8
|
+
from infrahub_sdk.utils import extract_fields_first_node
|
|
9
9
|
from typing_extensions import Self
|
|
10
10
|
|
|
11
11
|
from infrahub import config, lock
|
|
12
|
-
from infrahub.core.constants import
|
|
12
|
+
from infrahub.core.constants import MutationAction
|
|
13
13
|
from infrahub.core.constraint.node.runner import NodeConstraintRunner
|
|
14
14
|
from infrahub.core.manager import NodeManager
|
|
15
|
-
from infrahub.core.node.create import
|
|
16
|
-
create_node,
|
|
17
|
-
get_profile_ids,
|
|
18
|
-
refresh_for_profile_update,
|
|
19
|
-
)
|
|
15
|
+
from infrahub.core.node.create import create_node, get_profile_ids
|
|
20
16
|
from infrahub.core.schema import MainSchemaTypes, NodeSchema
|
|
21
17
|
from infrahub.core.schema.generic_schema import GenericSchema
|
|
22
18
|
from infrahub.core.schema.profile_schema import ProfileSchema
|
|
@@ -28,9 +24,11 @@ from infrahub.events.generator import generate_node_mutation_events
|
|
|
28
24
|
from infrahub.exceptions import HFIDViolatedError, InitializationError, NodeNotFoundError
|
|
29
25
|
from infrahub.graphql.context import apply_external_context
|
|
30
26
|
from infrahub.graphql.field_extractor import extract_graphql_fields
|
|
31
|
-
from infrahub.lock import InfrahubMultiLock
|
|
27
|
+
from infrahub.lock import InfrahubMultiLock
|
|
32
28
|
from infrahub.log import get_log_data, get_logger
|
|
29
|
+
from infrahub.profiles.node_applier import NodeProfilesApplier
|
|
33
30
|
|
|
31
|
+
from ...core.node.lock_utils import get_kind_lock_names_on_object_mutation
|
|
34
32
|
from .node_getter.by_default_filter import MutationNodeGetterByDefaultFilter
|
|
35
33
|
|
|
36
34
|
if TYPE_CHECKING:
|
|
@@ -38,7 +36,6 @@ if TYPE_CHECKING:
|
|
|
38
36
|
|
|
39
37
|
from infrahub.core.branch import Branch
|
|
40
38
|
from infrahub.core.node import Node
|
|
41
|
-
from infrahub.core.schema.schema_branch import SchemaBranch
|
|
42
39
|
from infrahub.database import InfrahubDatabase
|
|
43
40
|
from infrahub.graphql.types.context import ContextInput
|
|
44
41
|
|
|
@@ -47,8 +44,6 @@ if TYPE_CHECKING:
|
|
|
47
44
|
|
|
48
45
|
log = get_logger()
|
|
49
46
|
|
|
50
|
-
KINDS_CONCURRENT_MUTATIONS_NOT_ALLOWED = [InfrahubKind.GENERICGROUP]
|
|
51
|
-
|
|
52
47
|
|
|
53
48
|
@dataclass
|
|
54
49
|
class DeleteResult:
|
|
@@ -146,23 +141,6 @@ class InfrahubMutationMixin:
|
|
|
146
141
|
|
|
147
142
|
return mutation
|
|
148
143
|
|
|
149
|
-
@classmethod
|
|
150
|
-
async def _call_mutate_create_object(
|
|
151
|
-
cls, data: InputObjectType, db: InfrahubDatabase, branch: Branch, override_data: dict[str, Any] | None = None
|
|
152
|
-
) -> Node:
|
|
153
|
-
"""
|
|
154
|
-
Wrapper around mutate_create_object to potentially activate locking.
|
|
155
|
-
"""
|
|
156
|
-
schema_branch = db.schema.get_schema_branch(name=branch.name)
|
|
157
|
-
lock_names = _get_kind_lock_names_on_object_mutation(
|
|
158
|
-
kind=cls._meta.active_schema.kind, branch=branch, schema_branch=schema_branch, data=data
|
|
159
|
-
)
|
|
160
|
-
if lock_names:
|
|
161
|
-
async with InfrahubMultiLock(lock_registry=lock.registry, locks=lock_names):
|
|
162
|
-
return await cls.mutate_create_object(data=data, db=db, branch=branch, override_data=override_data)
|
|
163
|
-
|
|
164
|
-
return await cls.mutate_create_object(data=data, db=db, branch=branch, override_data=override_data)
|
|
165
|
-
|
|
166
144
|
@classmethod
|
|
167
145
|
async def mutate_create(
|
|
168
146
|
cls,
|
|
@@ -172,40 +150,21 @@ class InfrahubMutationMixin:
|
|
|
172
150
|
database: InfrahubDatabase | None = None,
|
|
173
151
|
override_data: dict[str, Any] | None = None,
|
|
174
152
|
) -> tuple[Node, Self]:
|
|
175
|
-
|
|
176
|
-
db = database or graphql_context.db
|
|
177
|
-
obj = await cls._call_mutate_create_object(data=data, db=db, branch=branch, override_data=override_data)
|
|
178
|
-
result = await cls.mutate_create_to_graphql(info=info, db=db, obj=obj)
|
|
179
|
-
return obj, result
|
|
180
|
-
|
|
181
|
-
@classmethod
|
|
182
|
-
@retry_db_transaction(name="object_create")
|
|
183
|
-
async def mutate_create_object(
|
|
184
|
-
cls,
|
|
185
|
-
data: InputObjectType,
|
|
186
|
-
db: InfrahubDatabase,
|
|
187
|
-
branch: Branch,
|
|
188
|
-
override_data: dict[str, Any] | None = None,
|
|
189
|
-
) -> Node:
|
|
153
|
+
db = database or info.context.db
|
|
190
154
|
schema = cls._meta.active_schema
|
|
191
|
-
|
|
192
|
-
raise ValueError(f"Node of generic schema `{schema.name=}` can not be instantiated.")
|
|
155
|
+
|
|
193
156
|
create_data = dict(data)
|
|
194
157
|
create_data.update(override_data or {})
|
|
195
|
-
|
|
158
|
+
|
|
159
|
+
obj = await create_node(
|
|
196
160
|
data=create_data,
|
|
197
161
|
db=db,
|
|
198
162
|
branch=branch,
|
|
199
163
|
schema=schema,
|
|
200
164
|
)
|
|
201
165
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
fields = extract_graphql_fields(info=info)
|
|
205
|
-
result: dict[str, Any] = {"ok": True}
|
|
206
|
-
if "object" in fields:
|
|
207
|
-
result["object"] = await obj.to_graphql(db=db, fields=fields.get("object", {}))
|
|
208
|
-
return cls(**result)
|
|
166
|
+
graphql_response = await build_graphql_response(info=info, db=db, obj=obj)
|
|
167
|
+
return obj, cls(**graphql_response)
|
|
209
168
|
|
|
210
169
|
@classmethod
|
|
211
170
|
async def _call_mutate_update(
|
|
@@ -222,8 +181,8 @@ class InfrahubMutationMixin:
|
|
|
222
181
|
"""
|
|
223
182
|
|
|
224
183
|
schema_branch = db.schema.get_schema_branch(name=branch.name)
|
|
225
|
-
lock_names =
|
|
226
|
-
kind=cls._meta.active_schema.kind, branch=branch, schema_branch=schema_branch, data=data
|
|
184
|
+
lock_names = get_kind_lock_names_on_object_mutation(
|
|
185
|
+
kind=cls._meta.active_schema.kind, branch=branch, schema_branch=schema_branch, data=dict(data)
|
|
227
186
|
)
|
|
228
187
|
|
|
229
188
|
if db.is_transaction:
|
|
@@ -290,7 +249,6 @@ class InfrahubMutationMixin:
|
|
|
290
249
|
component_registry = get_component_registry()
|
|
291
250
|
node_constraint_runner = await component_registry.get_component(NodeConstraintRunner, db=db, branch=branch)
|
|
292
251
|
|
|
293
|
-
before_mutate_profile_ids = await get_profile_ids(db=db, obj=obj)
|
|
294
252
|
await obj.from_graphql(db=db, data=data)
|
|
295
253
|
fields_to_validate = list(data)
|
|
296
254
|
await node_constraint_runner.check(
|
|
@@ -302,15 +260,13 @@ class InfrahubMutationMixin:
|
|
|
302
260
|
if field_to_remove in fields:
|
|
303
261
|
fields.remove(field_to_remove)
|
|
304
262
|
|
|
263
|
+
after_mutate_profile_ids = await get_profile_ids(db=db, obj=obj)
|
|
264
|
+
if after_mutate_profile_ids or (not after_mutate_profile_ids and obj.uses_profiles()):
|
|
265
|
+
node_profiles_applier = NodeProfilesApplier(db=db, branch=branch)
|
|
266
|
+
updated_field_names = await node_profiles_applier.apply_profiles(node=obj)
|
|
267
|
+
fields += updated_field_names
|
|
305
268
|
await obj.save(db=db, fields=fields)
|
|
306
269
|
|
|
307
|
-
obj = await refresh_for_profile_update(
|
|
308
|
-
db=db,
|
|
309
|
-
branch=branch,
|
|
310
|
-
obj=obj,
|
|
311
|
-
previous_profile_ids=before_mutate_profile_ids,
|
|
312
|
-
schema=cls._meta.active_schema,
|
|
313
|
-
)
|
|
314
270
|
return obj
|
|
315
271
|
|
|
316
272
|
@classmethod
|
|
@@ -422,6 +378,15 @@ class InfrahubMutationMixin:
|
|
|
422
378
|
)
|
|
423
379
|
return updated_obj, mutation, False
|
|
424
380
|
|
|
381
|
+
@classmethod
|
|
382
|
+
async def _delete_obj(cls, graphql_context: GraphqlContext, branch: Branch, obj: Node) -> list[Node]:
|
|
383
|
+
db = graphql_context.db
|
|
384
|
+
async with db.start_transaction() as dbt:
|
|
385
|
+
deleted = await NodeManager.delete(db=dbt, branch=branch, nodes=[obj])
|
|
386
|
+
deleted_str = ", ".join([f"{d.get_kind()}({d.get_id()})" for d in deleted])
|
|
387
|
+
log.info(f"nodes deleted: {deleted_str}")
|
|
388
|
+
return deleted
|
|
389
|
+
|
|
425
390
|
@classmethod
|
|
426
391
|
@retry_db_transaction(name="object_delete")
|
|
427
392
|
async def mutate_delete(
|
|
@@ -440,11 +405,7 @@ class InfrahubMutationMixin:
|
|
|
440
405
|
branch=branch,
|
|
441
406
|
)
|
|
442
407
|
|
|
443
|
-
|
|
444
|
-
deleted = await NodeManager.delete(db=db, branch=branch, nodes=[obj])
|
|
445
|
-
|
|
446
|
-
deleted_str = ", ".join([f"{d.get_kind()}({d.get_id()})" for d in deleted])
|
|
447
|
-
log.info(f"nodes deleted: {deleted_str}")
|
|
408
|
+
deleted = await cls._delete_obj(graphql_context=graphql_context, branch=branch, obj=obj)
|
|
448
409
|
|
|
449
410
|
ok = True
|
|
450
411
|
|
|
@@ -471,90 +432,13 @@ class InfrahubMutation(InfrahubMutationMixin, Mutation):
|
|
|
471
432
|
super().__init_subclass_with_meta__(_meta=_meta, **options)
|
|
472
433
|
|
|
473
434
|
|
|
474
|
-
def _get_kinds_to_lock_on_object_mutation(kind: str, schema_branch: SchemaBranch) -> list[str]:
|
|
475
|
-
"""
|
|
476
|
-
Return kinds for which we want to lock during creating / updating an object of a given schema node.
|
|
477
|
-
Lock should be performed on schema kind and its generics having a uniqueness_constraint defined.
|
|
478
|
-
If a generic uniqueness constraint is the same as the node schema one,
|
|
479
|
-
it means node schema overrided this constraint, in which case we only need to lock on the generic.
|
|
480
|
-
"""
|
|
481
|
-
|
|
482
|
-
node_schema = schema_branch.get(name=kind)
|
|
483
|
-
|
|
484
|
-
schema_uc = None
|
|
485
|
-
kinds = []
|
|
486
|
-
if node_schema.uniqueness_constraints:
|
|
487
|
-
kinds.append(node_schema.kind)
|
|
488
|
-
schema_uc = node_schema.uniqueness_constraints
|
|
489
|
-
|
|
490
|
-
if node_schema.is_generic_schema:
|
|
491
|
-
return kinds
|
|
492
|
-
|
|
493
|
-
generics_kinds = node_schema.inherit_from
|
|
494
|
-
|
|
495
|
-
node_schema_kind_removed = False
|
|
496
|
-
for generic_kind in generics_kinds:
|
|
497
|
-
generic_uc = schema_branch.get(name=generic_kind).uniqueness_constraints
|
|
498
|
-
if generic_uc:
|
|
499
|
-
kinds.append(generic_kind)
|
|
500
|
-
if not node_schema_kind_removed and generic_uc == schema_uc:
|
|
501
|
-
# Check whether we should remove original schema kind as it simply overrides uniqueness_constraint
|
|
502
|
-
# of a generic
|
|
503
|
-
kinds.pop(0)
|
|
504
|
-
node_schema_kind_removed = True
|
|
505
|
-
return kinds
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
def _should_kind_be_locked_on_any_branch(kind: str, schema_branch: SchemaBranch) -> bool:
|
|
509
|
-
"""
|
|
510
|
-
Check whether kind or any kind generic is in KINDS_TO_LOCK_ON_ANY_BRANCH.
|
|
511
|
-
"""
|
|
512
|
-
|
|
513
|
-
if kind in KINDS_CONCURRENT_MUTATIONS_NOT_ALLOWED:
|
|
514
|
-
return True
|
|
515
|
-
|
|
516
|
-
node_schema = schema_branch.get(name=kind)
|
|
517
|
-
if node_schema.is_generic_schema:
|
|
518
|
-
return False
|
|
519
|
-
|
|
520
|
-
for generic_kind in node_schema.inherit_from:
|
|
521
|
-
if generic_kind in KINDS_CONCURRENT_MUTATIONS_NOT_ALLOWED:
|
|
522
|
-
return True
|
|
523
|
-
return False
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
def _hash(value: str) -> str:
|
|
527
|
-
# Do not use builtin `hash` for lock names as due to randomization results would differ between
|
|
528
|
-
# different processes.
|
|
529
|
-
return hashlib.sha256(value.encode()).hexdigest()
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
def _get_kind_lock_names_on_object_mutation(
|
|
533
|
-
kind: str, branch: Branch, schema_branch: SchemaBranch, data: InputObjectType
|
|
534
|
-
) -> list[str]:
|
|
535
|
-
"""
|
|
536
|
-
Return objects kind for which we want to avoid concurrent mutation (create/update). Except for some specific kinds,
|
|
537
|
-
concurrent mutations are only allowed on non-main branch as objects validations will be performed at least when merging in main branch.
|
|
538
|
-
"""
|
|
539
|
-
|
|
540
|
-
if not branch.is_default and not _should_kind_be_locked_on_any_branch(kind=kind, schema_branch=schema_branch):
|
|
541
|
-
return []
|
|
542
|
-
|
|
543
|
-
if kind == InfrahubKind.GRAPHQLQUERYGROUP:
|
|
544
|
-
# Lock on name as well to improve performances
|
|
545
|
-
try:
|
|
546
|
-
name = data.name.value
|
|
547
|
-
return [build_object_lock_name(kind + "." + _hash(name))]
|
|
548
|
-
except AttributeError:
|
|
549
|
-
# We might reach here if we are updating a CoreGraphQLQueryGroup without updating the name,
|
|
550
|
-
# in which case we would not need to lock. This is not supposed to happen as current `update`
|
|
551
|
-
# logic first fetches the node with its name.
|
|
552
|
-
return []
|
|
553
|
-
|
|
554
|
-
lock_kinds = _get_kinds_to_lock_on_object_mutation(kind, schema_branch)
|
|
555
|
-
lock_names = [build_object_lock_name(kind) for kind in lock_kinds]
|
|
556
|
-
return lock_names
|
|
557
|
-
|
|
558
|
-
|
|
559
435
|
def _get_data_fields(data: InputObjectType) -> list[str]:
|
|
560
436
|
return [field for field in data.keys() if field not in ["id", "hfid"]]
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
async def build_graphql_response(info: GraphQLResolveInfo, db: InfrahubDatabase, obj: Node) -> dict:
|
|
440
|
+
fields = await extract_fields_first_node(info)
|
|
441
|
+
result: dict[str, Any] = {"ok": True}
|
|
442
|
+
if "object" in fields:
|
|
443
|
+
result["object"] = await obj.to_graphql(db=db, fields=fields.get("object", {}))
|
|
444
|
+
return result
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from graphene import Boolean, InputObjectType, Mutation, String
|
|
6
|
+
from graphql import GraphQLResolveInfo
|
|
7
|
+
from opentelemetry import trace
|
|
8
|
+
from typing_extensions import Self
|
|
9
|
+
|
|
10
|
+
from infrahub.core.manager import NodeManager
|
|
11
|
+
from infrahub.core.schema import ProfileSchema
|
|
12
|
+
from infrahub.graphql.types.context import ContextInput
|
|
13
|
+
from infrahub.log import get_logger
|
|
14
|
+
from infrahub.profiles.node_applier import NodeProfilesApplier
|
|
15
|
+
from infrahub.workflows.catalogue import PROFILE_REFRESH_MULTIPLE
|
|
16
|
+
|
|
17
|
+
from .main import InfrahubMutationMixin, InfrahubMutationOptions
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from graphql import GraphQLResolveInfo
|
|
21
|
+
|
|
22
|
+
from infrahub.core.branch import Branch
|
|
23
|
+
from infrahub.core.node import Node
|
|
24
|
+
from infrahub.database import InfrahubDatabase
|
|
25
|
+
from infrahub.graphql.initialization import GraphqlContext
|
|
26
|
+
from infrahub.services.adapters.workflow import InfrahubWorkflow
|
|
27
|
+
|
|
28
|
+
log = get_logger()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class InfrahubProfileMutation(InfrahubMutationMixin, Mutation):
|
|
32
|
+
@classmethod
|
|
33
|
+
def __init_subclass_with_meta__(
|
|
34
|
+
cls,
|
|
35
|
+
schema: ProfileSchema,
|
|
36
|
+
_meta: InfrahubMutationOptions | None = None,
|
|
37
|
+
**options: dict[str, Any],
|
|
38
|
+
) -> None:
|
|
39
|
+
# Make sure schema is a valid NodeSchema Node Class
|
|
40
|
+
if not isinstance(schema, ProfileSchema):
|
|
41
|
+
raise ValueError(f"You need to pass a valid ProfileSchema in '{cls.__name__}.Meta', received '{schema}'")
|
|
42
|
+
|
|
43
|
+
if not _meta:
|
|
44
|
+
_meta = InfrahubMutationOptions(cls)
|
|
45
|
+
_meta.schema = schema
|
|
46
|
+
|
|
47
|
+
super().__init_subclass_with_meta__(_meta=_meta, **options)
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
async def _send_profile_refresh_workflows(
|
|
51
|
+
cls,
|
|
52
|
+
db: InfrahubDatabase,
|
|
53
|
+
workflow_service: InfrahubWorkflow,
|
|
54
|
+
branch_name: str,
|
|
55
|
+
obj: Node,
|
|
56
|
+
node_ids: list[str] | None = None,
|
|
57
|
+
) -> None:
|
|
58
|
+
if not node_ids:
|
|
59
|
+
related_nodes = await obj.related_nodes.get_relationships(db=db) # type: ignore[attr-defined]
|
|
60
|
+
node_ids = [rel.peer_id for rel in related_nodes]
|
|
61
|
+
if node_ids:
|
|
62
|
+
await workflow_service.submit_workflow(
|
|
63
|
+
workflow=PROFILE_REFRESH_MULTIPLE,
|
|
64
|
+
parameters={
|
|
65
|
+
"branch_name": branch_name,
|
|
66
|
+
"node_ids": node_ids,
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def _get_profile_attr_values_map(cls, obj: Node) -> dict[str, Any]:
|
|
72
|
+
attr_values_map = {}
|
|
73
|
+
for attr_schema in obj.get_schema().attributes:
|
|
74
|
+
# profile name update can be ignored
|
|
75
|
+
if attr_schema.name == "profile_name":
|
|
76
|
+
continue
|
|
77
|
+
attr_values_map[attr_schema.name] = getattr(obj, attr_schema.name).value
|
|
78
|
+
return attr_values_map
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
async def _get_profile_related_node_ids(cls, db: InfrahubDatabase, obj: Node) -> set[str]:
|
|
82
|
+
related_nodes = await obj.related_nodes.get_relationships(db=db) # type: ignore[attr-defined]
|
|
83
|
+
if related_nodes:
|
|
84
|
+
related_node_ids = {rel.peer_id for rel in related_nodes}
|
|
85
|
+
else:
|
|
86
|
+
related_node_ids = set()
|
|
87
|
+
return related_node_ids
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
async def mutate_create(
|
|
91
|
+
cls,
|
|
92
|
+
info: GraphQLResolveInfo,
|
|
93
|
+
data: InputObjectType,
|
|
94
|
+
branch: Branch,
|
|
95
|
+
database: InfrahubDatabase | None = None,
|
|
96
|
+
override_data: dict[str, Any] | None = None,
|
|
97
|
+
) -> tuple[Node, Self]:
|
|
98
|
+
graphql_context: GraphqlContext = info.context
|
|
99
|
+
db = database or graphql_context.db
|
|
100
|
+
workflow_service = graphql_context.active_service.workflow
|
|
101
|
+
|
|
102
|
+
obj, mutation = await super().mutate_create(
|
|
103
|
+
info=info, data=data, branch=branch, database=database, override_data=override_data
|
|
104
|
+
)
|
|
105
|
+
await cls._send_profile_refresh_workflows(
|
|
106
|
+
db=db, workflow_service=workflow_service, branch_name=branch.name, obj=obj
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return obj, mutation
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
async def _call_mutate_update(
|
|
113
|
+
cls,
|
|
114
|
+
info: GraphQLResolveInfo,
|
|
115
|
+
data: InputObjectType,
|
|
116
|
+
branch: Branch,
|
|
117
|
+
db: InfrahubDatabase,
|
|
118
|
+
obj: Node,
|
|
119
|
+
skip_uniqueness_check: bool = False,
|
|
120
|
+
) -> tuple[Node, Self]:
|
|
121
|
+
workflow_service = info.context.active_service.workflow
|
|
122
|
+
original_attr_values = cls._get_profile_attr_values_map(obj=obj)
|
|
123
|
+
original_related_node_ids = await cls._get_profile_related_node_ids(db=db, obj=obj)
|
|
124
|
+
|
|
125
|
+
obj, mutation = await super()._call_mutate_update(
|
|
126
|
+
info=info, data=data, branch=branch, db=db, obj=obj, skip_uniqueness_check=skip_uniqueness_check
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
updated_attr_values = cls._get_profile_attr_values_map(obj=obj)
|
|
130
|
+
updated_related_node_ids = await cls._get_profile_related_node_ids(db=db, obj=obj)
|
|
131
|
+
|
|
132
|
+
if original_attr_values != updated_attr_values:
|
|
133
|
+
await cls._send_profile_refresh_workflows(
|
|
134
|
+
db=db, workflow_service=workflow_service, branch_name=branch.name, obj=obj
|
|
135
|
+
)
|
|
136
|
+
elif updated_related_node_ids != original_related_node_ids:
|
|
137
|
+
removed_node_ids = original_related_node_ids - updated_related_node_ids
|
|
138
|
+
added_node_ids = updated_related_node_ids - original_related_node_ids
|
|
139
|
+
await cls._send_profile_refresh_workflows(
|
|
140
|
+
db=db,
|
|
141
|
+
workflow_service=workflow_service,
|
|
142
|
+
branch_name=branch.name,
|
|
143
|
+
obj=obj,
|
|
144
|
+
node_ids=list(removed_node_ids) + list(added_node_ids),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return obj, mutation
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
async def _delete_obj(cls, graphql_context: GraphqlContext, branch: Branch, obj: Node) -> list[Node]:
|
|
151
|
+
db = graphql_context.db
|
|
152
|
+
workflow_service = graphql_context.active_service.workflow
|
|
153
|
+
related_node_ids = await cls._get_profile_related_node_ids(db=db, obj=obj)
|
|
154
|
+
deleted = await super()._delete_obj(graphql_context=graphql_context, branch=branch, obj=obj)
|
|
155
|
+
await cls._send_profile_refresh_workflows(
|
|
156
|
+
db=db, workflow_service=workflow_service, branch_name=branch.name, obj=obj, node_ids=list(related_node_ids)
|
|
157
|
+
)
|
|
158
|
+
return deleted
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class ProfilesRefreshInput(InputObjectType):
|
|
162
|
+
id = String(required=False)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class InfrahubProfilesRefresh(Mutation):
|
|
166
|
+
class Arguments:
|
|
167
|
+
data = ProfilesRefreshInput(required=True)
|
|
168
|
+
context = ContextInput(required=False)
|
|
169
|
+
|
|
170
|
+
ok = Boolean()
|
|
171
|
+
|
|
172
|
+
@classmethod
|
|
173
|
+
@trace.get_tracer(__name__).start_as_current_span("profiles_refresh")
|
|
174
|
+
async def mutate(
|
|
175
|
+
cls,
|
|
176
|
+
root: dict, # noqa: ARG003
|
|
177
|
+
info: GraphQLResolveInfo,
|
|
178
|
+
data: ProfilesRefreshInput,
|
|
179
|
+
context: ContextInput | None = None, # noqa: ARG003
|
|
180
|
+
) -> Self:
|
|
181
|
+
graphql_context: GraphqlContext = info.context
|
|
182
|
+
db = graphql_context.db
|
|
183
|
+
branch = graphql_context.branch
|
|
184
|
+
obj = await NodeManager.get_one(
|
|
185
|
+
db=db,
|
|
186
|
+
branch=branch,
|
|
187
|
+
id=str(data.id),
|
|
188
|
+
include_source=True,
|
|
189
|
+
)
|
|
190
|
+
node_profiles_applier = NodeProfilesApplier(db=db, branch=branch)
|
|
191
|
+
updated_fields = await node_profiles_applier.apply_profiles(node=obj)
|
|
192
|
+
if updated_fields:
|
|
193
|
+
await obj.save(db=db, fields=updated_fields)
|
|
194
|
+
|
|
195
|
+
return cls(ok=True)
|
|
@@ -29,13 +29,14 @@ from infrahub.exceptions import BranchNotFoundError, PermissionDeniedError, Vali
|
|
|
29
29
|
from infrahub.graphql.mutations.main import InfrahubMutationMixin
|
|
30
30
|
from infrahub.graphql.types.enums import CheckType as GraphQLCheckType
|
|
31
31
|
from infrahub.graphql.types.task import TaskInfo
|
|
32
|
-
from infrahub.lock import InfrahubLock
|
|
32
|
+
from infrahub.lock import InfrahubLock
|
|
33
33
|
from infrahub.proposed_change.approval_revoker import do_revoke_approvals_on_updated_pcs
|
|
34
34
|
from infrahub.proposed_change.constants import ProposedChangeApprovalDecision, ProposedChangeState
|
|
35
35
|
from infrahub.proposed_change.models import RequestProposedChangePipeline
|
|
36
36
|
from infrahub.workers.dependencies import get_event_service
|
|
37
37
|
from infrahub.workflows.catalogue import PROPOSED_CHANGE_MERGE, REQUEST_PROPOSED_CHANGE_PIPELINE
|
|
38
38
|
|
|
39
|
+
from ...core.node.lock_utils import build_object_lock_name
|
|
39
40
|
from .main import InfrahubMutationOptions
|
|
40
41
|
|
|
41
42
|
if TYPE_CHECKING:
|
|
@@ -91,7 +91,7 @@ class RelationshipAdd(Mutation):
|
|
|
91
91
|
await apply_external_context(graphql_context=graphql_context, context_input=context)
|
|
92
92
|
|
|
93
93
|
rel_schema = source.get_schema().get_relationship(name=relationship_name)
|
|
94
|
-
display_label: str = await source.
|
|
94
|
+
display_label: str = await source.get_display_label(db=graphql_context.db) or ""
|
|
95
95
|
node_changelog = NodeChangelog(
|
|
96
96
|
node_id=source.get_id(), node_kind=source.get_kind(), display_label=display_label
|
|
97
97
|
)
|
|
@@ -214,7 +214,7 @@ class RelationshipRemove(Mutation):
|
|
|
214
214
|
await apply_external_context(graphql_context=graphql_context, context_input=context)
|
|
215
215
|
|
|
216
216
|
rel_schema = source.get_schema().get_relationship(name=relationship_name)
|
|
217
|
-
display_label: str = await source.
|
|
217
|
+
display_label: str = await source.get_display_label(db=graphql_context.db) or ""
|
|
218
218
|
node_changelog = NodeChangelog(
|
|
219
219
|
node_id=source.get_id(), node_kind=source.get_kind(), display_label=display_label
|
|
220
220
|
)
|
|
@@ -7,14 +7,11 @@ import httpx
|
|
|
7
7
|
from graphene import Boolean, Field, InputObjectType, Mutation, String
|
|
8
8
|
|
|
9
9
|
from infrahub import config
|
|
10
|
-
from infrahub.core.constants import InfrahubKind
|
|
10
|
+
from infrahub.core.constants import InfrahubKind
|
|
11
11
|
from infrahub.core.manager import NodeManager
|
|
12
|
-
from infrahub.core.protocols import
|
|
12
|
+
from infrahub.core.protocols import CoreReadOnlyRepository, CoreRepository
|
|
13
13
|
from infrahub.core.schema import NodeSchema
|
|
14
|
-
from infrahub.exceptions import ValidationError
|
|
15
14
|
from infrahub.git.models import (
|
|
16
|
-
GitRepositoryAdd,
|
|
17
|
-
GitRepositoryAddReadOnly,
|
|
18
15
|
GitRepositoryImportObjects,
|
|
19
16
|
GitRepositoryPullReadOnly,
|
|
20
17
|
)
|
|
@@ -22,15 +19,15 @@ from infrahub.graphql.types.common import IdentifierInput
|
|
|
22
19
|
from infrahub.log import get_logger
|
|
23
20
|
from infrahub.message_bus import messages
|
|
24
21
|
from infrahub.message_bus.messages.git_repository_connectivity import GitRepositoryConnectivityResponse
|
|
22
|
+
from infrahub.repositories.create_repository import RepositoryFinalizer
|
|
25
23
|
from infrahub.workflows.catalogue import (
|
|
26
24
|
GIT_REPOSITORIES_IMPORT_OBJECTS,
|
|
27
25
|
GIT_REPOSITORIES_PULL_READ_ONLY,
|
|
28
|
-
GIT_REPOSITORY_ADD,
|
|
29
|
-
GIT_REPOSITORY_ADD_READ_ONLY,
|
|
30
26
|
)
|
|
31
27
|
|
|
28
|
+
from ...core.node.create import create_node
|
|
32
29
|
from ..types.task import TaskInfo
|
|
33
|
-
from .main import InfrahubMutationMixin, InfrahubMutationOptions
|
|
30
|
+
from .main import InfrahubMutationMixin, InfrahubMutationOptions, build_graphql_response
|
|
34
31
|
|
|
35
32
|
if TYPE_CHECKING:
|
|
36
33
|
from graphql import GraphQLResolveInfo
|
|
@@ -63,86 +60,28 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
|
|
|
63
60
|
info: GraphQLResolveInfo,
|
|
64
61
|
data: InputObjectType,
|
|
65
62
|
branch: Branch,
|
|
66
|
-
database: InfrahubDatabase | None = None,
|
|
63
|
+
database: InfrahubDatabase | None = None,
|
|
67
64
|
override_data: dict[str, Any] | None = None,
|
|
68
65
|
) -> tuple[Node, Self]:
|
|
69
66
|
graphql_context: GraphqlContext = info.context
|
|
70
|
-
|
|
71
67
|
cleanup_payload(data)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if response.data.success is False:
|
|
88
|
-
await obj.delete(db=graphql_context.db)
|
|
89
|
-
raise ValidationError(response.data.message)
|
|
90
|
-
|
|
91
|
-
# If we are in the default branch, we set the sync status to Active
|
|
92
|
-
# If we are in another branch, we set the sync status to Staging
|
|
93
|
-
if branch.is_default:
|
|
94
|
-
obj.internal_status.value = RepositoryInternalStatus.ACTIVE.value
|
|
95
|
-
else:
|
|
96
|
-
obj.internal_status.value = RepositoryInternalStatus.STAGING.value
|
|
97
|
-
await obj.save(db=graphql_context.db)
|
|
98
|
-
|
|
99
|
-
# Create the new repository in the filesystem.
|
|
100
|
-
log.info("create_repository", name=obj.name.value)
|
|
101
|
-
authenticated_user = None
|
|
102
|
-
if graphql_context.account_session and graphql_context.account_session.authenticated:
|
|
103
|
-
authenticated_user = graphql_context.account_session.account_id
|
|
104
|
-
if obj.get_kind() == InfrahubKind.READONLYREPOSITORY:
|
|
105
|
-
obj = cast(CoreReadOnlyRepository, obj)
|
|
106
|
-
model = GitRepositoryAddReadOnly(
|
|
107
|
-
repository_id=obj.id,
|
|
108
|
-
repository_name=obj.name.value,
|
|
109
|
-
location=obj.location.value,
|
|
110
|
-
ref=obj.ref.value,
|
|
111
|
-
infrahub_branch_name=branch.name,
|
|
112
|
-
infrahub_branch_id=str(branch.get_uuid()),
|
|
113
|
-
internal_status=obj.internal_status.value,
|
|
114
|
-
created_by=authenticated_user,
|
|
115
|
-
)
|
|
116
|
-
if graphql_context.service:
|
|
117
|
-
await graphql_context.service.workflow.submit_workflow(
|
|
118
|
-
workflow=GIT_REPOSITORY_ADD_READ_ONLY,
|
|
119
|
-
context=graphql_context.get_context(),
|
|
120
|
-
parameters={"model": model},
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
else:
|
|
124
|
-
obj = cast(CoreRepository, obj)
|
|
125
|
-
git_repo_add_model = GitRepositoryAdd(
|
|
126
|
-
repository_id=obj.id,
|
|
127
|
-
repository_name=obj.name.value,
|
|
128
|
-
location=obj.location.value,
|
|
129
|
-
default_branch_name=obj.default_branch.value,
|
|
130
|
-
infrahub_branch_name=branch.name,
|
|
131
|
-
infrahub_branch_id=str(branch.get_uuid()),
|
|
132
|
-
internal_status=obj.internal_status.value,
|
|
133
|
-
created_by=authenticated_user,
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
if graphql_context.service:
|
|
137
|
-
await graphql_context.service.workflow.submit_workflow(
|
|
138
|
-
workflow=GIT_REPOSITORY_ADD,
|
|
139
|
-
context=graphql_context.get_context(),
|
|
140
|
-
parameters={"model": git_repo_add_model},
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
# TODO Validate that the creation of the repository went as expected
|
|
68
|
+
db = database or graphql_context.db
|
|
69
|
+
create_data = dict(data)
|
|
70
|
+
create_data.update(override_data or {})
|
|
71
|
+
obj = await create_node(data=create_data, db=db, branch=branch, schema=cls._meta.active_schema)
|
|
72
|
+
|
|
73
|
+
await RepositoryFinalizer(
|
|
74
|
+
account_session=graphql_context.active_account_session,
|
|
75
|
+
services=graphql_context.active_service,
|
|
76
|
+
context=graphql_context.get_context(),
|
|
77
|
+
).post_create(
|
|
78
|
+
obj=obj, # type: ignore
|
|
79
|
+
branch=branch,
|
|
80
|
+
db=db,
|
|
81
|
+
)
|
|
144
82
|
|
|
145
|
-
|
|
83
|
+
graphql_response = await build_graphql_response(info=info, db=db, obj=obj)
|
|
84
|
+
return obj, cls(**graphql_response)
|
|
146
85
|
|
|
147
86
|
@classmethod
|
|
148
87
|
async def mutate_update(
|
|
@@ -98,7 +98,7 @@ class IPPrefixPoolGetResource(Mutation):
|
|
|
98
98
|
"id": resource.id,
|
|
99
99
|
"kind": resource.get_kind(),
|
|
100
100
|
"identifier": data.get("identifier", None),
|
|
101
|
-
"display_label": await resource.
|
|
101
|
+
"display_label": await resource.get_display_label(db=graphql_context.db),
|
|
102
102
|
"branch": graphql_context.branch.name,
|
|
103
103
|
},
|
|
104
104
|
}
|
|
@@ -144,7 +144,7 @@ class IPAddressPoolGetResource(Mutation):
|
|
|
144
144
|
"id": resource.id,
|
|
145
145
|
"kind": resource.get_kind(),
|
|
146
146
|
"identifier": data.get("identifier"),
|
|
147
|
-
"display_label": await resource.
|
|
147
|
+
"display_label": await resource.get_display_label(db=graphql_context.db),
|
|
148
148
|
"branch": graphql_context.branch.name,
|
|
149
149
|
},
|
|
150
150
|
}
|