infrahub-server 1.6.0b0__py3-none-any.whl → 1.6.1__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/oauth2.py +33 -6
- infrahub/api/oidc.py +36 -6
- infrahub/auth.py +11 -0
- infrahub/auth_pkce.py +41 -0
- infrahub/config.py +9 -3
- infrahub/core/branch/models.py +3 -2
- infrahub/core/changelog/models.py +2 -2
- infrahub/core/constants/__init__.py +1 -0
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
- infrahub/core/manager.py +36 -31
- infrahub/core/migrations/graph/__init__.py +2 -0
- infrahub/core/migrations/graph/m047_backfill_or_null_display_label.py +606 -0
- infrahub/core/models.py +5 -6
- infrahub/core/node/__init__.py +16 -13
- infrahub/core/node/create.py +36 -8
- infrahub/core/node/proposed_change.py +5 -3
- infrahub/core/node/standard.py +1 -1
- infrahub/core/protocols.py +1 -7
- infrahub/core/query/attribute.py +1 -1
- infrahub/core/query/node.py +9 -5
- infrahub/core/relationship/model.py +21 -4
- infrahub/core/schema/generic_schema.py +1 -1
- infrahub/core/schema/manager.py +8 -3
- infrahub/core/schema/schema_branch.py +35 -16
- infrahub/core/validators/attribute/choices.py +2 -2
- infrahub/core/validators/determiner.py +3 -6
- infrahub/database/__init__.py +1 -1
- infrahub/git/base.py +2 -3
- infrahub/git/models.py +13 -0
- infrahub/git/tasks.py +23 -19
- infrahub/git/utils.py +16 -9
- infrahub/graphql/app.py +6 -6
- infrahub/graphql/loaders/peers.py +6 -0
- infrahub/graphql/mutations/action.py +15 -7
- infrahub/graphql/mutations/hfid.py +1 -1
- infrahub/graphql/mutations/profile.py +8 -1
- infrahub/graphql/mutations/repository.py +3 -3
- infrahub/graphql/mutations/schema.py +4 -4
- infrahub/graphql/mutations/webhook.py +2 -2
- infrahub/graphql/queries/resource_manager.py +2 -3
- infrahub/graphql/queries/search.py +2 -3
- infrahub/graphql/resolvers/ipam.py +20 -0
- infrahub/graphql/resolvers/many_relationship.py +12 -11
- infrahub/graphql/resolvers/resolver.py +6 -2
- infrahub/graphql/resolvers/single_relationship.py +1 -11
- infrahub/log.py +1 -1
- infrahub/message_bus/messages/__init__.py +0 -12
- infrahub/profiles/node_applier.py +9 -0
- infrahub/proposed_change/branch_diff.py +1 -1
- infrahub/proposed_change/tasks.py +1 -1
- infrahub/repositories/create_repository.py +3 -3
- infrahub/task_manager/models.py +1 -1
- infrahub/task_manager/task.py +5 -5
- infrahub/trigger/setup.py +6 -9
- infrahub/utils.py +18 -0
- infrahub/validators/tasks.py +1 -1
- infrahub/workers/infrahub_async.py +7 -6
- infrahub_sdk/client.py +113 -1
- infrahub_sdk/ctl/AGENTS.md +67 -0
- infrahub_sdk/ctl/branch.py +175 -1
- infrahub_sdk/ctl/check.py +3 -3
- infrahub_sdk/ctl/cli_commands.py +9 -9
- infrahub_sdk/ctl/generator.py +2 -2
- infrahub_sdk/ctl/graphql.py +1 -2
- infrahub_sdk/ctl/importer.py +1 -2
- infrahub_sdk/ctl/repository.py +6 -49
- infrahub_sdk/ctl/task.py +2 -4
- infrahub_sdk/ctl/utils.py +2 -2
- infrahub_sdk/ctl/validate.py +1 -2
- infrahub_sdk/diff.py +80 -3
- infrahub_sdk/graphql/constants.py +14 -1
- infrahub_sdk/graphql/renderers.py +5 -1
- infrahub_sdk/node/attribute.py +0 -1
- infrahub_sdk/node/constants.py +3 -1
- infrahub_sdk/node/node.py +303 -3
- infrahub_sdk/node/related_node.py +1 -2
- infrahub_sdk/node/relationship.py +1 -2
- infrahub_sdk/protocols_base.py +0 -1
- infrahub_sdk/pytest_plugin/AGENTS.md +67 -0
- infrahub_sdk/schema/__init__.py +0 -3
- infrahub_sdk/timestamp.py +7 -7
- {infrahub_server-1.6.0b0.dist-info → infrahub_server-1.6.1.dist-info}/METADATA +2 -3
- {infrahub_server-1.6.0b0.dist-info → infrahub_server-1.6.1.dist-info}/RECORD +88 -84
- {infrahub_server-1.6.0b0.dist-info → infrahub_server-1.6.1.dist-info}/WHEEL +1 -1
- infrahub_testcontainers/container.py +2 -2
- {infrahub_server-1.6.0b0.dist-info → infrahub_server-1.6.1.dist-info}/entry_points.txt +0 -0
- {infrahub_server-1.6.0b0.dist-info → infrahub_server-1.6.1.dist-info}/licenses/LICENSE.txt +0 -0
infrahub/git/tasks.py
CHANGED
|
@@ -60,7 +60,7 @@ from .models import (
|
|
|
60
60
|
UserCheckDefinitionData,
|
|
61
61
|
)
|
|
62
62
|
from .repository import InfrahubReadOnlyRepository, InfrahubRepository, get_initialized_repo
|
|
63
|
-
from .utils import fetch_artifact_definition_targets, fetch_check_definition_targets
|
|
63
|
+
from .utils import fetch_artifact_definition_targets, fetch_check_definition_targets, get_repositories_commit_per_branch
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
@flow(
|
|
@@ -195,13 +195,17 @@ async def sync_git_repo_with_origin_and_tag_on_failure(
|
|
|
195
195
|
@flow(name="git_repositories_sync", flow_run_name="Sync Git Repositories")
|
|
196
196
|
async def sync_remote_repositories() -> None:
|
|
197
197
|
log = get_run_logger()
|
|
198
|
+
db = await get_database()
|
|
198
199
|
|
|
199
200
|
client = get_client()
|
|
200
201
|
|
|
201
202
|
branches = await client.branch.all()
|
|
202
|
-
|
|
203
|
+
async with db.start_session() as dbs:
|
|
204
|
+
repositories = await get_repositories_commit_per_branch(db=dbs, kind=InfrahubKind.REPOSITORY)
|
|
203
205
|
|
|
204
206
|
for repo_name, repository_data in repositories.items():
|
|
207
|
+
repository: CoreRepository = repository_data.repository
|
|
208
|
+
|
|
205
209
|
active_internal_status = RepositoryInternalStatus.ACTIVE.value
|
|
206
210
|
default_internal_status = repository_data.branch_info[registry.default_branch].internal_status
|
|
207
211
|
staging_branch = None
|
|
@@ -215,12 +219,12 @@ async def sync_remote_repositories() -> None:
|
|
|
215
219
|
init_failed = False
|
|
216
220
|
try:
|
|
217
221
|
repo = await InfrahubRepository.init(
|
|
218
|
-
id=
|
|
219
|
-
name=
|
|
220
|
-
location=
|
|
222
|
+
id=repository.id,
|
|
223
|
+
name=repository.name.value,
|
|
224
|
+
location=repository.location.value,
|
|
221
225
|
client=client,
|
|
222
226
|
internal_status=active_internal_status,
|
|
223
|
-
default_branch_name=
|
|
227
|
+
default_branch_name=repository.default_branch.value,
|
|
224
228
|
)
|
|
225
229
|
except RepositoryError as exc:
|
|
226
230
|
get_logger().error(str(exc))
|
|
@@ -229,12 +233,12 @@ async def sync_remote_repositories() -> None:
|
|
|
229
233
|
if init_failed:
|
|
230
234
|
try:
|
|
231
235
|
repo = await InfrahubRepository.new(
|
|
232
|
-
id=
|
|
233
|
-
name=
|
|
234
|
-
location=
|
|
236
|
+
id=repository.id,
|
|
237
|
+
name=repository.name.value,
|
|
238
|
+
location=repository.location.value,
|
|
235
239
|
client=client,
|
|
236
240
|
internal_status=active_internal_status,
|
|
237
|
-
default_branch_name=
|
|
241
|
+
default_branch_name=repository.default_branch.value,
|
|
238
242
|
)
|
|
239
243
|
await repo.import_objects_from_files( # type: ignore[call-overload]
|
|
240
244
|
git_branch_name=registry.default_branch, infrahub_branch_name=infrahub_branch
|
|
@@ -246,22 +250,22 @@ async def sync_remote_repositories() -> None:
|
|
|
246
250
|
try:
|
|
247
251
|
await sync_git_repo_with_origin_and_tag_on_failure(
|
|
248
252
|
client=client,
|
|
249
|
-
repository_id=
|
|
250
|
-
repository_name=
|
|
251
|
-
repository_location=
|
|
253
|
+
repository_id=repository.id,
|
|
254
|
+
repository_name=repository.name.value,
|
|
255
|
+
repository_location=repository.location.value,
|
|
252
256
|
internal_status=active_internal_status,
|
|
253
|
-
default_branch_name=
|
|
254
|
-
operational_status=
|
|
257
|
+
default_branch_name=repository.default_branch.value,
|
|
258
|
+
operational_status=repository.operational_status.value,
|
|
255
259
|
staging_branch=staging_branch,
|
|
256
260
|
infrahub_branch=infrahub_branch,
|
|
257
261
|
)
|
|
258
262
|
# Tell workers to fetch to stay in sync
|
|
259
263
|
message = messages.RefreshGitFetch(
|
|
260
264
|
meta=Meta(initiator_id=WORKER_IDENTITY, request_id=get_log_data().get("request_id", "")),
|
|
261
|
-
location=
|
|
262
|
-
repository_id=
|
|
263
|
-
repository_name=
|
|
264
|
-
repository_kind=
|
|
265
|
+
location=repository.location.value,
|
|
266
|
+
repository_id=repository.id,
|
|
267
|
+
repository_name=repository.name.value,
|
|
268
|
+
repository_kind=repository.get_kind(),
|
|
265
269
|
infrahub_branch_name=infrahub_branch,
|
|
266
270
|
infrahub_branch_id=branches[infrahub_branch].id,
|
|
267
271
|
)
|
infrahub/git/utils.py
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from collections import defaultdict
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from infrahub_sdk import InfrahubClient
|
|
6
6
|
from infrahub_sdk.node import RelationshipManager
|
|
7
|
-
from infrahub_sdk.protocols import
|
|
7
|
+
from infrahub_sdk.protocols import (
|
|
8
|
+
CoreArtifactDefinition,
|
|
9
|
+
CoreCheckDefinition,
|
|
10
|
+
CoreGroup,
|
|
11
|
+
CoreReadOnlyRepository,
|
|
12
|
+
CoreRepository,
|
|
13
|
+
)
|
|
8
14
|
from infrahub_sdk.types import Order
|
|
9
15
|
|
|
10
16
|
from infrahub.core import registry
|
|
@@ -12,16 +18,15 @@ from infrahub.core.constants import InfrahubKind
|
|
|
12
18
|
from infrahub.core.manager import NodeManager
|
|
13
19
|
from infrahub.database import InfrahubDatabase
|
|
14
20
|
from infrahub.generators.models import ProposedChangeGeneratorDefinition
|
|
21
|
+
from infrahub.graphql.models import OrderModel
|
|
15
22
|
|
|
16
23
|
from .. import config
|
|
17
24
|
from .models import RepositoryBranchInfo, RepositoryData
|
|
18
25
|
|
|
19
|
-
if TYPE_CHECKING:
|
|
20
|
-
from infrahub.core.protocols import CoreGenericRepository
|
|
21
|
-
|
|
22
26
|
|
|
23
27
|
async def get_repositories_commit_per_branch(
|
|
24
28
|
db: InfrahubDatabase,
|
|
29
|
+
kind: str = InfrahubKind.GENERICREPOSITORY,
|
|
25
30
|
) -> dict[str, RepositoryData]:
|
|
26
31
|
"""Get a list of all repositories and their commit on each branches.
|
|
27
32
|
|
|
@@ -33,11 +38,12 @@ async def get_repositories_commit_per_branch(
|
|
|
33
38
|
repositories: dict[str, RepositoryData] = {}
|
|
34
39
|
|
|
35
40
|
for branch in list(registry.branch.values()):
|
|
36
|
-
repos: list[
|
|
41
|
+
repos: list[CoreRepository | CoreReadOnlyRepository] = await NodeManager.query(
|
|
37
42
|
db=db,
|
|
38
43
|
branch=branch,
|
|
39
|
-
fields={"id": None, "name": None, "commit": None, "internal_status": None},
|
|
40
|
-
schema=
|
|
44
|
+
fields={"id": None, "name": None, "commit": None, "internal_status": None, "location": None, "ref": None},
|
|
45
|
+
schema=kind,
|
|
46
|
+
order=OrderModel(disable=True),
|
|
41
47
|
)
|
|
42
48
|
|
|
43
49
|
for repository in repos:
|
|
@@ -46,10 +52,11 @@ async def get_repositories_commit_per_branch(
|
|
|
46
52
|
repositories[repo_name] = RepositoryData(
|
|
47
53
|
repository_id=repository.get_id(),
|
|
48
54
|
repository_name=repo_name,
|
|
55
|
+
repository=repository,
|
|
49
56
|
branches={},
|
|
50
57
|
)
|
|
51
58
|
|
|
52
|
-
repositories[repo_name].branches[branch.name] = repository.commit.value
|
|
59
|
+
repositories[repo_name].branches[branch.name] = repository.commit.value
|
|
53
60
|
repositories[repo_name].branch_info[branch.name] = RepositoryBranchInfo(
|
|
54
61
|
internal_status=repository.internal_status.value
|
|
55
62
|
)
|
infrahub/graphql/app.py
CHANGED
|
@@ -172,9 +172,9 @@ class InfrahubGraphQLApp:
|
|
|
172
172
|
|
|
173
173
|
response = handler(request)
|
|
174
174
|
if isawaitable(response):
|
|
175
|
-
return await cast(Awaitable[Response], response)
|
|
175
|
+
return await cast("Awaitable[Response]", response)
|
|
176
176
|
|
|
177
|
-
return cast(Response, response)
|
|
177
|
+
return cast("Response", response)
|
|
178
178
|
|
|
179
179
|
async def _handle_http_request(
|
|
180
180
|
self, request: Request, db: InfrahubDatabase, branch: Branch, account_session: AccountSession
|
|
@@ -350,8 +350,8 @@ class InfrahubGraphQLApp:
|
|
|
350
350
|
websocket: WebSocket,
|
|
351
351
|
subscriptions: dict[str, AsyncGenerator[Any, None]],
|
|
352
352
|
) -> None:
|
|
353
|
-
operation_id = cast(str, message.get("id"))
|
|
354
|
-
message_type = cast(str, message.get("type"))
|
|
353
|
+
operation_id = cast("str", message.get("id"))
|
|
354
|
+
message_type = cast("str", message.get("type"))
|
|
355
355
|
|
|
356
356
|
if message_type == GQL_CONNECTION_INIT:
|
|
357
357
|
websocket.scope["connection_params"] = message.get("payload")
|
|
@@ -445,7 +445,7 @@ class InfrahubGraphQLApp:
|
|
|
445
445
|
if isinstance(result, ExecutionResult) and result.errors:
|
|
446
446
|
return result.errors
|
|
447
447
|
|
|
448
|
-
asyncgen = cast(AsyncGenerator[Any, None], result)
|
|
448
|
+
asyncgen = cast("AsyncGenerator[Any, None]", result)
|
|
449
449
|
subscriptions[operation_id] = asyncgen
|
|
450
450
|
task = asyncio.create_task(self._observe_subscription(asyncgen, operation_id, websocket))
|
|
451
451
|
subscription_tasks.add(task)
|
|
@@ -479,7 +479,7 @@ async def _get_operation_from_request(request: Request) -> dict[str, Any] | list
|
|
|
479
479
|
content_type = request.headers.get("Content-Type", "").split(";")[0]
|
|
480
480
|
if content_type == "application/json":
|
|
481
481
|
try:
|
|
482
|
-
return cast(dict[str, Any] | list[Any], await request.json())
|
|
482
|
+
return cast("dict[str, Any] | list[Any]", await request.json())
|
|
483
483
|
except (TypeError, ValueError) as err:
|
|
484
484
|
raise ValueError("Request body is not a valid JSON") from err
|
|
485
485
|
elif content_type == "multipart/form-data":
|
|
@@ -22,6 +22,8 @@ class QueryPeerParams:
|
|
|
22
22
|
fields: dict | None = None
|
|
23
23
|
at: Timestamp | str | None = None
|
|
24
24
|
branch_agnostic: bool = False
|
|
25
|
+
include_source: bool = False
|
|
26
|
+
include_owner: bool = False
|
|
25
27
|
|
|
26
28
|
def __hash__(self) -> int:
|
|
27
29
|
frozen_fields: frozenset | None = None
|
|
@@ -39,6 +41,8 @@ class QueryPeerParams:
|
|
|
39
41
|
self.schema.name,
|
|
40
42
|
str(self.source_kind),
|
|
41
43
|
str(self.branch_agnostic),
|
|
44
|
+
str(self.include_source),
|
|
45
|
+
str(self.include_owner),
|
|
42
46
|
]
|
|
43
47
|
)
|
|
44
48
|
return hash(hash_str)
|
|
@@ -63,6 +67,8 @@ class PeerRelationshipsDataLoader(DataLoader[str, list[Relationship]]):
|
|
|
63
67
|
branch=self.query_params.branch,
|
|
64
68
|
branch_agnostic=self.query_params.branch_agnostic,
|
|
65
69
|
fetch_peers=True,
|
|
70
|
+
include_source=self.query_params.include_source,
|
|
71
|
+
include_owner=self.query_params.include_owner,
|
|
66
72
|
)
|
|
67
73
|
peer_rels_by_node_id: dict[str, list[Relationship]] = {}
|
|
68
74
|
for rel in peer_rels:
|
|
@@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Any, cast
|
|
|
5
5
|
from graphene import InputObjectType, Mutation
|
|
6
6
|
from typing_extensions import Self
|
|
7
7
|
|
|
8
|
-
from infrahub.core.protocols import CoreNodeTriggerAttributeMatch, CoreNodeTriggerRelationshipMatch, CoreNodeTriggerRule
|
|
9
8
|
from infrahub.exceptions import SchemaNotFoundError, ValidationError
|
|
10
9
|
from infrahub.log import get_logger
|
|
11
10
|
|
|
@@ -16,6 +15,11 @@ if TYPE_CHECKING:
|
|
|
16
15
|
|
|
17
16
|
from infrahub.core.branch import Branch
|
|
18
17
|
from infrahub.core.node import Node
|
|
18
|
+
from infrahub.core.protocols import (
|
|
19
|
+
CoreNodeTriggerAttributeMatch,
|
|
20
|
+
CoreNodeTriggerRelationshipMatch,
|
|
21
|
+
CoreNodeTriggerRule,
|
|
22
|
+
)
|
|
19
23
|
from infrahub.core.schema import NodeSchema
|
|
20
24
|
from infrahub.database import InfrahubDatabase
|
|
21
25
|
|
|
@@ -104,9 +108,11 @@ class InfrahubTriggerRuleMatchMutation(InfrahubMutationMixin, Mutation):
|
|
|
104
108
|
trigger_match, result = await super().mutate_create(
|
|
105
109
|
info=info, data=data, branch=branch, database=dbt, override_data=override_data
|
|
106
110
|
)
|
|
107
|
-
trigger_match_model = cast(
|
|
111
|
+
trigger_match_model = cast(
|
|
112
|
+
"CoreNodeTriggerAttributeMatch | CoreNodeTriggerRelationshipMatch", trigger_match
|
|
113
|
+
)
|
|
108
114
|
node_trigger_rule = await trigger_match_model.trigger.get_peer(db=dbt, raise_on_error=True)
|
|
109
|
-
node_trigger_rule_model = cast(CoreNodeTriggerRule, node_trigger_rule)
|
|
115
|
+
node_trigger_rule_model = cast("CoreNodeTriggerRule", node_trigger_rule)
|
|
110
116
|
node_schema = dbt.schema.get_node_schema(name=node_trigger_rule_model.node_kind.value, duplicate=False)
|
|
111
117
|
_validate_node_kind_field(data=data, node_schema=node_schema)
|
|
112
118
|
|
|
@@ -124,9 +130,11 @@ class InfrahubTriggerRuleMatchMutation(InfrahubMutationMixin, Mutation):
|
|
|
124
130
|
graphql_context: GraphqlContext = info.context
|
|
125
131
|
async with graphql_context.db.start_transaction() as dbt:
|
|
126
132
|
trigger_match, result = await super().mutate_update(info=info, data=data, branch=branch, database=dbt)
|
|
127
|
-
trigger_match_model = cast(
|
|
133
|
+
trigger_match_model = cast(
|
|
134
|
+
"CoreNodeTriggerAttributeMatch | CoreNodeTriggerRelationshipMatch", trigger_match
|
|
135
|
+
)
|
|
128
136
|
node_trigger_rule = await trigger_match_model.trigger.get_peer(db=dbt, raise_on_error=True)
|
|
129
|
-
node_trigger_rule_model = cast(CoreNodeTriggerRule, node_trigger_rule)
|
|
137
|
+
node_trigger_rule_model = cast("CoreNodeTriggerRule", node_trigger_rule)
|
|
130
138
|
node_schema = dbt.schema.get_node_schema(name=node_trigger_rule_model.node_kind.value, duplicate=False)
|
|
131
139
|
_validate_node_kind_field(data=data, node_schema=node_schema)
|
|
132
140
|
|
|
@@ -134,7 +142,7 @@ class InfrahubTriggerRuleMatchMutation(InfrahubMutationMixin, Mutation):
|
|
|
134
142
|
|
|
135
143
|
|
|
136
144
|
def _validate_node_kind(data: InputObjectType, db: InfrahubDatabase) -> None:
|
|
137
|
-
input_data = cast(dict[str, dict[str, Any]], data)
|
|
145
|
+
input_data = cast("dict[str, dict[str, Any]]", data)
|
|
138
146
|
if node_kind := input_data.get("node_kind"):
|
|
139
147
|
value = node_kind.get("value")
|
|
140
148
|
if isinstance(value, str):
|
|
@@ -149,7 +157,7 @@ def _validate_node_kind(data: InputObjectType, db: InfrahubDatabase) -> None:
|
|
|
149
157
|
|
|
150
158
|
|
|
151
159
|
def _validate_node_kind_field(data: InputObjectType, node_schema: NodeSchema) -> None:
|
|
152
|
-
input_data = cast(dict[str, dict[str, Any]], data)
|
|
160
|
+
input_data = cast("dict[str, dict[str, Any]]", data)
|
|
153
161
|
if attribute_name := input_data.get("attribute_name"):
|
|
154
162
|
value = attribute_name.get("value")
|
|
155
163
|
if isinstance(value, str):
|
|
@@ -55,7 +55,7 @@ class UpdateHFID(Mutation):
|
|
|
55
55
|
input_value=f"{node_schema.kind}.human_friendly_id has not been defined for this kind."
|
|
56
56
|
)
|
|
57
57
|
|
|
58
|
-
updated_hfid = cast(list[str], data.value)
|
|
58
|
+
updated_hfid = cast("list[str]", data.value)
|
|
59
59
|
|
|
60
60
|
if len(node_schema.human_friendly_id) != len(updated_hfid):
|
|
61
61
|
raise ValidationError(
|
|
@@ -57,6 +57,8 @@ class InfrahubProfileMutation(InfrahubMutationMixin, Mutation):
|
|
|
57
57
|
) -> None:
|
|
58
58
|
if not node_ids:
|
|
59
59
|
related_nodes = await obj.related_nodes.get_relationships(db=db) # type: ignore[attr-defined]
|
|
60
|
+
if hasattr(obj, "related_templates"):
|
|
61
|
+
related_nodes.extend(await obj.related_templates.get_relationships(db=db)) # type: ignore[attr-defined]
|
|
60
62
|
node_ids = [rel.peer_id for rel in related_nodes]
|
|
61
63
|
if node_ids:
|
|
62
64
|
await workflow_service.submit_workflow(
|
|
@@ -79,7 +81,12 @@ class InfrahubProfileMutation(InfrahubMutationMixin, Mutation):
|
|
|
79
81
|
|
|
80
82
|
@classmethod
|
|
81
83
|
async def _get_profile_related_node_ids(cls, db: InfrahubDatabase, obj: Node) -> set[str]:
|
|
82
|
-
related_nodes =
|
|
84
|
+
related_nodes = []
|
|
85
|
+
related_nodes.extend(await obj.related_nodes.get_relationships(db=db)) # type: ignore[attr-defined]
|
|
86
|
+
|
|
87
|
+
if hasattr(obj, "related_templates"):
|
|
88
|
+
related_nodes.extend(await obj.related_templates.get_relationships(db=db)) # type: ignore[attr-defined]
|
|
89
|
+
|
|
83
90
|
if related_nodes:
|
|
84
91
|
related_node_ids = {rel.peer_id for rel in related_nodes}
|
|
85
92
|
else:
|
|
@@ -9,7 +9,6 @@ from graphene import Boolean, Field, InputObjectType, Mutation, String
|
|
|
9
9
|
from infrahub import config
|
|
10
10
|
from infrahub.core.constants import InfrahubKind
|
|
11
11
|
from infrahub.core.manager import NodeManager
|
|
12
|
-
from infrahub.core.protocols import CoreReadOnlyRepository, CoreRepository
|
|
13
12
|
from infrahub.core.schema import NodeSchema
|
|
14
13
|
from infrahub.git.models import (
|
|
15
14
|
GitRepositoryImportObjects,
|
|
@@ -34,6 +33,7 @@ if TYPE_CHECKING:
|
|
|
34
33
|
|
|
35
34
|
from infrahub.core.branch import Branch
|
|
36
35
|
from infrahub.core.node import Node
|
|
36
|
+
from infrahub.core.protocols import CoreReadOnlyRepository, CoreRepository
|
|
37
37
|
from infrahub.database import InfrahubDatabase
|
|
38
38
|
from infrahub.graphql.initialization import GraphqlContext
|
|
39
39
|
|
|
@@ -107,7 +107,7 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
|
|
|
107
107
|
if node.get_kind() != InfrahubKind.READONLYREPOSITORY:
|
|
108
108
|
return await super().mutate_update(info, data, branch, database=graphql_context.db, node=node)
|
|
109
109
|
|
|
110
|
-
node = cast(CoreReadOnlyRepository, node)
|
|
110
|
+
node = cast("CoreReadOnlyRepository", node)
|
|
111
111
|
current_commit = node.commit.value
|
|
112
112
|
current_ref = node.ref.value
|
|
113
113
|
new_commit = None
|
|
@@ -118,7 +118,7 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
|
|
|
118
118
|
new_ref = data.ref.value
|
|
119
119
|
|
|
120
120
|
obj, result = await super().mutate_update(info, data, branch, database=graphql_context.db, node=node)
|
|
121
|
-
obj = cast(CoreReadOnlyRepository, obj)
|
|
121
|
+
obj = cast("CoreReadOnlyRepository", obj)
|
|
122
122
|
|
|
123
123
|
send_update_message = (new_commit and new_commit != current_commit) or (new_ref and new_ref != current_ref)
|
|
124
124
|
if not send_update_message:
|
|
@@ -81,7 +81,7 @@ class SchemaDropdownAdd(Mutation):
|
|
|
81
81
|
_validate_schema_permission(graphql_context=graphql_context)
|
|
82
82
|
await apply_external_context(graphql_context=graphql_context, context_input=context)
|
|
83
83
|
|
|
84
|
-
kind = graphql_context.db.schema.get(name=str(data.kind), branch=graphql_context.branch.name, duplicate=
|
|
84
|
+
kind = graphql_context.db.schema.get(name=str(data.kind), branch=graphql_context.branch.name, duplicate=True)
|
|
85
85
|
attribute = str(data.attribute)
|
|
86
86
|
validate_kind_dropdown(kind=kind, attribute=attribute)
|
|
87
87
|
dropdown = str(data.dropdown)
|
|
@@ -141,7 +141,7 @@ class SchemaDropdownRemove(Mutation):
|
|
|
141
141
|
graphql_context: GraphqlContext = info.context
|
|
142
142
|
|
|
143
143
|
_validate_schema_permission(graphql_context=graphql_context)
|
|
144
|
-
kind = graphql_context.db.schema.get(name=str(data.kind), branch=graphql_context.branch.name, duplicate=
|
|
144
|
+
kind = graphql_context.db.schema.get(name=str(data.kind), branch=graphql_context.branch.name, duplicate=True)
|
|
145
145
|
await apply_external_context(graphql_context=graphql_context, context_input=context)
|
|
146
146
|
|
|
147
147
|
attribute = str(data.attribute)
|
|
@@ -197,7 +197,7 @@ class SchemaEnumAdd(Mutation):
|
|
|
197
197
|
graphql_context: GraphqlContext = info.context
|
|
198
198
|
|
|
199
199
|
_validate_schema_permission(graphql_context=graphql_context)
|
|
200
|
-
kind = graphql_context.db.schema.get(name=str(data.kind), branch=graphql_context.branch.name, duplicate=
|
|
200
|
+
kind = graphql_context.db.schema.get(name=str(data.kind), branch=graphql_context.branch.name, duplicate=True)
|
|
201
201
|
await apply_external_context(graphql_context=graphql_context, context_input=context)
|
|
202
202
|
|
|
203
203
|
attribute = str(data.attribute)
|
|
@@ -243,7 +243,7 @@ class SchemaEnumRemove(Mutation):
|
|
|
243
243
|
graphql_context: GraphqlContext = info.context
|
|
244
244
|
|
|
245
245
|
_validate_schema_permission(graphql_context=graphql_context)
|
|
246
|
-
kind = graphql_context.db.schema.get(name=str(data.kind), branch=graphql_context.branch.name, duplicate=
|
|
246
|
+
kind = graphql_context.db.schema.get(name=str(data.kind), branch=graphql_context.branch.name, duplicate=True)
|
|
247
247
|
await apply_external_context(graphql_context=graphql_context, context_input=context)
|
|
248
248
|
|
|
249
249
|
attribute = str(data.attribute)
|
|
@@ -6,7 +6,6 @@ from typing import TYPE_CHECKING, Any, Self, cast
|
|
|
6
6
|
from graphene import InputObjectType, Mutation
|
|
7
7
|
|
|
8
8
|
from infrahub.core.manager import NodeManager
|
|
9
|
-
from infrahub.core.protocols import CoreWebhook
|
|
10
9
|
from infrahub.core.schema import NodeSchema
|
|
11
10
|
from infrahub.database import retry_db_transaction
|
|
12
11
|
from infrahub.events.utils import get_all_infrahub_node_kind_events
|
|
@@ -20,6 +19,7 @@ if TYPE_CHECKING:
|
|
|
20
19
|
|
|
21
20
|
from infrahub.core.branch import Branch
|
|
22
21
|
from infrahub.core.node import Node
|
|
22
|
+
from infrahub.core.protocols import CoreWebhook
|
|
23
23
|
from infrahub.database import InfrahubDatabase
|
|
24
24
|
from infrahub.graphql.initialization import GraphqlContext
|
|
25
25
|
|
|
@@ -107,7 +107,7 @@ class InfrahubWebhookMutation(InfrahubMutationMixin, Mutation):
|
|
|
107
107
|
branch=branch,
|
|
108
108
|
)
|
|
109
109
|
|
|
110
|
-
webhook = cast(CoreWebhook, obj)
|
|
110
|
+
webhook = cast("CoreWebhook", obj)
|
|
111
111
|
|
|
112
112
|
event_type = input_data.event_type.value if input_data.event_type else webhook.event_type.value.value
|
|
113
113
|
node_kind = input_data.node_kind.value if input_data.node_kind else webhook.node_kind.value
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import contextlib
|
|
3
4
|
from typing import TYPE_CHECKING, Any
|
|
4
5
|
|
|
5
6
|
from graphene import BigInt, Field, Float, Int, List, NonNull, ObjectType, String
|
|
@@ -196,10 +197,8 @@ class PoolUtilization(ObjectType):
|
|
|
196
197
|
|
|
197
198
|
resources_map: dict[str, Node] = {}
|
|
198
199
|
|
|
199
|
-
|
|
200
|
+
with contextlib.suppress(SchemaNotFoundError):
|
|
200
201
|
resources_map = await pool.resources.get_peers(db=db, branch_agnostic=True) # type: ignore[attr-defined,union-attr]
|
|
201
|
-
except SchemaNotFoundError:
|
|
202
|
-
pass
|
|
203
202
|
|
|
204
203
|
utilization_getter = PrefixUtilizationGetter(
|
|
205
204
|
db=db, ip_prefixes=list(resources_map.values()), at=graphql_context.at
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import contextlib
|
|
3
4
|
import ipaddress
|
|
4
5
|
from typing import TYPE_CHECKING, Any
|
|
5
6
|
|
|
@@ -117,11 +118,9 @@ async def search_resolver(
|
|
|
117
118
|
if matching:
|
|
118
119
|
results.append(matching)
|
|
119
120
|
else:
|
|
120
|
-
|
|
121
|
+
with contextlib.suppress(ValueError, ipaddress.AddressValueError):
|
|
121
122
|
# Convert any IPv6 address, network or partial address to collapsed format as it might be stored in db.
|
|
122
123
|
q = _collapse_ipv6(q)
|
|
123
|
-
except (ValueError, ipaddress.AddressValueError):
|
|
124
|
-
pass
|
|
125
124
|
|
|
126
125
|
for kind in [InfrahubKind.NODE, InfrahubKind.GENERICGROUP]:
|
|
127
126
|
objs = await NodeManager.query(
|
|
@@ -4,6 +4,7 @@ import ipaddress
|
|
|
4
4
|
from typing import TYPE_CHECKING, Any
|
|
5
5
|
|
|
6
6
|
from graphql.type.definition import GraphQLNonNull
|
|
7
|
+
from infrahub_sdk.utils import deep_merge_dict
|
|
7
8
|
from netaddr import IPSet
|
|
8
9
|
from opentelemetry import trace
|
|
9
10
|
|
|
@@ -233,6 +234,23 @@ async def _resolve_available_prefix_nodes(
|
|
|
233
234
|
return available_nodes
|
|
234
235
|
|
|
235
236
|
|
|
237
|
+
def _ensure_display_label_fields(
|
|
238
|
+
db: InfrahubDatabase, branch: Branch, schema: NodeSchema | GenericSchema, node_fields: dict[str, Any]
|
|
239
|
+
) -> None:
|
|
240
|
+
"""Ensure fields needed to compute display_label are included in node_fields.
|
|
241
|
+
|
|
242
|
+
This is mostly for virtual nodes (InternalIPPrefixAvailable, InternalIPRangeAvailable) that are not stored in the
|
|
243
|
+
database.
|
|
244
|
+
"""
|
|
245
|
+
if "display_label" not in node_fields or schema.kind not in [InfrahubKind.IPPREFIX, InfrahubKind.IPADDRESS]:
|
|
246
|
+
return
|
|
247
|
+
|
|
248
|
+
schema_branch = db.schema.get_schema_branch(name=branch.name)
|
|
249
|
+
display_label_fields = schema_branch.generate_fields_for_display_label(name=schema.kind)
|
|
250
|
+
if display_label_fields:
|
|
251
|
+
deep_merge_dict(dicta=node_fields, dictb=display_label_fields)
|
|
252
|
+
|
|
253
|
+
|
|
236
254
|
def _filter_kinds(nodes: list[Node], kinds: list[str], limit: int | None) -> list[Node]:
|
|
237
255
|
filtered: list[Node] = []
|
|
238
256
|
available_node_kinds = [InfrahubKind.IPPREFIXAVAILABLE, InfrahubKind.IPRANGEAVAILABLE]
|
|
@@ -324,6 +342,8 @@ async def ipam_paginated_list_resolver( # noqa: PLR0915
|
|
|
324
342
|
edges = fields.get("edges", {})
|
|
325
343
|
node_fields = edges.get("node", {})
|
|
326
344
|
|
|
345
|
+
_ensure_display_label_fields(db=db, branch=graphql_context.branch, schema=schema, node_fields=node_fields)
|
|
346
|
+
|
|
327
347
|
permission_set: dict[str, Any] | None = None
|
|
328
348
|
permissions = (
|
|
329
349
|
await get_permissions(schema=schema, graphql_context=graphql_context)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, Any
|
|
2
2
|
|
|
3
3
|
from graphql import GraphQLResolveInfo
|
|
4
|
-
from infrahub_sdk.utils import deep_merge_dict
|
|
5
4
|
|
|
6
5
|
from infrahub.core.branch.models import Branch
|
|
7
6
|
from infrahub.core.constants import BranchSupportType, RelationshipHierarchyDirection
|
|
@@ -12,6 +11,7 @@ from infrahub.core.schema.relationship_schema import RelationshipSchema
|
|
|
12
11
|
from infrahub.core.timestamp import Timestamp
|
|
13
12
|
from infrahub.database import InfrahubDatabase
|
|
14
13
|
from infrahub.graphql.field_extractor import extract_graphql_fields
|
|
14
|
+
from infrahub.utils import has_any_key
|
|
15
15
|
|
|
16
16
|
from ..loaders.peers import PeerRelationshipsDataLoader, QueryPeerParams
|
|
17
17
|
from ..types import RELATIONS_PROPERTY_MAP, RELATIONS_PROPERTY_MAP_REVERSED
|
|
@@ -195,6 +195,9 @@ class ManyRelationshipResolver:
|
|
|
195
195
|
offset: int | None = None,
|
|
196
196
|
limit: int | None = None,
|
|
197
197
|
) -> list[dict[str, Any]] | None:
|
|
198
|
+
include_source = has_any_key(data=node_fields, keys=["_relation__source", "source"])
|
|
199
|
+
include_owner = has_any_key(data=node_fields, keys=["_relation__owner", "owner"])
|
|
200
|
+
|
|
198
201
|
async with db.start_session(read_only=True) as dbs:
|
|
199
202
|
objs = await NodeManager.query_peers(
|
|
200
203
|
db=dbs,
|
|
@@ -209,6 +212,8 @@ class ManyRelationshipResolver:
|
|
|
209
212
|
branch=branch,
|
|
210
213
|
branch_agnostic=rel_schema.branch is BranchSupportType.AGNOSTIC,
|
|
211
214
|
fetch_peers=True,
|
|
215
|
+
include_source=include_source,
|
|
216
|
+
include_owner=include_owner,
|
|
212
217
|
)
|
|
213
218
|
if not objs:
|
|
214
219
|
return None
|
|
@@ -226,17 +231,11 @@ class ManyRelationshipResolver:
|
|
|
226
231
|
filters: dict[str, Any],
|
|
227
232
|
node_fields: dict[str, Any],
|
|
228
233
|
) -> list[dict[str, Any]] | None:
|
|
229
|
-
if node_fields and "display_label" in node_fields:
|
|
230
|
-
schema_branch = db.schema.get_schema_branch(name=branch.name)
|
|
231
|
-
display_label_fields = schema_branch.generate_fields_for_display_label(name=rel_schema.peer)
|
|
232
|
-
if display_label_fields:
|
|
233
|
-
node_fields = deep_merge_dict(dicta=node_fields, dictb=display_label_fields)
|
|
234
|
-
|
|
235
234
|
if node_fields and "hfid" in node_fields:
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
235
|
+
node_fields["human_friendly_id"] = None
|
|
236
|
+
|
|
237
|
+
include_source = has_any_key(data=node_fields, keys=["_relation__source", "source"])
|
|
238
|
+
include_owner = has_any_key(data=node_fields, keys=["_relation__owner", "owner"])
|
|
240
239
|
|
|
241
240
|
query_params = QueryPeerParams(
|
|
242
241
|
branch=branch,
|
|
@@ -246,6 +245,8 @@ class ManyRelationshipResolver:
|
|
|
246
245
|
fields=node_fields,
|
|
247
246
|
at=at,
|
|
248
247
|
branch_agnostic=rel_schema.branch is BranchSupportType.AGNOSTIC,
|
|
248
|
+
include_source=include_source,
|
|
249
|
+
include_owner=include_owner,
|
|
249
250
|
)
|
|
250
251
|
if query_params in self._data_loader_instances:
|
|
251
252
|
loader = self._data_loader_instances[query_params]
|
|
@@ -9,6 +9,7 @@ from infrahub.core.constants import BranchSupportType, InfrahubKind, Relationshi
|
|
|
9
9
|
from infrahub.core.manager import NodeManager
|
|
10
10
|
from infrahub.exceptions import NodeNotFoundError
|
|
11
11
|
from infrahub.graphql.field_extractor import extract_graphql_fields
|
|
12
|
+
from infrahub.utils import has_any_key
|
|
12
13
|
|
|
13
14
|
from ..models import OrderModel
|
|
14
15
|
from ..parser import extract_selection
|
|
@@ -185,6 +186,9 @@ async def default_paginated_list_resolver(
|
|
|
185
186
|
|
|
186
187
|
objs = []
|
|
187
188
|
if edges or "hfid" in filters:
|
|
189
|
+
include_source = has_any_key(data=node_fields, keys=["_relation__source", "source"])
|
|
190
|
+
include_owner = has_any_key(data=node_fields, keys=["_relation__owner", "owner"])
|
|
191
|
+
|
|
188
192
|
objs = await NodeManager.query(
|
|
189
193
|
db=db,
|
|
190
194
|
schema=schema,
|
|
@@ -195,8 +199,8 @@ async def default_paginated_list_resolver(
|
|
|
195
199
|
limit=limit,
|
|
196
200
|
offset=offset,
|
|
197
201
|
account=graphql_context.account_session,
|
|
198
|
-
include_source=
|
|
199
|
-
include_owner=
|
|
202
|
+
include_source=include_source,
|
|
203
|
+
include_owner=include_owner,
|
|
200
204
|
partial_match=partial_match,
|
|
201
205
|
order=order,
|
|
202
206
|
)
|
|
@@ -2,7 +2,6 @@ from typing import TYPE_CHECKING, Any
|
|
|
2
2
|
|
|
3
3
|
from graphql import GraphQLResolveInfo
|
|
4
4
|
from graphql.type.definition import GraphQLNonNull
|
|
5
|
-
from infrahub_sdk.utils import deep_merge_dict
|
|
6
5
|
|
|
7
6
|
from infrahub.core.branch.models import Branch
|
|
8
7
|
from infrahub.core.constants import BranchSupportType
|
|
@@ -142,17 +141,8 @@ class SingleRelationshipResolver:
|
|
|
142
141
|
except (KeyError, IndexError):
|
|
143
142
|
return None
|
|
144
143
|
|
|
145
|
-
if node_fields and "display_label" in node_fields:
|
|
146
|
-
schema_branch = db.schema.get_schema_branch(name=branch.name)
|
|
147
|
-
display_label_fields = schema_branch.generate_fields_for_display_label(name=rel_schema.peer)
|
|
148
|
-
if display_label_fields:
|
|
149
|
-
node_fields = deep_merge_dict(dicta=node_fields, dictb=display_label_fields)
|
|
150
|
-
|
|
151
144
|
if node_fields and "hfid" in node_fields:
|
|
152
|
-
|
|
153
|
-
hfid_fields = peer_schema.generate_fields_for_hfid()
|
|
154
|
-
if hfid_fields:
|
|
155
|
-
node_fields = deep_merge_dict(dicta=node_fields, dictb=hfid_fields)
|
|
145
|
+
node_fields["human_friendly_id"] = None
|
|
156
146
|
|
|
157
147
|
query_params = GetManyParams(
|
|
158
148
|
fields=node_fields,
|
infrahub/log.py
CHANGED
|
@@ -10,7 +10,7 @@ from structlog.dev import plain_traceback
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
11
|
from structlog.types import Processor
|
|
12
12
|
|
|
13
|
-
INFRAHUB_PRODUCTION = TypeAdapter(bool).validate_python(os.environ.get("INFRAHUB_PRODUCTION",
|
|
13
|
+
INFRAHUB_PRODUCTION = TypeAdapter(bool).validate_python(os.environ.get("INFRAHUB_PRODUCTION", "true"))
|
|
14
14
|
INFRAHUB_LOG_LEVEL = os.environ.get("INFRAHUB_LOG_LEVEL", "INFO")
|
|
15
15
|
|
|
16
16
|
|
|
@@ -22,20 +22,8 @@ RESPONSE_MAP: dict[str, type[InfrahubResponse]] = {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
PRIORITY_MAP = {
|
|
25
|
-
"check.artifact.create": 2,
|
|
26
|
-
"check.repository.check_definition": 2,
|
|
27
|
-
"check.repository.merge_conflicts": 2,
|
|
28
25
|
"send.echo.request": 5, # Currently only for testing purposes, will be removed once all message bus have been migrated to prefect
|
|
29
|
-
"event.branch.delete": 5,
|
|
30
|
-
"event.branch.merge": 5,
|
|
31
|
-
"event.schema.update": 5,
|
|
32
|
-
"git.diff.names_only": 4,
|
|
33
26
|
"git.file.get": 4,
|
|
34
|
-
"request.artifact.generate": 2,
|
|
35
|
-
"request.git.sync": 4,
|
|
36
|
-
"request.proposed_change.pipeline": 5,
|
|
37
|
-
"transform.jinja.template": 4,
|
|
38
|
-
"transform.python.data": 4,
|
|
39
27
|
}
|
|
40
28
|
|
|
41
29
|
|