infrahub-server 1.6.0b0__py3-none-any.whl → 1.6.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- infrahub/api/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/branch/tasks.py +6 -1
- 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 +4 -0
- infrahub/core/migrations/graph/m041_deleted_dup_edges.py +30 -12
- infrahub/core/migrations/graph/m047_backfill_or_null_display_label.py +606 -0
- infrahub/core/migrations/graph/m048_undelete_rel_props.py +161 -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.2.dist-info}/METADATA +2 -3
- {infrahub_server-1.6.0b0.dist-info → infrahub_server-1.6.2.dist-info}/RECORD +91 -86
- {infrahub_server-1.6.0b0.dist-info → infrahub_server-1.6.2.dist-info}/WHEEL +1 -1
- infrahub_testcontainers/container.py +2 -2
- {infrahub_server-1.6.0b0.dist-info → infrahub_server-1.6.2.dist-info}/entry_points.txt +0 -0
- {infrahub_server-1.6.0b0.dist-info → infrahub_server-1.6.2.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import contextlib
|
|
3
4
|
import copy
|
|
4
5
|
import hashlib
|
|
5
6
|
import keyword
|
|
@@ -19,6 +20,7 @@ from infrahub.core.constants import (
|
|
|
19
20
|
OBJECT_TEMPLATE_NAME_ATTR,
|
|
20
21
|
OBJECT_TEMPLATE_RELATIONSHIP_NAME,
|
|
21
22
|
PROFILE_NODE_RELATIONSHIP_IDENTIFIER,
|
|
23
|
+
PROFILE_TEMPLATE_RELATIONSHIP_IDENTIFIER,
|
|
22
24
|
RESERVED_ATTR_GEN_NAMES,
|
|
23
25
|
RESERVED_ATTR_REL_NAMES,
|
|
24
26
|
RESTRICTED_NAMESPACES,
|
|
@@ -72,6 +74,16 @@ from .schema_branch_hfid import HFIDs
|
|
|
72
74
|
log = get_logger()
|
|
73
75
|
|
|
74
76
|
|
|
77
|
+
profiles_rel_settings: dict[str, Any] = {
|
|
78
|
+
"name": "profiles",
|
|
79
|
+
"identifier": PROFILE_NODE_RELATIONSHIP_IDENTIFIER,
|
|
80
|
+
"peer": InfrahubKind.PROFILE,
|
|
81
|
+
"kind": RelationshipKind.PROFILE,
|
|
82
|
+
"cardinality": RelationshipCardinality.MANY,
|
|
83
|
+
"branch": BranchSupportType.AWARE,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
75
87
|
class SchemaBranch:
|
|
76
88
|
def __init__(
|
|
77
89
|
self,
|
|
@@ -334,10 +346,8 @@ class SchemaBranch:
|
|
|
334
346
|
)
|
|
335
347
|
|
|
336
348
|
schema: MainSchemaTypes | None = None
|
|
337
|
-
|
|
349
|
+
with contextlib.suppress(KeyError):
|
|
338
350
|
schema = self._cache[key]
|
|
339
|
-
except KeyError:
|
|
340
|
-
pass
|
|
341
351
|
|
|
342
352
|
if not schema:
|
|
343
353
|
raise ValueError(f"Schema {name!r} on branch {self.name} has incorrect hash: {key!r}")
|
|
@@ -1116,7 +1126,7 @@ class SchemaBranch:
|
|
|
1116
1126
|
) from None
|
|
1117
1127
|
|
|
1118
1128
|
for rel in node.relationships:
|
|
1119
|
-
if rel.peer
|
|
1129
|
+
if rel.peer == InfrahubKind.GENERICGROUP:
|
|
1120
1130
|
continue
|
|
1121
1131
|
if not self.has(rel.peer) or self.get(rel.peer, duplicate=False).state == HashableModelState.ABSENT:
|
|
1122
1132
|
raise ValueError(
|
|
@@ -2163,10 +2173,8 @@ class SchemaBranch:
|
|
|
2163
2173
|
or not node.generate_profile
|
|
2164
2174
|
or node.state == HashableModelState.ABSENT
|
|
2165
2175
|
):
|
|
2166
|
-
|
|
2176
|
+
with contextlib.suppress(SchemaNotFoundError):
|
|
2167
2177
|
self.delete(name=self._get_profile_kind(node_kind=node.kind))
|
|
2168
|
-
except SchemaNotFoundError:
|
|
2169
|
-
...
|
|
2170
2178
|
continue
|
|
2171
2179
|
|
|
2172
2180
|
profile = self.generate_profile_from_node(node=node)
|
|
@@ -2212,15 +2220,6 @@ class SchemaBranch:
|
|
|
2212
2220
|
):
|
|
2213
2221
|
continue
|
|
2214
2222
|
|
|
2215
|
-
profiles_rel_settings: dict[str, Any] = {
|
|
2216
|
-
"name": "profiles",
|
|
2217
|
-
"identifier": PROFILE_NODE_RELATIONSHIP_IDENTIFIER,
|
|
2218
|
-
"peer": InfrahubKind.PROFILE,
|
|
2219
|
-
"kind": RelationshipKind.PROFILE,
|
|
2220
|
-
"cardinality": RelationshipCardinality.MANY,
|
|
2221
|
-
"branch": BranchSupportType.AWARE,
|
|
2222
|
-
}
|
|
2223
|
-
|
|
2224
2223
|
# Add relationship between node and profile
|
|
2225
2224
|
if "profiles" not in node.relationship_names:
|
|
2226
2225
|
node_schema = self.get(name=node_name, duplicate=True)
|
|
@@ -2285,6 +2284,18 @@ class SchemaBranch:
|
|
|
2285
2284
|
)
|
|
2286
2285
|
],
|
|
2287
2286
|
)
|
|
2287
|
+
if f"Template{node.kind}" in self.all_names:
|
|
2288
|
+
template = self.get(name=f"Template{node.kind}", duplicate=False)
|
|
2289
|
+
profile.relationships.append(
|
|
2290
|
+
RelationshipSchema(
|
|
2291
|
+
name="related_templates",
|
|
2292
|
+
identifier=PROFILE_TEMPLATE_RELATIONSHIP_IDENTIFIER,
|
|
2293
|
+
peer=template.kind,
|
|
2294
|
+
kind=RelationshipKind.PROFILE,
|
|
2295
|
+
cardinality=RelationshipCardinality.MANY,
|
|
2296
|
+
branch=BranchSupportType.AWARE,
|
|
2297
|
+
)
|
|
2298
|
+
)
|
|
2288
2299
|
|
|
2289
2300
|
for node_attr in node.attributes:
|
|
2290
2301
|
if not node_attr.support_profiles:
|
|
@@ -2415,6 +2426,14 @@ class SchemaBranch:
|
|
|
2415
2426
|
template_schema.human_friendly_id = [parent_hfid] + template_schema.human_friendly_id
|
|
2416
2427
|
template_schema.uniqueness_constraints[0].append(relationship.name)
|
|
2417
2428
|
|
|
2429
|
+
if getattr(node, "generate_profile", False):
|
|
2430
|
+
if "profiles" not in [r.name for r in template_schema.relationships]:
|
|
2431
|
+
settings = dict(profiles_rel_settings)
|
|
2432
|
+
settings["identifier"] = PROFILE_TEMPLATE_RELATIONSHIP_IDENTIFIER
|
|
2433
|
+
template_schema.relationships.append(RelationshipSchema(**settings))
|
|
2434
|
+
|
|
2435
|
+
self.set(name=template_schema.kind, schema=template_schema)
|
|
2436
|
+
|
|
2418
2437
|
def generate_object_template_from_node(
|
|
2419
2438
|
self, node: NodeSchema | GenericSchema, need_templates: set[NodeSchema | GenericSchema]
|
|
2420
2439
|
) -> TemplateSchema | GenericSchema:
|
|
@@ -4,13 +4,13 @@ from typing import TYPE_CHECKING, Any, cast
|
|
|
4
4
|
|
|
5
5
|
from infrahub.core.constants import NULL_VALUE, PathType
|
|
6
6
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
7
|
-
from infrahub.core.schema.generic_schema import GenericSchema
|
|
8
7
|
|
|
9
8
|
from ..interface import ConstraintCheckerInterface
|
|
10
9
|
from ..shared import AttributeSchemaValidatorQuery
|
|
11
10
|
|
|
12
11
|
if TYPE_CHECKING:
|
|
13
12
|
from infrahub.core.branch import Branch
|
|
13
|
+
from infrahub.core.schema.generic_schema import GenericSchema
|
|
14
14
|
from infrahub.database import InfrahubDatabase
|
|
15
15
|
|
|
16
16
|
from ..model import SchemaConstraintValidatorRequest
|
|
@@ -106,7 +106,7 @@ class AttributeChoicesChecker(ConstraintCheckerInterface):
|
|
|
106
106
|
# skip inheriting schemas that override the attribute being checked
|
|
107
107
|
excluded_kinds: list[str] = []
|
|
108
108
|
if request.node_schema.is_generic_schema:
|
|
109
|
-
request.node_schema = cast(GenericSchema, request.node_schema)
|
|
109
|
+
request.node_schema = cast("GenericSchema", request.node_schema)
|
|
110
110
|
for inheriting_kind in request.node_schema.used_by:
|
|
111
111
|
inheriting_schema = request.schema_branch.get_node(name=inheriting_kind, duplicate=False)
|
|
112
112
|
inheriting_schema_attribute = inheriting_schema.get_attribute(name=request.schema_path.field_name)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import contextlib
|
|
1
2
|
from typing import TYPE_CHECKING, Any
|
|
2
3
|
|
|
3
4
|
from infrahub.core.constants import RelationshipKind, SchemaPathType
|
|
@@ -84,14 +85,10 @@ class ConstraintValidatorDeterminer:
|
|
|
84
85
|
constraints: list[SchemaUpdateConstraintInfo] = []
|
|
85
86
|
schemas = list(self.schema_branch.get_all(duplicate=False).values())
|
|
86
87
|
# added here to check their uniqueness constraints
|
|
87
|
-
|
|
88
|
+
with contextlib.suppress(SchemaNotFoundError):
|
|
88
89
|
schemas.append(self.schema_branch.get_node(name="SchemaAttribute", duplicate=False))
|
|
89
|
-
|
|
90
|
-
pass
|
|
91
|
-
try:
|
|
90
|
+
with contextlib.suppress(SchemaNotFoundError):
|
|
92
91
|
schemas.append(self.schema_branch.get_node(name="SchemaRelationship", duplicate=False))
|
|
93
|
-
except SchemaNotFoundError:
|
|
94
|
-
pass
|
|
95
92
|
for schema in schemas:
|
|
96
93
|
constraints.extend(await self._get_property_constraints_for_one_schema(schema=schema))
|
|
97
94
|
return constraints
|
infrahub/database/__init__.py
CHANGED
|
@@ -356,7 +356,7 @@ class InfrahubDatabase:
|
|
|
356
356
|
type
|
|
357
357
|
and type == QueryType.READ
|
|
358
358
|
and runtime not in [Neo4jRuntime.DEFAULT, Neo4jRuntime.UNDEFINED]
|
|
359
|
-
and not (self.is_transaction and runtime
|
|
359
|
+
and not (self.is_transaction and runtime == Neo4jRuntime.PARALLEL)
|
|
360
360
|
):
|
|
361
361
|
query = f"CYPHER runtime = {runtime.value}\n" + query
|
|
362
362
|
else:
|
infrahub/git/base.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import contextlib
|
|
3
4
|
import shutil
|
|
4
5
|
from abc import ABC, abstractmethod
|
|
5
6
|
from pathlib import Path
|
|
@@ -748,10 +749,8 @@ class InfrahubRepositoryBase(BaseModel, ABC):
|
|
|
748
749
|
for short_name, branch_data in branches.items():
|
|
749
750
|
branch = None
|
|
750
751
|
|
|
751
|
-
|
|
752
|
+
with contextlib.suppress(BranchNotFoundError):
|
|
752
753
|
branch = registry.get_branch_from_registry(branch=short_name)
|
|
753
|
-
except BranchNotFoundError:
|
|
754
|
-
...
|
|
755
754
|
|
|
756
755
|
branch_exists_import_sync_condition = branch and (
|
|
757
756
|
branch.name not in {registry.default_branch, self.default_branch}
|
infrahub/git/models.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from pydantic import BaseModel, ConfigDict, Field
|
|
2
2
|
|
|
3
3
|
from infrahub.context import InfrahubContext
|
|
4
|
+
from infrahub.core.node import Node
|
|
5
|
+
from infrahub.core.protocols import CoreReadOnlyRepository, CoreRepository
|
|
4
6
|
from infrahub.message_bus.types import ProposedChangeBranchDiff
|
|
5
7
|
|
|
6
8
|
|
|
@@ -201,11 +203,22 @@ class RepositoryBranchInfo(BaseModel):
|
|
|
201
203
|
|
|
202
204
|
|
|
203
205
|
class RepositoryData(BaseModel):
|
|
206
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
207
|
+
|
|
204
208
|
repository_id: str = Field(..., description="Id of the repository")
|
|
205
209
|
repository_name: str = Field(..., description="Name of the repository")
|
|
210
|
+
repository: CoreRepository | CoreReadOnlyRepository | Node = Field(
|
|
211
|
+
..., description="InfrahubNode representing a Repository"
|
|
212
|
+
)
|
|
206
213
|
branches: dict[str, str] = Field(
|
|
207
214
|
...,
|
|
208
215
|
description="Dictionary with the name of the branch as the key and the active commit id as the value",
|
|
209
216
|
)
|
|
210
217
|
|
|
211
218
|
branch_info: dict[str, RepositoryBranchInfo] = Field(default_factory=dict)
|
|
219
|
+
|
|
220
|
+
def get_staging_branch(self) -> str | None:
|
|
221
|
+
for branch, info in self.branch_info.items():
|
|
222
|
+
if info.internal_status == "staging":
|
|
223
|
+
return branch
|
|
224
|
+
return None
|
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
|