infrahub-server 1.3.5__py3-none-any.whl → 1.4.0b0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- infrahub/api/internal.py +5 -0
- infrahub/artifacts/tasks.py +17 -22
- infrahub/branch/merge_mutation_checker.py +38 -0
- infrahub/cli/__init__.py +2 -2
- infrahub/cli/context.py +7 -3
- infrahub/cli/db.py +5 -16
- infrahub/cli/upgrade.py +7 -29
- infrahub/computed_attribute/tasks.py +36 -46
- infrahub/config.py +53 -2
- infrahub/constants/environment.py +1 -0
- infrahub/core/attribute.py +9 -7
- infrahub/core/branch/tasks.py +43 -41
- infrahub/core/constants/__init__.py +20 -6
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/diff/coordinator.py +3 -1
- infrahub/core/diff/repository/repository.py +0 -8
- infrahub/core/diff/tasks.py +11 -8
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/index.py +1 -2
- infrahub/core/graph/schema.py +50 -29
- infrahub/core/initialization.py +62 -33
- infrahub/core/ipam/tasks.py +4 -3
- infrahub/core/merge.py +8 -10
- infrahub/core/migrations/graph/__init__.py +2 -0
- infrahub/core/migrations/graph/m035_drop_attr_value_index.py +45 -0
- infrahub/core/migrations/query/attribute_add.py +27 -2
- infrahub/core/migrations/schema/tasks.py +6 -5
- infrahub/core/node/proposed_change.py +43 -0
- infrahub/core/protocols.py +12 -0
- infrahub/core/query/attribute.py +32 -14
- infrahub/core/query/diff.py +11 -0
- infrahub/core/query/ipam.py +13 -7
- infrahub/core/query/node.py +51 -10
- infrahub/core/query/resource_manager.py +3 -3
- infrahub/core/schema/basenode_schema.py +8 -0
- infrahub/core/schema/definitions/core/__init__.py +10 -1
- infrahub/core/schema/definitions/core/ipam.py +28 -2
- infrahub/core/schema/definitions/core/propose_change.py +15 -0
- infrahub/core/schema/definitions/core/webhook.py +3 -0
- infrahub/core/schema/generic_schema.py +10 -0
- infrahub/core/schema/manager.py +10 -1
- infrahub/core/schema/node_schema.py +22 -17
- infrahub/core/schema/profile_schema.py +8 -0
- infrahub/core/schema/schema_branch.py +9 -5
- infrahub/core/schema/template_schema.py +8 -0
- infrahub/core/validators/checks_runner.py +5 -5
- infrahub/core/validators/tasks.py +6 -7
- infrahub/core/validators/uniqueness/checker.py +4 -2
- infrahub/core/validators/uniqueness/model.py +1 -0
- infrahub/core/validators/uniqueness/query.py +57 -7
- infrahub/database/__init__.py +2 -1
- infrahub/events/__init__.py +18 -0
- infrahub/events/constants.py +7 -0
- infrahub/events/generator.py +29 -2
- infrahub/events/proposed_change_action.py +181 -0
- infrahub/generators/tasks.py +24 -20
- infrahub/git/base.py +4 -7
- infrahub/git/integrator.py +21 -12
- infrahub/git/repository.py +15 -30
- infrahub/git/tasks.py +121 -106
- infrahub/graphql/field_extractor.py +69 -0
- infrahub/graphql/manager.py +15 -11
- infrahub/graphql/mutations/account.py +2 -2
- infrahub/graphql/mutations/action.py +8 -2
- infrahub/graphql/mutations/artifact_definition.py +4 -1
- infrahub/graphql/mutations/branch.py +10 -5
- infrahub/graphql/mutations/graphql_query.py +2 -1
- infrahub/graphql/mutations/main.py +14 -8
- infrahub/graphql/mutations/menu.py +2 -1
- infrahub/graphql/mutations/proposed_change.py +225 -8
- infrahub/graphql/mutations/relationship.py +5 -0
- infrahub/graphql/mutations/repository.py +2 -1
- infrahub/graphql/mutations/tasks.py +7 -9
- infrahub/graphql/mutations/webhook.py +4 -1
- infrahub/graphql/parser.py +15 -6
- infrahub/graphql/queries/__init__.py +10 -1
- infrahub/graphql/queries/account.py +3 -3
- infrahub/graphql/queries/branch.py +2 -2
- infrahub/graphql/queries/diff/tree.py +3 -3
- infrahub/graphql/queries/event.py +13 -3
- infrahub/graphql/queries/ipam.py +23 -1
- infrahub/graphql/queries/proposed_change.py +84 -0
- infrahub/graphql/queries/relationship.py +2 -2
- infrahub/graphql/queries/resource_manager.py +3 -3
- infrahub/graphql/queries/search.py +3 -2
- infrahub/graphql/queries/status.py +3 -2
- infrahub/graphql/queries/task.py +2 -2
- infrahub/graphql/resolvers/ipam.py +440 -0
- infrahub/graphql/resolvers/many_relationship.py +4 -3
- infrahub/graphql/resolvers/resolver.py +5 -5
- infrahub/graphql/resolvers/single_relationship.py +3 -2
- infrahub/graphql/schema.py +25 -5
- infrahub/graphql/types/__init__.py +2 -2
- infrahub/graphql/types/attribute.py +3 -3
- infrahub/graphql/types/event.py +60 -0
- infrahub/groups/tasks.py +6 -6
- infrahub/lock.py +3 -2
- infrahub/menu/generator.py +8 -0
- infrahub/message_bus/operations/__init__.py +9 -12
- infrahub/message_bus/operations/git/file.py +6 -5
- infrahub/message_bus/operations/git/repository.py +12 -20
- infrahub/message_bus/operations/refresh/registry.py +15 -9
- infrahub/message_bus/operations/send/echo.py +7 -4
- infrahub/message_bus/types.py +1 -0
- infrahub/permissions/globals.py +1 -4
- infrahub/permissions/manager.py +8 -5
- infrahub/pools/prefix.py +7 -5
- infrahub/prefect_server/app.py +31 -0
- infrahub/prefect_server/bootstrap.py +18 -0
- infrahub/proposed_change/action_checker.py +206 -0
- infrahub/proposed_change/approval_revoker.py +40 -0
- infrahub/proposed_change/branch_diff.py +3 -1
- infrahub/proposed_change/checker.py +45 -0
- infrahub/proposed_change/constants.py +32 -2
- infrahub/proposed_change/tasks.py +182 -150
- infrahub/py.typed +0 -0
- infrahub/server.py +29 -17
- infrahub/services/__init__.py +13 -28
- infrahub/services/adapters/cache/__init__.py +4 -0
- infrahub/services/adapters/cache/nats.py +2 -0
- infrahub/services/adapters/cache/redis.py +3 -0
- infrahub/services/adapters/message_bus/__init__.py +0 -2
- infrahub/services/adapters/message_bus/local.py +1 -2
- infrahub/services/adapters/message_bus/nats.py +6 -8
- infrahub/services/adapters/message_bus/rabbitmq.py +7 -9
- infrahub/services/adapters/workflow/__init__.py +1 -0
- infrahub/services/adapters/workflow/local.py +1 -8
- infrahub/services/component.py +2 -1
- infrahub/task_manager/event.py +52 -0
- infrahub/task_manager/models.py +9 -0
- infrahub/tasks/artifact.py +6 -7
- infrahub/tasks/check.py +4 -7
- infrahub/telemetry/tasks.py +15 -18
- infrahub/transformations/tasks.py +10 -6
- infrahub/trigger/tasks.py +4 -3
- infrahub/types.py +4 -0
- infrahub/validators/events.py +7 -7
- infrahub/validators/tasks.py +6 -7
- infrahub/webhook/models.py +45 -45
- infrahub/webhook/tasks.py +25 -24
- infrahub/workers/dependencies.py +143 -0
- infrahub/workers/infrahub_async.py +19 -43
- infrahub/workflows/catalogue.py +16 -2
- infrahub/workflows/initialization.py +5 -4
- infrahub/workflows/models.py +2 -0
- infrahub_sdk/client.py +6 -6
- infrahub_sdk/ctl/repository.py +51 -0
- infrahub_sdk/ctl/schema.py +9 -9
- infrahub_sdk/protocols.py +40 -6
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/METADATA +5 -4
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/RECORD +158 -144
- infrahub_testcontainers/container.py +17 -0
- infrahub_testcontainers/docker-compose-cluster.test.yml +56 -1
- infrahub_testcontainers/docker-compose.test.yml +56 -1
- infrahub_testcontainers/helpers.py +4 -1
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.3.5.dist-info → infrahub_server-1.4.0b0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from graphql import (
|
|
4
|
+
FieldNode,
|
|
5
|
+
FragmentSpreadNode,
|
|
6
|
+
GraphQLResolveInfo,
|
|
7
|
+
InlineFragmentNode,
|
|
8
|
+
SelectionSetNode,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GraphQLFieldExtractor:
|
|
13
|
+
"""Class to extract fields from a GraphQL selection set."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, info: GraphQLResolveInfo):
|
|
16
|
+
self.info = info
|
|
17
|
+
self.fragments = info.fragments
|
|
18
|
+
|
|
19
|
+
def get_fields(self) -> dict[str, Any]:
|
|
20
|
+
"""Extract fields from the GraphQL selection set."""
|
|
21
|
+
fields = self._extract_fields(selection_set=self.info.field_nodes[0].selection_set)
|
|
22
|
+
return fields or {}
|
|
23
|
+
|
|
24
|
+
def _extract_fields(self, selection_set: SelectionSetNode | None) -> dict[str, dict] | None:
|
|
25
|
+
"""This function extract all the requested fields in a tree of Dict from a SelectionSetNode
|
|
26
|
+
|
|
27
|
+
The goal of this function is to limit the fields that we need to query from the backend.
|
|
28
|
+
|
|
29
|
+
Currently the function support Fields and InlineFragments but in a combined tree where the fragments are merged together
|
|
30
|
+
This implementation may seam counter intuitive but in the current implementation
|
|
31
|
+
it's better to have slightly more information at time passed to the query manager.
|
|
32
|
+
|
|
33
|
+
In the future we'll probably need to redesign how we read GraphQL queries to generate better Database query.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
if not selection_set:
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
fields: dict[str, dict | Any] = {}
|
|
40
|
+
for node in selection_set.selections:
|
|
41
|
+
sub_selection_set = getattr(node, "selection_set", None)
|
|
42
|
+
if isinstance(node, FieldNode):
|
|
43
|
+
value = self._extract_fields(sub_selection_set)
|
|
44
|
+
if node.name.value not in fields:
|
|
45
|
+
fields[node.name.value] = value
|
|
46
|
+
elif isinstance(fields[node.name.value], dict) and isinstance(value, dict):
|
|
47
|
+
fields[node.name.value].update(value)
|
|
48
|
+
|
|
49
|
+
elif isinstance(node, InlineFragmentNode):
|
|
50
|
+
for sub_node in node.selection_set.selections:
|
|
51
|
+
sub_sub_selection_set = getattr(sub_node, "selection_set", None)
|
|
52
|
+
value = self._extract_fields(sub_sub_selection_set)
|
|
53
|
+
sub_node_name = getattr(sub_node, "name", "")
|
|
54
|
+
sub_node_name_value = getattr(sub_node_name, "value", "")
|
|
55
|
+
if sub_node_name_value not in fields:
|
|
56
|
+
fields[sub_node_name_value] = self._extract_fields(sub_sub_selection_set)
|
|
57
|
+
elif isinstance(fields[sub_node_name_value], dict) and isinstance(value, dict):
|
|
58
|
+
fields[sub_node_name_value].update(value)
|
|
59
|
+
elif isinstance(node, FragmentSpreadNode):
|
|
60
|
+
if node.name.value in self.info.fragments:
|
|
61
|
+
if fragment_fields := self._extract_fields(self.info.fragments[node.name.value].selection_set):
|
|
62
|
+
fields.update(fragment_fields)
|
|
63
|
+
|
|
64
|
+
return fields
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def extract_graphql_fields(info: GraphQLResolveInfo) -> dict[str, Any]:
|
|
68
|
+
graphql_extractor = GraphQLFieldExtractor(info=info)
|
|
69
|
+
return graphql_extractor.get_fields()
|
infrahub/graphql/manager.py
CHANGED
|
@@ -40,6 +40,7 @@ from .mutations.resource_manager import (
|
|
|
40
40
|
InfrahubNumberPoolMutation,
|
|
41
41
|
)
|
|
42
42
|
from .mutations.webhook import InfrahubWebhookMutation
|
|
43
|
+
from .resolvers.ipam import ipam_paginated_list_resolver
|
|
43
44
|
from .resolvers.resolver import (
|
|
44
45
|
account_resolver,
|
|
45
46
|
ancestors_resolver,
|
|
@@ -57,8 +58,8 @@ from .types import (
|
|
|
57
58
|
InfrahubObject,
|
|
58
59
|
PaginatedObjectPermission,
|
|
59
60
|
RelatedIPAddressNodeInput,
|
|
61
|
+
RelatedIPPrefixNodeInput,
|
|
60
62
|
RelatedNodeInput,
|
|
61
|
-
RelatedPrefixNodeInput,
|
|
62
63
|
)
|
|
63
64
|
from .types.attribute import BaseAttribute as BaseAttributeType
|
|
64
65
|
from .types.attribute import TextAttributeType
|
|
@@ -343,14 +344,10 @@ class GraphQLSchemaManager:
|
|
|
343
344
|
|
|
344
345
|
def _get_related_input_type(self, relationship: RelationshipSchema) -> type[RelatedNodeInput]:
|
|
345
346
|
peer_schema = self.schema.get(name=relationship.peer, duplicate=False)
|
|
346
|
-
if
|
|
347
|
-
|
|
348
|
-
):
|
|
349
|
-
return RelatedPrefixNodeInput
|
|
347
|
+
if peer_schema.is_ip_prefix:
|
|
348
|
+
return RelatedIPPrefixNodeInput
|
|
350
349
|
|
|
351
|
-
if
|
|
352
|
-
isinstance(peer_schema, GenericSchema) and relationship.peer == InfrahubKind.IPADDRESS
|
|
353
|
-
):
|
|
350
|
+
if peer_schema.is_ip_address:
|
|
354
351
|
return RelatedIPAddressNodeInput
|
|
355
352
|
|
|
356
353
|
return RelatedNodeInput
|
|
@@ -495,7 +492,9 @@ class GraphQLSchemaManager:
|
|
|
495
492
|
|
|
496
493
|
class_attrs[node_schema.kind] = graphene.Field(
|
|
497
494
|
node_type,
|
|
498
|
-
resolver=default_paginated_list_resolver
|
|
495
|
+
resolver=default_paginated_list_resolver
|
|
496
|
+
if node_name not in [InfrahubKind.IPADDRESS, InfrahubKind.IPPREFIX]
|
|
497
|
+
else ipam_paginated_list_resolver,
|
|
499
498
|
required=True,
|
|
500
499
|
**node_filters,
|
|
501
500
|
)
|
|
@@ -530,9 +529,9 @@ class GraphQLSchemaManager:
|
|
|
530
529
|
InfrahubKind.NODETRIGGERRELATIONSHIPMATCH: InfrahubTriggerRuleMatchMutation,
|
|
531
530
|
}
|
|
532
531
|
|
|
533
|
-
if isinstance(node_schema, NodeSchema) and node_schema.is_ip_prefix
|
|
532
|
+
if isinstance(node_schema, NodeSchema) and node_schema.is_ip_prefix:
|
|
534
533
|
base_class = InfrahubIPPrefixMutation
|
|
535
|
-
elif isinstance(node_schema, NodeSchema) and node_schema.is_ip_address
|
|
534
|
+
elif isinstance(node_schema, NodeSchema) and node_schema.is_ip_address:
|
|
536
535
|
base_class = InfrahubIPAddressMutation
|
|
537
536
|
else:
|
|
538
537
|
base_class = mutation_map.get(node_schema.kind, InfrahubMutation)
|
|
@@ -912,6 +911,11 @@ class GraphQLSchemaManager:
|
|
|
912
911
|
filters.update(get_attribute_type().get_graphql_filters(name="any"))
|
|
913
912
|
filters["partial_match"] = graphene.Boolean()
|
|
914
913
|
|
|
914
|
+
if schema.kind in [InfrahubKind.IPADDRESS, InfrahubKind.IPPREFIX]:
|
|
915
|
+
# This is only available for IPAM generics
|
|
916
|
+
filters["include_available"] = graphene.Boolean()
|
|
917
|
+
filters["kinds"] = graphene.List(graphene.NonNull(graphene.String))
|
|
918
|
+
|
|
915
919
|
if not top_level:
|
|
916
920
|
return filters
|
|
917
921
|
|
|
@@ -2,7 +2,6 @@ from typing import TYPE_CHECKING, Any
|
|
|
2
2
|
|
|
3
3
|
from graphene import Boolean, Field, InputField, InputObjectType, Mutation, String
|
|
4
4
|
from graphql import GraphQLResolveInfo
|
|
5
|
-
from infrahub_sdk.utils import extract_fields
|
|
6
5
|
from infrahub_sdk.uuidt import UUIDT
|
|
7
6
|
from typing_extensions import Self
|
|
8
7
|
|
|
@@ -14,6 +13,7 @@ from infrahub.core.protocols import CoreAccount, CoreNode, InternalAccountToken
|
|
|
14
13
|
from infrahub.core.timestamp import Timestamp
|
|
15
14
|
from infrahub.database import InfrahubDatabase, retry_db_transaction
|
|
16
15
|
from infrahub.exceptions import NodeNotFoundError, PermissionDeniedError
|
|
16
|
+
from infrahub.graphql.field_extractor import extract_graphql_fields
|
|
17
17
|
|
|
18
18
|
from ..models import OrderModel
|
|
19
19
|
from ..types import InfrahubObjectType
|
|
@@ -101,7 +101,7 @@ class AccountMixin:
|
|
|
101
101
|
async with db.start_transaction() as dbt:
|
|
102
102
|
await obj.save(db=dbt)
|
|
103
103
|
|
|
104
|
-
fields =
|
|
104
|
+
fields = extract_graphql_fields(info=info)
|
|
105
105
|
return cls(object=await obj.to_graphql(db=db, fields=fields.get("object", {})), ok=True) # type: ignore[call-arg]
|
|
106
106
|
|
|
107
107
|
@classmethod
|
|
@@ -46,11 +46,14 @@ class InfrahubTriggerRuleMutation(InfrahubMutationMixin, Mutation):
|
|
|
46
46
|
data: InputObjectType,
|
|
47
47
|
branch: Branch,
|
|
48
48
|
database: InfrahubDatabase | None = None,
|
|
49
|
+
override_data: dict[str, Any] | None = None,
|
|
49
50
|
) -> tuple[Node, Self]:
|
|
50
51
|
graphql_context: GraphqlContext = info.context
|
|
51
52
|
db = database or graphql_context.db
|
|
52
53
|
_validate_node_kind(data=data, db=db)
|
|
53
|
-
trigger_rule_definition, result = await super().mutate_create(
|
|
54
|
+
trigger_rule_definition, result = await super().mutate_create(
|
|
55
|
+
info=info, data=data, branch=branch, database=db, override_data=override_data
|
|
56
|
+
)
|
|
54
57
|
|
|
55
58
|
return trigger_rule_definition, result
|
|
56
59
|
|
|
@@ -93,11 +96,14 @@ class InfrahubTriggerRuleMatchMutation(InfrahubMutationMixin, Mutation):
|
|
|
93
96
|
data: InputObjectType,
|
|
94
97
|
branch: Branch,
|
|
95
98
|
database: InfrahubDatabase | None = None, # noqa: ARG003
|
|
99
|
+
override_data: dict[str, Any] | None = None,
|
|
96
100
|
) -> tuple[Node, Self]:
|
|
97
101
|
graphql_context: GraphqlContext = info.context
|
|
98
102
|
|
|
99
103
|
async with graphql_context.db.start_transaction() as dbt:
|
|
100
|
-
trigger_match, result = await super().mutate_create(
|
|
104
|
+
trigger_match, result = await super().mutate_create(
|
|
105
|
+
info=info, data=data, branch=branch, database=dbt, override_data=override_data
|
|
106
|
+
)
|
|
101
107
|
trigger_match_model = cast(CoreNodeTriggerAttributeMatch | CoreNodeTriggerRelationshipMatch, trigger_match)
|
|
102
108
|
node_trigger_rule = await trigger_match_model.trigger.get_peer(db=dbt, raise_on_error=True)
|
|
103
109
|
node_trigger_rule_model = cast(CoreNodeTriggerRule, node_trigger_rule)
|
|
@@ -49,10 +49,13 @@ class InfrahubArtifactDefinitionMutation(InfrahubMutationMixin, Mutation):
|
|
|
49
49
|
data: InputObjectType,
|
|
50
50
|
branch: Branch,
|
|
51
51
|
database: InfrahubDatabase | None = None, # noqa: ARG003
|
|
52
|
+
override_data: dict[str, Any] | None = None,
|
|
52
53
|
) -> tuple[Node, Self]:
|
|
53
54
|
graphql_context: GraphqlContext = info.context
|
|
54
55
|
|
|
55
|
-
artifact_definition, result = await super().mutate_create(
|
|
56
|
+
artifact_definition, result = await super().mutate_create(
|
|
57
|
+
info=info, data=data, branch=branch, override_data=override_data
|
|
58
|
+
)
|
|
56
59
|
|
|
57
60
|
if graphql_context.service:
|
|
58
61
|
model = RequestArtifactDefinitionGenerate(
|
|
@@ -3,13 +3,14 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from graphene import Boolean, Field, InputField, InputObjectType, Mutation, String
|
|
6
|
-
from infrahub_sdk.utils import extract_fields, extract_fields_first_node
|
|
7
6
|
from opentelemetry import trace
|
|
8
7
|
from typing_extensions import Self
|
|
9
8
|
|
|
9
|
+
from infrahub.branch.merge_mutation_checker import verify_branch_merge_mutation_allowed
|
|
10
10
|
from infrahub.core.branch import Branch
|
|
11
11
|
from infrahub.database import retry_db_transaction
|
|
12
12
|
from infrahub.graphql.context import apply_external_context
|
|
13
|
+
from infrahub.graphql.field_extractor import extract_graphql_fields
|
|
13
14
|
from infrahub.graphql.types.context import ContextInput
|
|
14
15
|
from infrahub.log import get_logger
|
|
15
16
|
from infrahub.workflows.catalogue import (
|
|
@@ -84,7 +85,7 @@ class BranchCreate(Mutation):
|
|
|
84
85
|
|
|
85
86
|
# Retrieve created branch
|
|
86
87
|
obj = await Branch.get_by_name(db=graphql_context.db, name=model.name)
|
|
87
|
-
fields =
|
|
88
|
+
fields = extract_graphql_fields(info=info)
|
|
88
89
|
return cls(object=await obj.to_graphql(fields=fields.get("object", {})), ok=True, task=task)
|
|
89
90
|
|
|
90
91
|
|
|
@@ -202,7 +203,7 @@ class BranchRebase(Mutation):
|
|
|
202
203
|
)
|
|
203
204
|
task = {"id": workflow.id}
|
|
204
205
|
|
|
205
|
-
fields =
|
|
206
|
+
fields = extract_graphql_fields(info=info)
|
|
206
207
|
ok = True
|
|
207
208
|
|
|
208
209
|
return cls(object=await obj.to_graphql(fields=fields.get("object", {})), ok=ok, task=task)
|
|
@@ -245,7 +246,7 @@ class BranchValidate(Mutation):
|
|
|
245
246
|
)
|
|
246
247
|
task = {"id": workflow.id}
|
|
247
248
|
|
|
248
|
-
fields =
|
|
249
|
+
fields = extract_graphql_fields(info=info)
|
|
249
250
|
|
|
250
251
|
return cls(object=await obj.to_graphql(fields=fields.get("object", {})), ok=ok, task=task)
|
|
251
252
|
|
|
@@ -274,6 +275,10 @@ class BranchMerge(Mutation):
|
|
|
274
275
|
graphql_context: GraphqlContext = info.context
|
|
275
276
|
await apply_external_context(graphql_context=graphql_context, context_input=context)
|
|
276
277
|
|
|
278
|
+
await verify_branch_merge_mutation_allowed(
|
|
279
|
+
db=graphql_context.db, account_session=graphql_context.active_account_session
|
|
280
|
+
)
|
|
281
|
+
|
|
277
282
|
if wait_until_completion:
|
|
278
283
|
await graphql_context.active_service.workflow.execute_workflow(
|
|
279
284
|
workflow=BRANCH_MERGE_MUTATION,
|
|
@@ -291,7 +296,7 @@ class BranchMerge(Mutation):
|
|
|
291
296
|
# Pull the latest information about the branch from the database directly
|
|
292
297
|
obj = await Branch.get_by_name(db=graphql_context.db, name=branch_name)
|
|
293
298
|
|
|
294
|
-
fields =
|
|
299
|
+
fields = extract_graphql_fields(info=info)
|
|
295
300
|
ok = True
|
|
296
301
|
|
|
297
302
|
return cls(object=await obj.to_graphql(fields=fields.get("object", {})), ok=ok, task=task)
|
|
@@ -68,6 +68,7 @@ class InfrahubGraphQLQueryMutation(InfrahubMutationMixin, Mutation):
|
|
|
68
68
|
data: InputObjectType,
|
|
69
69
|
branch: Branch,
|
|
70
70
|
database: InfrahubDatabase | None = None, # noqa: ARG003
|
|
71
|
+
override_data: dict[str, Any] | None = None,
|
|
71
72
|
) -> tuple[Node, Self]:
|
|
72
73
|
graphql_context: GraphqlContext = info.context
|
|
73
74
|
|
|
@@ -75,7 +76,7 @@ class InfrahubGraphQLQueryMutation(InfrahubMutationMixin, Mutation):
|
|
|
75
76
|
await cls.extract_query_info(info=info, data=data, branch=graphql_context.branch, db=graphql_context.db)
|
|
76
77
|
)
|
|
77
78
|
|
|
78
|
-
obj, result = await super().mutate_create(info=info, data=data, branch=branch)
|
|
79
|
+
obj, result = await super().mutate_create(info=info, data=data, branch=branch, override_data=override_data)
|
|
79
80
|
|
|
80
81
|
return obj, result
|
|
81
82
|
|
|
@@ -6,7 +6,6 @@ from typing import TYPE_CHECKING, Any
|
|
|
6
6
|
|
|
7
7
|
from graphene import InputObjectType, Mutation
|
|
8
8
|
from graphene.types.mutation import MutationOptions
|
|
9
|
-
from infrahub_sdk.utils import extract_fields
|
|
10
9
|
from typing_extensions import Self
|
|
11
10
|
|
|
12
11
|
from infrahub import config, lock
|
|
@@ -28,6 +27,7 @@ from infrahub.dependencies.registry import get_component_registry
|
|
|
28
27
|
from infrahub.events.generator import generate_node_mutation_events
|
|
29
28
|
from infrahub.exceptions import HFIDViolatedError, InitializationError, NodeNotFoundError
|
|
30
29
|
from infrahub.graphql.context import apply_external_context
|
|
30
|
+
from infrahub.graphql.field_extractor import extract_graphql_fields
|
|
31
31
|
from infrahub.lock import InfrahubMultiLock, build_object_lock_name
|
|
32
32
|
from infrahub.log import get_log_data, get_logger
|
|
33
33
|
|
|
@@ -147,7 +147,9 @@ class InfrahubMutationMixin:
|
|
|
147
147
|
return mutation
|
|
148
148
|
|
|
149
149
|
@classmethod
|
|
150
|
-
async def _call_mutate_create_object(
|
|
150
|
+
async def _call_mutate_create_object(
|
|
151
|
+
cls, data: InputObjectType, db: InfrahubDatabase, branch: Branch, override_data: dict[str, Any] | None = None
|
|
152
|
+
) -> Node:
|
|
151
153
|
"""
|
|
152
154
|
Wrapper around mutate_create_object to potentially activate locking.
|
|
153
155
|
"""
|
|
@@ -157,9 +159,9 @@ class InfrahubMutationMixin:
|
|
|
157
159
|
)
|
|
158
160
|
if lock_names:
|
|
159
161
|
async with InfrahubMultiLock(lock_registry=lock.registry, locks=lock_names):
|
|
160
|
-
return await cls.mutate_create_object(data=data, db=db, branch=branch)
|
|
162
|
+
return await cls.mutate_create_object(data=data, db=db, branch=branch, override_data=override_data)
|
|
161
163
|
|
|
162
|
-
return await cls.mutate_create_object(data=data, db=db, branch=branch)
|
|
164
|
+
return await cls.mutate_create_object(data=data, db=db, branch=branch, override_data=override_data)
|
|
163
165
|
|
|
164
166
|
@classmethod
|
|
165
167
|
async def mutate_create(
|
|
@@ -168,10 +170,11 @@ class InfrahubMutationMixin:
|
|
|
168
170
|
data: InputObjectType,
|
|
169
171
|
branch: Branch,
|
|
170
172
|
database: InfrahubDatabase | None = None,
|
|
173
|
+
override_data: dict[str, Any] | None = None,
|
|
171
174
|
) -> tuple[Node, Self]:
|
|
172
175
|
graphql_context: GraphqlContext = info.context
|
|
173
176
|
db = database or graphql_context.db
|
|
174
|
-
obj = await cls._call_mutate_create_object(data=data, db=db, branch=branch)
|
|
177
|
+
obj = await cls._call_mutate_create_object(data=data, db=db, branch=branch, override_data=override_data)
|
|
175
178
|
result = await cls.mutate_create_to_graphql(info=info, db=db, obj=obj)
|
|
176
179
|
return obj, result
|
|
177
180
|
|
|
@@ -182,12 +185,15 @@ class InfrahubMutationMixin:
|
|
|
182
185
|
data: InputObjectType,
|
|
183
186
|
db: InfrahubDatabase,
|
|
184
187
|
branch: Branch,
|
|
188
|
+
override_data: dict[str, Any] | None = None,
|
|
185
189
|
) -> Node:
|
|
186
190
|
schema = cls._meta.active_schema
|
|
187
191
|
if isinstance(schema, GenericSchema):
|
|
188
192
|
raise ValueError(f"Node of generic schema `{schema.name=}` can not be instantiated.")
|
|
193
|
+
create_data = dict(data)
|
|
194
|
+
create_data.update(override_data or {})
|
|
189
195
|
return await create_node(
|
|
190
|
-
data=
|
|
196
|
+
data=create_data,
|
|
191
197
|
db=db,
|
|
192
198
|
branch=branch,
|
|
193
199
|
schema=schema,
|
|
@@ -195,7 +201,7 @@ class InfrahubMutationMixin:
|
|
|
195
201
|
|
|
196
202
|
@classmethod
|
|
197
203
|
async def mutate_create_to_graphql(cls, info: GraphQLResolveInfo, db: InfrahubDatabase, obj: Node) -> Self:
|
|
198
|
-
fields =
|
|
204
|
+
fields = extract_graphql_fields(info=info)
|
|
199
205
|
result: dict[str, Any] = {"ok": True}
|
|
200
206
|
if "object" in fields:
|
|
201
207
|
result["object"] = await obj.to_graphql(db=db, fields=fields.get("object", {}))
|
|
@@ -314,7 +320,7 @@ class InfrahubMutationMixin:
|
|
|
314
320
|
info: GraphQLResolveInfo,
|
|
315
321
|
obj: Node,
|
|
316
322
|
) -> Self:
|
|
317
|
-
fields_object =
|
|
323
|
+
fields_object = extract_graphql_fields(info=info)
|
|
318
324
|
fields_object = fields_object.get("object", {})
|
|
319
325
|
result: dict[str, Any] = {"ok": True}
|
|
320
326
|
if fields_object:
|
|
@@ -54,10 +54,11 @@ class InfrahubCoreMenuMutation(InfrahubMutationMixin, Mutation):
|
|
|
54
54
|
data: InputObjectType,
|
|
55
55
|
branch: Branch,
|
|
56
56
|
database: InfrahubDatabase | None = None, # noqa: ARG003
|
|
57
|
+
override_data: dict[str, Any] | None = None,
|
|
57
58
|
) -> tuple[Node, Self]:
|
|
58
59
|
validate_namespace(data=data)
|
|
59
60
|
|
|
60
|
-
obj, result = await super().mutate_create(info=info, data=data, branch=branch)
|
|
61
|
+
obj, result = await super().mutate_create(info=info, data=data, branch=branch, override_data=override_data)
|
|
61
62
|
|
|
62
63
|
return obj, result
|
|
63
64
|
|