infrahub-server 1.4.9__py3-none-any.whl → 1.5.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/actions/tasks.py +200 -16
- infrahub/api/artifact.py +3 -0
- infrahub/api/query.py +2 -0
- infrahub/api/schema.py +3 -0
- infrahub/auth.py +5 -5
- infrahub/cli/db.py +2 -2
- infrahub/config.py +7 -2
- infrahub/core/attribute.py +22 -19
- infrahub/core/branch/models.py +2 -2
- infrahub/core/branch/needs_rebase_status.py +11 -0
- infrahub/core/branch/tasks.py +2 -2
- infrahub/core/constants/__init__.py +1 -0
- infrahub/core/convert_object_type/object_conversion.py +201 -0
- infrahub/core/convert_object_type/repository_conversion.py +89 -0
- infrahub/core/convert_object_type/schema_mapping.py +27 -3
- infrahub/core/diff/query/artifact.py +12 -9
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/initialization.py +2 -2
- infrahub/core/manager.py +3 -81
- infrahub/core/migrations/graph/__init__.py +2 -0
- infrahub/core/migrations/graph/m040_profile_attrs_in_db.py +166 -0
- infrahub/core/node/__init__.py +26 -3
- infrahub/core/node/create.py +79 -38
- infrahub/core/node/lock_utils.py +98 -0
- infrahub/core/property.py +11 -0
- infrahub/core/protocols.py +1 -0
- infrahub/core/query/attribute.py +27 -15
- infrahub/core/query/node.py +47 -184
- infrahub/core/query/relationship.py +43 -26
- infrahub/core/query/subquery.py +0 -8
- infrahub/core/relationship/model.py +59 -19
- infrahub/core/schema/attribute_schema.py +0 -2
- infrahub/core/schema/definitions/core/repository.py +7 -0
- infrahub/core/schema/relationship_schema.py +0 -1
- infrahub/core/schema/schema_branch.py +3 -2
- infrahub/generators/models.py +31 -12
- infrahub/generators/tasks.py +3 -1
- infrahub/git/base.py +38 -1
- infrahub/graphql/api/dependencies.py +2 -4
- infrahub/graphql/api/endpoints.py +2 -2
- infrahub/graphql/app.py +2 -4
- infrahub/graphql/initialization.py +2 -3
- infrahub/graphql/manager.py +212 -137
- infrahub/graphql/middleware.py +12 -0
- infrahub/graphql/mutations/branch.py +11 -0
- infrahub/graphql/mutations/computed_attribute.py +110 -3
- infrahub/graphql/mutations/convert_object_type.py +34 -13
- infrahub/graphql/mutations/ipam.py +21 -8
- infrahub/graphql/mutations/main.py +37 -153
- infrahub/graphql/mutations/profile.py +195 -0
- infrahub/graphql/mutations/proposed_change.py +2 -1
- infrahub/graphql/mutations/repository.py +22 -83
- infrahub/graphql/mutations/webhook.py +1 -1
- infrahub/graphql/registry.py +173 -0
- infrahub/graphql/schema.py +4 -1
- infrahub/lock.py +52 -26
- infrahub/locks/__init__.py +0 -0
- infrahub/locks/tasks.py +37 -0
- infrahub/patch/plan_writer.py +2 -2
- infrahub/profiles/__init__.py +0 -0
- infrahub/profiles/node_applier.py +101 -0
- infrahub/profiles/queries/__init__.py +0 -0
- infrahub/profiles/queries/get_profile_data.py +99 -0
- infrahub/profiles/tasks.py +63 -0
- infrahub/repositories/__init__.py +0 -0
- infrahub/repositories/create_repository.py +113 -0
- infrahub/tasks/registry.py +6 -4
- infrahub/webhook/models.py +1 -1
- infrahub/workflows/catalogue.py +38 -3
- infrahub/workflows/models.py +17 -2
- infrahub_sdk/branch.py +5 -8
- infrahub_sdk/client.py +364 -84
- infrahub_sdk/convert_object_type.py +61 -0
- infrahub_sdk/ctl/check.py +2 -3
- infrahub_sdk/ctl/cli_commands.py +16 -12
- infrahub_sdk/ctl/config.py +8 -2
- infrahub_sdk/ctl/generator.py +2 -3
- infrahub_sdk/ctl/repository.py +39 -1
- infrahub_sdk/ctl/schema.py +12 -1
- infrahub_sdk/ctl/utils.py +4 -0
- infrahub_sdk/ctl/validate.py +5 -3
- infrahub_sdk/diff.py +4 -5
- infrahub_sdk/exceptions.py +2 -0
- infrahub_sdk/graphql.py +7 -2
- infrahub_sdk/node/attribute.py +2 -0
- infrahub_sdk/node/node.py +28 -20
- infrahub_sdk/playback.py +1 -2
- infrahub_sdk/protocols.py +40 -6
- infrahub_sdk/pytest_plugin/plugin.py +7 -4
- infrahub_sdk/pytest_plugin/utils.py +40 -0
- infrahub_sdk/repository.py +1 -2
- infrahub_sdk/schema/main.py +1 -0
- infrahub_sdk/spec/object.py +43 -4
- infrahub_sdk/spec/range_expansion.py +118 -0
- infrahub_sdk/timestamp.py +18 -6
- {infrahub_server-1.4.9.dist-info → infrahub_server-1.5.0b0.dist-info}/METADATA +20 -24
- {infrahub_server-1.4.9.dist-info → infrahub_server-1.5.0b0.dist-info}/RECORD +102 -84
- infrahub_testcontainers/models.py +2 -2
- infrahub_testcontainers/performance_test.py +4 -4
- infrahub/core/convert_object_type/conversion.py +0 -134
- {infrahub_server-1.4.9.dist-info → infrahub_server-1.5.0b0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.4.9.dist-info → infrahub_server-1.5.0b0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.4.9.dist-info → infrahub_server-1.5.0b0.dist-info}/entry_points.txt +0 -0
infrahub/actions/tasks.py
CHANGED
|
@@ -1,17 +1,108 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
|
+
|
|
6
|
+
from infrahub_sdk.graphql import Mutation, Query
|
|
7
|
+
from infrahub_sdk.types import Order
|
|
4
8
|
from prefect import flow
|
|
5
9
|
|
|
6
10
|
from infrahub.context import InfrahubContext # noqa: TC001 needed for prefect flow
|
|
11
|
+
from infrahub.core.constants import InfrahubKind
|
|
12
|
+
from infrahub.generators.models import (
|
|
13
|
+
GeneratorDefinitionModel,
|
|
14
|
+
RequestGeneratorRun,
|
|
15
|
+
)
|
|
7
16
|
from infrahub.services import InfrahubServices # noqa: TC001 needed for prefect flow
|
|
8
17
|
from infrahub.trigger.models import TriggerType
|
|
9
18
|
from infrahub.trigger.setup import setup_triggers_specific
|
|
19
|
+
from infrahub.workers.dependencies import get_client, get_workflow
|
|
20
|
+
from infrahub.workflows.catalogue import REQUEST_GENERATOR_RUN
|
|
10
21
|
from infrahub.workflows.utils import add_tags
|
|
11
22
|
|
|
12
23
|
from .gather import gather_trigger_action_rules
|
|
13
24
|
from .models import EventGroupMember # noqa: TC001 needed for prefect flow
|
|
14
25
|
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from infrahub_sdk.client import InfrahubClient
|
|
28
|
+
from infrahub_sdk.node import InfrahubNode
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_generator_run_query(definition_id: str, target_ids: list[str]) -> Query:
|
|
32
|
+
return Query(
|
|
33
|
+
name=InfrahubKind.GENERATORDEFINITION,
|
|
34
|
+
query={
|
|
35
|
+
InfrahubKind.GENERATORDEFINITION: {
|
|
36
|
+
"@filters": {
|
|
37
|
+
"ids": [definition_id],
|
|
38
|
+
},
|
|
39
|
+
"edges": {
|
|
40
|
+
"node": {
|
|
41
|
+
"id": None,
|
|
42
|
+
"name": {
|
|
43
|
+
"value": None,
|
|
44
|
+
},
|
|
45
|
+
"class_name": {
|
|
46
|
+
"value": None,
|
|
47
|
+
},
|
|
48
|
+
"file_path": {
|
|
49
|
+
"value": None,
|
|
50
|
+
},
|
|
51
|
+
"query": {
|
|
52
|
+
"node": {
|
|
53
|
+
"name": {
|
|
54
|
+
"value": None,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
"convert_query_response": {
|
|
59
|
+
"value": None,
|
|
60
|
+
},
|
|
61
|
+
"parameters": {
|
|
62
|
+
"value": None,
|
|
63
|
+
},
|
|
64
|
+
"targets": {
|
|
65
|
+
"node": {
|
|
66
|
+
"id": None,
|
|
67
|
+
"members": {
|
|
68
|
+
"@filters": {
|
|
69
|
+
"ids": target_ids,
|
|
70
|
+
},
|
|
71
|
+
"edges": {
|
|
72
|
+
"node": {
|
|
73
|
+
"__typename": None,
|
|
74
|
+
"id": None,
|
|
75
|
+
"display_label": None,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
"repository": {
|
|
82
|
+
"node": {
|
|
83
|
+
"__typename": None,
|
|
84
|
+
"id": None,
|
|
85
|
+
"name": {
|
|
86
|
+
"value": None,
|
|
87
|
+
},
|
|
88
|
+
f"... on {InfrahubKind.REPOSITORY}": {
|
|
89
|
+
"commit": {
|
|
90
|
+
"value": None,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
f"... on {InfrahubKind.READONLYREPOSITORY}": {
|
|
94
|
+
"commit": {
|
|
95
|
+
"value": None,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
)
|
|
105
|
+
|
|
15
106
|
|
|
16
107
|
@flow(
|
|
17
108
|
name="action-add-node-to-group",
|
|
@@ -65,12 +156,19 @@ async def run_generator(
|
|
|
65
156
|
branch_name: str,
|
|
66
157
|
node_ids: list[str],
|
|
67
158
|
generator_definition_id: str,
|
|
68
|
-
context: InfrahubContext,
|
|
69
|
-
service: InfrahubServices,
|
|
159
|
+
context: InfrahubContext,
|
|
160
|
+
service: InfrahubServices, # noqa: ARG001
|
|
70
161
|
) -> None:
|
|
71
162
|
await add_tags(branches=[branch_name], nodes=node_ids + [generator_definition_id])
|
|
72
|
-
|
|
73
|
-
|
|
163
|
+
|
|
164
|
+
client = get_client()
|
|
165
|
+
|
|
166
|
+
await _run_generators(
|
|
167
|
+
branch_name=branch_name,
|
|
168
|
+
node_ids=node_ids,
|
|
169
|
+
generator_definition_id=generator_definition_id,
|
|
170
|
+
client=client,
|
|
171
|
+
context=context,
|
|
74
172
|
)
|
|
75
173
|
|
|
76
174
|
|
|
@@ -82,13 +180,20 @@ async def run_generator_group_event(
|
|
|
82
180
|
branch_name: str,
|
|
83
181
|
members: list[EventGroupMember],
|
|
84
182
|
generator_definition_id: str,
|
|
85
|
-
context: InfrahubContext,
|
|
86
|
-
service: InfrahubServices,
|
|
183
|
+
context: InfrahubContext,
|
|
184
|
+
service: InfrahubServices, # noqa: ARG001
|
|
87
185
|
) -> None:
|
|
88
186
|
node_ids = [node.id for node in members]
|
|
89
187
|
await add_tags(branches=[branch_name], nodes=node_ids + [generator_definition_id])
|
|
90
|
-
|
|
91
|
-
|
|
188
|
+
|
|
189
|
+
client = get_client()
|
|
190
|
+
|
|
191
|
+
await _run_generators(
|
|
192
|
+
branch_name=branch_name,
|
|
193
|
+
node_ids=node_ids,
|
|
194
|
+
generator_definition_id=generator_definition_id,
|
|
195
|
+
client=client,
|
|
196
|
+
context=context,
|
|
92
197
|
)
|
|
93
198
|
|
|
94
199
|
|
|
@@ -104,16 +209,95 @@ async def configure_action_rules(
|
|
|
104
209
|
) # type: ignore[misc]
|
|
105
210
|
|
|
106
211
|
|
|
107
|
-
async def
|
|
212
|
+
async def _get_targets(
|
|
213
|
+
branch_name: str,
|
|
214
|
+
targets: list[dict[str, Any]],
|
|
215
|
+
client: InfrahubClient,
|
|
216
|
+
) -> dict[str, dict[str, InfrahubNode]]:
|
|
217
|
+
"""Get the targets per kind in order to extract the variables."""
|
|
218
|
+
|
|
219
|
+
targets_per_kind: dict[str, dict[str, InfrahubNode]] = defaultdict(dict)
|
|
220
|
+
|
|
221
|
+
for target in targets:
|
|
222
|
+
targets_per_kind[target["node"]["__typename"]][target["node"]["id"]] = None
|
|
223
|
+
|
|
224
|
+
for kind, values in targets_per_kind.items():
|
|
225
|
+
nodes = await client.filters(
|
|
226
|
+
kind=kind, branch=branch_name, ids=list(values.keys()), populate_store=False, order=Order(disable=True)
|
|
227
|
+
)
|
|
228
|
+
for node in nodes:
|
|
229
|
+
targets_per_kind[kind][node.id] = node
|
|
230
|
+
|
|
231
|
+
return targets_per_kind
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
async def _run_generators(
|
|
108
235
|
branch_name: str,
|
|
109
236
|
node_ids: list[str],
|
|
110
237
|
generator_definition_id: str,
|
|
111
|
-
|
|
238
|
+
client: InfrahubClient,
|
|
239
|
+
context: InfrahubContext | None = None,
|
|
112
240
|
) -> None:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
241
|
+
"""Fetch generator metadata and submit per-target runs.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
branch_name: Branch on which to execute.
|
|
245
|
+
node_ids: Node IDs to run against (restricts selection if provided).
|
|
246
|
+
generator_definition_id: Generator definition to execute.
|
|
247
|
+
client: InfrahubClient to query additional data.
|
|
248
|
+
context: Execution context passed to downstream workflow submissions.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
None
|
|
252
|
+
|
|
253
|
+
Raises:
|
|
254
|
+
ValueError: If the generator definition is not found or none of the requested
|
|
255
|
+
targets are members of the target group.
|
|
256
|
+
"""
|
|
257
|
+
response = await client.execute_graphql(
|
|
258
|
+
query=get_generator_run_query(definition_id=generator_definition_id, target_ids=node_ids).render(),
|
|
259
|
+
branch_name=branch_name,
|
|
117
260
|
)
|
|
261
|
+
if not response[InfrahubKind.GENERATORDEFINITION]["edges"]:
|
|
262
|
+
raise ValueError(f"Generator definition {generator_definition_id} not found")
|
|
118
263
|
|
|
119
|
-
|
|
264
|
+
data = response[InfrahubKind.GENERATORDEFINITION]["edges"][0]["node"]
|
|
265
|
+
|
|
266
|
+
if not data["targets"]["node"]["members"]["edges"]:
|
|
267
|
+
raise ValueError(f"Target {node_ids[0]} is not part of the group {data['targets']['node']['id']}")
|
|
268
|
+
|
|
269
|
+
targets = data["targets"]["node"]["members"]["edges"]
|
|
270
|
+
|
|
271
|
+
targets_per_kind = await _get_targets(branch_name=branch_name, targets=targets, client=client)
|
|
272
|
+
|
|
273
|
+
workflow = get_workflow()
|
|
274
|
+
|
|
275
|
+
for target in targets:
|
|
276
|
+
node: InfrahubNode | None = None
|
|
277
|
+
if data["parameters"]["value"]:
|
|
278
|
+
node = targets_per_kind[target["node"]["__typename"]][target["node"]["id"]]
|
|
279
|
+
|
|
280
|
+
request_generator_run_model = RequestGeneratorRun(
|
|
281
|
+
generator_definition=GeneratorDefinitionModel(
|
|
282
|
+
definition_id=generator_definition_id,
|
|
283
|
+
definition_name=data["name"]["value"],
|
|
284
|
+
class_name=data["class_name"]["value"],
|
|
285
|
+
file_path=data["file_path"]["value"],
|
|
286
|
+
query_name=data["query"]["node"]["name"]["value"],
|
|
287
|
+
convert_query_response=data["convert_query_response"]["value"],
|
|
288
|
+
group_id=data["targets"]["node"]["id"],
|
|
289
|
+
parameters=data["parameters"]["value"],
|
|
290
|
+
),
|
|
291
|
+
commit=data["repository"]["node"]["commit"]["value"],
|
|
292
|
+
repository_id=data["repository"]["node"]["id"],
|
|
293
|
+
repository_name=data["repository"]["node"]["name"]["value"],
|
|
294
|
+
repository_kind=data["repository"]["node"]["__typename"],
|
|
295
|
+
branch_name=branch_name,
|
|
296
|
+
query=data["query"]["node"]["name"]["value"],
|
|
297
|
+
variables=await node.extract(params=data["parameters"]["value"]) if node else {},
|
|
298
|
+
target_id=target["node"]["id"],
|
|
299
|
+
target_name=target["node"]["display_label"],
|
|
300
|
+
)
|
|
301
|
+
await workflow.submit_workflow(
|
|
302
|
+
workflow=REQUEST_GENERATOR_RUN, context=context, parameters={"model": request_generator_run_model}
|
|
303
|
+
)
|
infrahub/api/artifact.py
CHANGED
|
@@ -15,6 +15,7 @@ from infrahub.api.dependencies import (
|
|
|
15
15
|
)
|
|
16
16
|
from infrahub.core import registry
|
|
17
17
|
from infrahub.core.account import ObjectPermission
|
|
18
|
+
from infrahub.core.branch.needs_rebase_status import check_need_rebase_status
|
|
18
19
|
from infrahub.core.constants import GLOBAL_BRANCH_NAME, InfrahubKind, PermissionAction
|
|
19
20
|
from infrahub.core.protocols import CoreArtifactDefinition
|
|
20
21
|
from infrahub.database import InfrahubDatabase # noqa: TC001
|
|
@@ -74,6 +75,8 @@ async def generate_artifact(
|
|
|
74
75
|
permission_manager: PermissionManager = Depends(get_permission_manager),
|
|
75
76
|
context: InfrahubContext = Depends(get_context),
|
|
76
77
|
) -> None:
|
|
78
|
+
check_need_rebase_status(branch_params.branch)
|
|
79
|
+
|
|
77
80
|
permission_decision = (
|
|
78
81
|
PermissionDecisionFlag.ALLOW_DEFAULT
|
|
79
82
|
if branch_params.branch.name in (GLOBAL_BRANCH_NAME, registry.default_branch)
|
infrahub/api/query.py
CHANGED
|
@@ -24,6 +24,7 @@ from infrahub.graphql.metrics import (
|
|
|
24
24
|
GRAPHQL_RESPONSE_SIZE_METRICS,
|
|
25
25
|
GRAPHQL_TOP_LEVEL_QUERIES_METRICS,
|
|
26
26
|
)
|
|
27
|
+
from infrahub.graphql.middleware import raise_on_mutation_on_branch_needing_rebase
|
|
27
28
|
from infrahub.graphql.utils import extract_data
|
|
28
29
|
from infrahub.groups.models import RequestGraphQLQueryGroupUpdate
|
|
29
30
|
from infrahub.log import get_logger
|
|
@@ -98,6 +99,7 @@ async def execute_query(
|
|
|
98
99
|
context_value=gql_params.context,
|
|
99
100
|
root_value=None,
|
|
100
101
|
variable_values=params,
|
|
102
|
+
middleware=[raise_on_mutation_on_branch_needing_rebase],
|
|
101
103
|
)
|
|
102
104
|
|
|
103
105
|
data = extract_data(query_name=gql_query.name.value, result=result)
|
infrahub/api/schema.py
CHANGED
|
@@ -18,6 +18,7 @@ from infrahub.api.exceptions import SchemaNotValidError
|
|
|
18
18
|
from infrahub.core import registry
|
|
19
19
|
from infrahub.core.account import GlobalPermission
|
|
20
20
|
from infrahub.core.branch import Branch # noqa: TC001
|
|
21
|
+
from infrahub.core.branch.needs_rebase_status import check_need_rebase_status
|
|
21
22
|
from infrahub.core.constants import GLOBAL_BRANCH_NAME, GlobalPermissions, PermissionDecision
|
|
22
23
|
from infrahub.core.migrations.schema.models import SchemaApplyMigrationData
|
|
23
24
|
from infrahub.core.models import ( # noqa: TC001
|
|
@@ -287,6 +288,8 @@ async def load_schema(
|
|
|
287
288
|
permission_manager: PermissionManager = Depends(get_permission_manager),
|
|
288
289
|
context: InfrahubContext = Depends(get_context),
|
|
289
290
|
) -> SchemaUpdate:
|
|
291
|
+
check_need_rebase_status(branch)
|
|
292
|
+
|
|
290
293
|
permission_manager.raise_for_permission(
|
|
291
294
|
permission=define_global_permission_from_branch(
|
|
292
295
|
permission=GlobalPermissions.MANAGE_SCHEMA, branch_name=branch.name
|
infrahub/auth.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import uuid
|
|
4
|
-
from datetime import datetime, timedelta
|
|
4
|
+
from datetime import UTC, datetime, timedelta
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
@@ -78,7 +78,7 @@ async def authenticate_with_password(
|
|
|
78
78
|
if not valid_credentials:
|
|
79
79
|
raise AuthorizationError("Incorrect password")
|
|
80
80
|
|
|
81
|
-
now = datetime.now(tz=
|
|
81
|
+
now = datetime.now(tz=UTC)
|
|
82
82
|
refresh_expires = now + timedelta(seconds=config.SETTINGS.security.refresh_token_lifetime)
|
|
83
83
|
|
|
84
84
|
session_id = await create_db_refresh_token(db=db, account_id=account.id, expiration=refresh_expires)
|
|
@@ -139,7 +139,7 @@ async def signin_sso_account(db: InfrahubDatabase, account_name: str, sso_groups
|
|
|
139
139
|
await group.members.add(db=db, data=account)
|
|
140
140
|
await group.members.save(db=db)
|
|
141
141
|
|
|
142
|
-
now = datetime.now(tz=
|
|
142
|
+
now = datetime.now(tz=UTC)
|
|
143
143
|
refresh_expires = now + timedelta(seconds=config.SETTINGS.security.refresh_token_lifetime)
|
|
144
144
|
session_id = await create_db_refresh_token(db=db, account_id=account.id, expiration=refresh_expires)
|
|
145
145
|
access_token = generate_access_token(account_id=account.id, session_id=session_id)
|
|
@@ -148,7 +148,7 @@ async def signin_sso_account(db: InfrahubDatabase, account_name: str, sso_groups
|
|
|
148
148
|
|
|
149
149
|
|
|
150
150
|
def generate_access_token(account_id: str, session_id: uuid.UUID) -> str:
|
|
151
|
-
now = datetime.now(tz=
|
|
151
|
+
now = datetime.now(tz=UTC)
|
|
152
152
|
|
|
153
153
|
access_expires = now + timedelta(seconds=config.SETTINGS.security.access_token_lifetime)
|
|
154
154
|
access_data = {
|
|
@@ -165,7 +165,7 @@ def generate_access_token(account_id: str, session_id: uuid.UUID) -> str:
|
|
|
165
165
|
|
|
166
166
|
|
|
167
167
|
def generate_refresh_token(account_id: str, session_id: uuid.UUID, expiration: datetime) -> str:
|
|
168
|
-
now = datetime.now(tz=
|
|
168
|
+
now = datetime.now(tz=UTC)
|
|
169
169
|
|
|
170
170
|
refresh_data = {
|
|
171
171
|
"sub": account_id,
|
infrahub/cli/db.py
CHANGED
|
@@ -5,7 +5,7 @@ import logging
|
|
|
5
5
|
import os
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from csv import DictReader, DictWriter
|
|
8
|
-
from datetime import
|
|
8
|
+
from datetime import UTC, datetime
|
|
9
9
|
from enum import Enum
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import TYPE_CHECKING, Any, Sequence
|
|
@@ -59,7 +59,7 @@ from .patch import patch_app
|
|
|
59
59
|
|
|
60
60
|
def get_timestamp_string() -> str:
|
|
61
61
|
"""Generate a timestamp string in the format YYYYMMDD-HHMMSS."""
|
|
62
|
-
return datetime.now(tz=
|
|
62
|
+
return datetime.now(tz=UTC).strftime("%Y%m%d-%H%M%S")
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
if TYPE_CHECKING:
|
infrahub/config.py
CHANGED
|
@@ -8,7 +8,7 @@ from enum import Enum
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import TYPE_CHECKING, Any
|
|
10
10
|
|
|
11
|
-
import
|
|
11
|
+
import tomllib
|
|
12
12
|
from infrahub_sdk.utils import generate_uuid
|
|
13
13
|
from pydantic import (
|
|
14
14
|
AliasChoices,
|
|
@@ -371,6 +371,11 @@ class CacheSettings(BaseSettings):
|
|
|
371
371
|
tls_enabled: bool = Field(default=False, description="Indicates if TLS is enabled for the connection")
|
|
372
372
|
tls_insecure: bool = Field(default=False, description="Indicates if TLS certificates are verified")
|
|
373
373
|
tls_ca_file: str | None = Field(default=None, description="File path to CA cert or bundle in PEM format")
|
|
374
|
+
clean_up_deadlocks_interval_mins: int = Field(
|
|
375
|
+
default=15,
|
|
376
|
+
ge=1,
|
|
377
|
+
description="Age threshold in minutes: locks older than this and owned by inactive workers are deleted by the cleanup task.",
|
|
378
|
+
)
|
|
374
379
|
|
|
375
380
|
@property
|
|
376
381
|
def service_port(self) -> int:
|
|
@@ -975,7 +980,7 @@ def load(config_file_name: Path | str = "infrahub.toml", config_data: dict[str,
|
|
|
975
980
|
|
|
976
981
|
if config_file.exists():
|
|
977
982
|
config_string = config_file.read_text(encoding="utf-8")
|
|
978
|
-
config_tmp =
|
|
983
|
+
config_tmp = tomllib.loads(config_string)
|
|
979
984
|
|
|
980
985
|
return Settings(**config_tmp)
|
|
981
986
|
|
infrahub/core/attribute.py
CHANGED
|
@@ -324,7 +324,7 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
|
|
|
324
324
|
|
|
325
325
|
save_at = Timestamp(at)
|
|
326
326
|
|
|
327
|
-
if not self.id
|
|
327
|
+
if not self.id:
|
|
328
328
|
return None
|
|
329
329
|
|
|
330
330
|
return await self._update(at=save_at, db=db)
|
|
@@ -395,7 +395,6 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
|
|
|
395
395
|
|
|
396
396
|
Get the current value
|
|
397
397
|
- If the value is the same, do nothing
|
|
398
|
-
- If the value is inherited and is different, raise error (for now just ignore)
|
|
399
398
|
- If the value is different, create new node and update relationship
|
|
400
399
|
|
|
401
400
|
"""
|
|
@@ -470,28 +469,32 @@ class BaseAttribute(FlagPropertyMixin, NodePropertyMixin):
|
|
|
470
469
|
|
|
471
470
|
# ---------- Update the Node Properties ----------
|
|
472
471
|
for prop_name in self._node_properties:
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
472
|
+
current_prop_id = getattr(self, f"{prop_name}_id")
|
|
473
|
+
database_prop_id: str | None = None
|
|
474
|
+
if prop_name in current_attr_data.node_properties:
|
|
475
|
+
database_prop_id = current_attr_data.node_properties[prop_name].uuid
|
|
476
|
+
needs_update = current_prop_id is not None and current_prop_id != database_prop_id
|
|
477
|
+
needs_clear = self.is_clear(prop_name) and database_prop_id
|
|
478
|
+
|
|
479
|
+
if not needs_update and not needs_clear:
|
|
480
|
+
continue
|
|
481
481
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
482
|
+
changelog.add_property(
|
|
483
|
+
name=prop_name,
|
|
484
|
+
value_current=current_prop_id,
|
|
485
|
+
value_previous=database_prop_id,
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
if needs_update:
|
|
487
489
|
query = await AttributeUpdateNodePropertyQuery.init(
|
|
488
|
-
db=db, attr=self, at=update_at, prop_name=prop_name, prop_id=
|
|
490
|
+
db=db, attr=self, at=update_at, prop_name=prop_name, prop_id=current_prop_id
|
|
489
491
|
)
|
|
490
492
|
await query.execute(db=db)
|
|
491
493
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
494
|
+
# set the to time on the previously active edge
|
|
495
|
+
rel = current_attr_result.get(f"rel_{prop_name}")
|
|
496
|
+
if rel and rel.get("branch") == branch.name:
|
|
497
|
+
await update_relationships_to([rel.element_id], to=update_at, db=db)
|
|
495
498
|
|
|
496
499
|
if changelog.has_updates:
|
|
497
500
|
return changelog
|
infrahub/core/branch/models.py
CHANGED
|
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Any, Optional, Self, Union
|
|
|
5
5
|
|
|
6
6
|
from pydantic import Field, field_validator
|
|
7
7
|
|
|
8
|
+
from infrahub.core.branch.enums import BranchStatus
|
|
8
9
|
from infrahub.core.constants import (
|
|
9
10
|
GLOBAL_BRANCH_NAME,
|
|
10
11
|
)
|
|
@@ -21,8 +22,6 @@ from infrahub.core.registry import registry
|
|
|
21
22
|
from infrahub.core.timestamp import Timestamp
|
|
22
23
|
from infrahub.exceptions import BranchNotFoundError, InitializationError, ValidationError
|
|
23
24
|
|
|
24
|
-
from .enums import BranchStatus
|
|
25
|
-
|
|
26
25
|
if TYPE_CHECKING:
|
|
27
26
|
from infrahub.database import InfrahubDatabase
|
|
28
27
|
|
|
@@ -485,6 +484,7 @@ class Branch(StandardNode):
|
|
|
485
484
|
# FIXME, we must ensure that there is no conflict before rebasing a branch
|
|
486
485
|
# Otherwise we could endup with a complicated situation
|
|
487
486
|
self.branched_from = at.to_string()
|
|
487
|
+
self.status = BranchStatus.OPEN
|
|
488
488
|
await self.save(db=db)
|
|
489
489
|
|
|
490
490
|
# Update the branch in the registry after the rebase
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from infrahub.core.branch import Branch
|
|
2
|
+
from infrahub.core.branch.enums import BranchStatus
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def raise_needs_rebase_error(branch_name: str) -> None:
|
|
6
|
+
raise ValueError(f"Branch {branch_name} must be rebased before any updates can be made")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def check_need_rebase_status(branch: Branch) -> None:
|
|
10
|
+
if branch.status == BranchStatus.NEED_REBASE:
|
|
11
|
+
raise_needs_rebase_error(branch_name=branch.name)
|
infrahub/core/branch/tasks.py
CHANGED
|
@@ -345,7 +345,7 @@ async def create_branch(model: BranchCreateModel, context: InfrahubContext) -> N
|
|
|
345
345
|
async with database.start_session() as db:
|
|
346
346
|
try:
|
|
347
347
|
await Branch.get_by_name(db=db, name=model.name)
|
|
348
|
-
raise
|
|
348
|
+
raise ValidationError(f"The branch {model.name} already exists")
|
|
349
349
|
except BranchNotFoundError:
|
|
350
350
|
pass
|
|
351
351
|
|
|
@@ -356,7 +356,7 @@ async def create_branch(model: BranchCreateModel, context: InfrahubContext) -> N
|
|
|
356
356
|
obj = Branch(**data_dict)
|
|
357
357
|
except pydantic.ValidationError as exc:
|
|
358
358
|
error_msgs = [f"invalid field {error['loc'][0]}: {error['msg']}" for error in exc.errors()]
|
|
359
|
-
raise
|
|
359
|
+
raise ValidationError("\n".join(error_msgs)) from exc
|
|
360
360
|
|
|
361
361
|
async with lock.registry.local_schema_lock():
|
|
362
362
|
# Copy the schema from the origin branch and set the hash and the schema_changed_at value
|