infrahub-server 1.3.8__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- infrahub/api/internal.py +5 -0
- infrahub/artifacts/tasks.py +17 -22
- infrahub/branch/merge_mutation_checker.py +38 -0
- infrahub/cli/__init__.py +2 -2
- infrahub/cli/context.py +7 -3
- infrahub/cli/db.py +5 -16
- infrahub/cli/upgrade.py +10 -29
- infrahub/computed_attribute/tasks.py +36 -46
- infrahub/config.py +57 -6
- infrahub/constants/environment.py +1 -0
- infrahub/core/attribute.py +15 -7
- infrahub/core/branch/tasks.py +43 -41
- infrahub/core/constants/__init__.py +21 -6
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/diff/coordinator.py +3 -1
- infrahub/core/diff/repository/repository.py +0 -8
- infrahub/core/diff/tasks.py +11 -8
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/index.py +1 -2
- infrahub/core/graph/schema.py +50 -29
- infrahub/core/initialization.py +81 -47
- infrahub/core/ipam/tasks.py +4 -3
- infrahub/core/merge.py +8 -10
- infrahub/core/migrations/__init__.py +2 -0
- infrahub/core/migrations/graph/__init__.py +4 -0
- infrahub/core/migrations/graph/m036_drop_attr_value_index.py +45 -0
- infrahub/core/migrations/graph/m037_index_attr_vals.py +577 -0
- infrahub/core/migrations/query/attribute_add.py +27 -2
- infrahub/core/migrations/schema/attribute_kind_update.py +156 -0
- infrahub/core/migrations/schema/tasks.py +6 -5
- infrahub/core/models.py +5 -1
- infrahub/core/node/proposed_change.py +43 -0
- infrahub/core/protocols.py +12 -0
- infrahub/core/query/attribute.py +32 -14
- infrahub/core/query/diff.py +11 -0
- infrahub/core/query/ipam.py +13 -7
- infrahub/core/query/node.py +51 -10
- infrahub/core/query/resource_manager.py +3 -3
- infrahub/core/schema/basenode_schema.py +8 -0
- infrahub/core/schema/definitions/core/__init__.py +10 -1
- infrahub/core/schema/definitions/core/ipam.py +28 -2
- infrahub/core/schema/definitions/core/propose_change.py +15 -0
- infrahub/core/schema/definitions/core/webhook.py +3 -0
- infrahub/core/schema/definitions/internal.py +1 -1
- infrahub/core/schema/generated/attribute_schema.py +1 -1
- infrahub/core/schema/generic_schema.py +10 -0
- infrahub/core/schema/manager.py +10 -1
- infrahub/core/schema/node_schema.py +22 -17
- infrahub/core/schema/profile_schema.py +8 -0
- infrahub/core/schema/schema_branch.py +9 -5
- infrahub/core/schema/template_schema.py +8 -0
- infrahub/core/validators/attribute/kind.py +5 -1
- infrahub/core/validators/checks_runner.py +5 -5
- infrahub/core/validators/determiner.py +22 -2
- infrahub/core/validators/tasks.py +6 -7
- infrahub/core/validators/uniqueness/checker.py +4 -2
- infrahub/core/validators/uniqueness/model.py +1 -0
- infrahub/core/validators/uniqueness/query.py +57 -7
- infrahub/database/__init__.py +2 -1
- infrahub/events/__init__.py +20 -0
- infrahub/events/constants.py +7 -0
- infrahub/events/generator.py +29 -2
- infrahub/events/proposed_change_action.py +203 -0
- infrahub/generators/tasks.py +24 -20
- infrahub/git/base.py +4 -7
- infrahub/git/integrator.py +21 -12
- infrahub/git/repository.py +15 -30
- infrahub/git/tasks.py +121 -106
- infrahub/graphql/field_extractor.py +69 -0
- infrahub/graphql/manager.py +15 -11
- infrahub/graphql/mutations/account.py +2 -2
- infrahub/graphql/mutations/action.py +8 -2
- infrahub/graphql/mutations/artifact_definition.py +4 -1
- infrahub/graphql/mutations/branch.py +10 -5
- infrahub/graphql/mutations/graphql_query.py +2 -1
- infrahub/graphql/mutations/main.py +14 -8
- infrahub/graphql/mutations/menu.py +2 -1
- infrahub/graphql/mutations/proposed_change.py +230 -8
- infrahub/graphql/mutations/relationship.py +5 -0
- infrahub/graphql/mutations/repository.py +2 -1
- infrahub/graphql/mutations/tasks.py +7 -9
- infrahub/graphql/mutations/webhook.py +4 -1
- infrahub/graphql/parser.py +15 -6
- infrahub/graphql/queries/__init__.py +10 -1
- infrahub/graphql/queries/account.py +3 -3
- infrahub/graphql/queries/branch.py +2 -2
- infrahub/graphql/queries/diff/tree.py +3 -3
- infrahub/graphql/queries/event.py +13 -3
- infrahub/graphql/queries/ipam.py +23 -1
- infrahub/graphql/queries/proposed_change.py +84 -0
- infrahub/graphql/queries/relationship.py +2 -2
- infrahub/graphql/queries/resource_manager.py +3 -3
- infrahub/graphql/queries/search.py +3 -2
- infrahub/graphql/queries/status.py +3 -2
- infrahub/graphql/queries/task.py +2 -2
- infrahub/graphql/resolvers/ipam.py +440 -0
- infrahub/graphql/resolvers/many_relationship.py +4 -3
- infrahub/graphql/resolvers/resolver.py +5 -5
- infrahub/graphql/resolvers/single_relationship.py +3 -2
- infrahub/graphql/schema.py +25 -5
- infrahub/graphql/types/__init__.py +2 -2
- infrahub/graphql/types/attribute.py +3 -3
- infrahub/graphql/types/event.py +68 -0
- infrahub/groups/tasks.py +6 -6
- infrahub/lock.py +3 -2
- infrahub/menu/generator.py +8 -0
- infrahub/message_bus/operations/__init__.py +9 -12
- infrahub/message_bus/operations/git/file.py +6 -5
- infrahub/message_bus/operations/git/repository.py +12 -20
- infrahub/message_bus/operations/refresh/registry.py +15 -9
- infrahub/message_bus/operations/send/echo.py +7 -4
- infrahub/message_bus/types.py +1 -0
- infrahub/permissions/__init__.py +2 -1
- infrahub/permissions/constants.py +13 -0
- infrahub/permissions/globals.py +31 -2
- infrahub/permissions/manager.py +8 -5
- infrahub/pools/prefix.py +7 -5
- infrahub/prefect_server/app.py +31 -0
- infrahub/prefect_server/bootstrap.py +18 -0
- infrahub/proposed_change/action_checker.py +206 -0
- infrahub/proposed_change/approval_revoker.py +40 -0
- infrahub/proposed_change/branch_diff.py +3 -1
- infrahub/proposed_change/checker.py +45 -0
- infrahub/proposed_change/constants.py +32 -2
- infrahub/proposed_change/tasks.py +182 -150
- infrahub/py.typed +0 -0
- infrahub/server.py +29 -17
- infrahub/services/__init__.py +13 -28
- infrahub/services/adapters/cache/__init__.py +4 -0
- infrahub/services/adapters/cache/nats.py +2 -0
- infrahub/services/adapters/cache/redis.py +3 -0
- infrahub/services/adapters/message_bus/__init__.py +0 -2
- infrahub/services/adapters/message_bus/local.py +1 -2
- infrahub/services/adapters/message_bus/nats.py +6 -8
- infrahub/services/adapters/message_bus/rabbitmq.py +7 -9
- infrahub/services/adapters/workflow/__init__.py +1 -0
- infrahub/services/adapters/workflow/local.py +1 -8
- infrahub/services/component.py +2 -1
- infrahub/task_manager/event.py +56 -0
- infrahub/task_manager/models.py +9 -0
- infrahub/tasks/artifact.py +6 -7
- infrahub/tasks/check.py +4 -7
- infrahub/telemetry/tasks.py +15 -18
- infrahub/transformations/tasks.py +10 -6
- infrahub/trigger/tasks.py +4 -3
- infrahub/types.py +4 -0
- infrahub/validators/events.py +7 -7
- infrahub/validators/tasks.py +6 -7
- infrahub/webhook/models.py +45 -45
- infrahub/webhook/tasks.py +25 -24
- infrahub/workers/dependencies.py +143 -0
- infrahub/workers/infrahub_async.py +19 -43
- infrahub/workflows/catalogue.py +16 -2
- infrahub/workflows/initialization.py +5 -4
- infrahub/workflows/models.py +2 -0
- infrahub_sdk/client.py +2 -2
- infrahub_sdk/ctl/repository.py +51 -0
- infrahub_sdk/ctl/schema.py +9 -9
- infrahub_sdk/node/node.py +2 -2
- infrahub_sdk/pytest_plugin/items/graphql_query.py +1 -1
- infrahub_sdk/schema/repository.py +1 -1
- infrahub_sdk/testing/docker.py +1 -1
- infrahub_sdk/utils.py +2 -2
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/METADATA +7 -5
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/RECORD +172 -156
- infrahub_testcontainers/container.py +17 -0
- infrahub_testcontainers/docker-compose-cluster.test.yml +56 -1
- infrahub_testcontainers/docker-compose.test.yml +56 -1
- infrahub_testcontainers/helpers.py +4 -1
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.3.8.dist-info → infrahub_server-1.4.0.dist-info}/entry_points.txt +0 -0
infrahub/core/graph/schema.py
CHANGED
|
@@ -23,6 +23,14 @@ class GraphRelationship(BaseModel):
|
|
|
23
23
|
direction: GraphRelDirection
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
class GraphVertex(BaseModel):
|
|
27
|
+
default_label: str = "NULL"
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def get_default_label(cls) -> str:
|
|
31
|
+
return cls.model_fields["default_label"].default
|
|
32
|
+
|
|
33
|
+
|
|
26
34
|
# -----------------------------------------------------
|
|
27
35
|
# Node
|
|
28
36
|
# -----------------------------------------------------
|
|
@@ -61,7 +69,7 @@ class GraphNodeRelationships(BaseModel):
|
|
|
61
69
|
)
|
|
62
70
|
|
|
63
71
|
|
|
64
|
-
class GraphNodeNode(
|
|
72
|
+
class GraphNodeNode(GraphVertex):
|
|
65
73
|
default_label: str = "Node" # Most node also have CoreNode
|
|
66
74
|
properties: GraphNodeProperties
|
|
67
75
|
relationships: GraphNodeRelationships
|
|
@@ -95,7 +103,7 @@ class GraphRelationshipRelationships(BaseModel):
|
|
|
95
103
|
)
|
|
96
104
|
|
|
97
105
|
|
|
98
|
-
class GraphRelationshipNode(
|
|
106
|
+
class GraphRelationshipNode(GraphVertex):
|
|
99
107
|
default_label: str = "Relationship"
|
|
100
108
|
properties: GraphRelationshipProperties
|
|
101
109
|
relationships: GraphRelationshipRelationships
|
|
@@ -133,7 +141,7 @@ class GraphAttributeRelationships(BaseModel):
|
|
|
133
141
|
)
|
|
134
142
|
|
|
135
143
|
|
|
136
|
-
class GraphAttributeNode(
|
|
144
|
+
class GraphAttributeNode(GraphVertex):
|
|
137
145
|
default_label: str = "Attribute"
|
|
138
146
|
properties: GraphAttributeProperties
|
|
139
147
|
relationships: GraphAttributeRelationships
|
|
@@ -168,19 +176,25 @@ class GraphAttributeValueRelationships(BaseModel):
|
|
|
168
176
|
)
|
|
169
177
|
|
|
170
178
|
|
|
171
|
-
class GraphAttributeValueNode(
|
|
179
|
+
class GraphAttributeValueNode(GraphVertex):
|
|
172
180
|
default_label: str = "AttributeValue"
|
|
173
181
|
properties: GraphAttributeValueProperties
|
|
174
182
|
relationships: GraphAttributeValueRelationships
|
|
175
183
|
|
|
176
184
|
|
|
177
|
-
class
|
|
185
|
+
class GraphAttributeValueIndexedNode(GraphVertex):
|
|
186
|
+
default_label: str = "AttributeValueIndexed"
|
|
187
|
+
properties: GraphAttributeValueProperties
|
|
188
|
+
relationships: GraphAttributeValueRelationships
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class GraphAttributeIPNetworkNode(GraphVertex):
|
|
178
192
|
default_label: str = "AttributeIPNetwork"
|
|
179
193
|
properties: GraphAttributeIPNetworkProperties
|
|
180
194
|
relationships: GraphAttributeValueRelationships
|
|
181
195
|
|
|
182
196
|
|
|
183
|
-
class GraphAttributeIPHostNode(
|
|
197
|
+
class GraphAttributeIPHostNode(GraphVertex):
|
|
184
198
|
default_label: str = "AttributeIPHost"
|
|
185
199
|
properties: GraphAttributeIPHostProperties
|
|
186
200
|
relationships: GraphAttributeValueRelationships
|
|
@@ -202,7 +216,7 @@ class GraphBooleanRelationships(BaseModel):
|
|
|
202
216
|
)
|
|
203
217
|
|
|
204
218
|
|
|
205
|
-
class GraphBooleanNode(
|
|
219
|
+
class GraphBooleanNode(GraphVertex):
|
|
206
220
|
default_label: str = "Boolean"
|
|
207
221
|
properties: GraphBooleanProperties
|
|
208
222
|
relationships: GraphBooleanRelationships
|
|
@@ -229,25 +243,32 @@ class GraphRelationshipDefault(BaseModel):
|
|
|
229
243
|
hierarchy: Optional[str] = Field(None, description="Name of the hierarchy this relationship is part of")
|
|
230
244
|
|
|
231
245
|
|
|
232
|
-
|
|
233
|
-
"nodes"
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
"
|
|
246
|
-
"
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
246
|
+
def get_graph_schema() -> dict[str, dict[str, Any]]:
|
|
247
|
+
"""Generate the graph schema dictionary containing nodes and relationships."""
|
|
248
|
+
graph_node_list: list[type[GraphVertex]] = [
|
|
249
|
+
GraphNodeNode,
|
|
250
|
+
GraphRelationshipNode,
|
|
251
|
+
GraphAttributeNode,
|
|
252
|
+
GraphAttributeValueNode,
|
|
253
|
+
GraphAttributeValueIndexedNode,
|
|
254
|
+
GraphAttributeIPNetworkNode,
|
|
255
|
+
GraphAttributeIPHostNode,
|
|
256
|
+
GraphBooleanNode,
|
|
257
|
+
]
|
|
258
|
+
return {
|
|
259
|
+
"nodes": {graph_node.get_default_label(): graph_node for graph_node in graph_node_list},
|
|
260
|
+
"relationships": {
|
|
261
|
+
# Ignoring IS_PART_OF for now, because there is a bit of cleanup required
|
|
262
|
+
# "IS_PART_OF": GraphRelationshipIsPartOf,
|
|
263
|
+
"HAS_VALUE": GraphRelationshipDefault,
|
|
264
|
+
"HAS_ATTRIBUTE": GraphRelationshipDefault,
|
|
265
|
+
"IS_RELATED": GraphRelationshipDefault,
|
|
266
|
+
"HAS_SOURCE": GraphRelationshipDefault,
|
|
267
|
+
"HAS_OWNER": GraphRelationshipDefault,
|
|
268
|
+
"IS_VISIBLE": GraphRelationshipDefault,
|
|
269
|
+
"IS_PROTECTED": GraphRelationshipDefault,
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
GRAPH_SCHEMA: dict[str, dict[str, Any]] = get_graph_schema()
|
infrahub/core/initialization.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import importlib
|
|
2
|
+
from collections.abc import Sequence
|
|
2
3
|
from typing import TYPE_CHECKING
|
|
3
4
|
from uuid import uuid4
|
|
4
5
|
|
|
@@ -16,15 +17,16 @@ from infrahub.core.constants import (
|
|
|
16
17
|
PermissionDecision,
|
|
17
18
|
)
|
|
18
19
|
from infrahub.core.graph import GRAPH_VERSION
|
|
19
|
-
from infrahub.core.graph.index import
|
|
20
|
+
from infrahub.core.graph.index import node_indexes, rel_indexes
|
|
20
21
|
from infrahub.core.manager import NodeManager
|
|
21
22
|
from infrahub.core.node import Node
|
|
22
23
|
from infrahub.core.node.ipam import BuiltinIPPrefix
|
|
23
24
|
from infrahub.core.node.permissions import CoreGlobalPermission, CoreObjectPermission
|
|
25
|
+
from infrahub.core.node.proposed_change import CoreProposedChange
|
|
24
26
|
from infrahub.core.node.resource_manager.ip_address_pool import CoreIPAddressPool
|
|
25
27
|
from infrahub.core.node.resource_manager.ip_prefix_pool import CoreIPPrefixPool
|
|
26
28
|
from infrahub.core.node.resource_manager.number_pool import CoreNumberPool
|
|
27
|
-
from infrahub.core.protocols import CoreAccount
|
|
29
|
+
from infrahub.core.protocols import CoreAccount, CoreAccountGroup, CoreAccountRole
|
|
28
30
|
from infrahub.core.root import Root
|
|
29
31
|
from infrahub.core.schema import SchemaRoot, core_models, internal_schema
|
|
30
32
|
from infrahub.core.schema.manager import SchemaManager
|
|
@@ -35,7 +37,7 @@ from infrahub.exceptions import DatabaseError
|
|
|
35
37
|
from infrahub.graphql.manager import GraphQLSchemaManager
|
|
36
38
|
from infrahub.log import get_logger
|
|
37
39
|
from infrahub.menu.utils import create_default_menu
|
|
38
|
-
from infrahub.permissions import PermissionBackend
|
|
40
|
+
from infrahub.permissions import PermissionBackend, get_or_create_global_permission
|
|
39
41
|
from infrahub.storage import InfrahubObjectStorage
|
|
40
42
|
|
|
41
43
|
if TYPE_CHECKING:
|
|
@@ -117,6 +119,7 @@ async def initialize_registry(db: InfrahubDatabase, initialize: bool = False) ->
|
|
|
117
119
|
registry.node[InfrahubKind.NUMBERPOOL] = CoreNumberPool
|
|
118
120
|
registry.node[InfrahubKind.GLOBALPERMISSION] = CoreGlobalPermission
|
|
119
121
|
registry.node[InfrahubKind.OBJECTPERMISSION] = CoreObjectPermission
|
|
122
|
+
registry.node[InfrahubKind.PROPOSEDCHANGE] = CoreProposedChange
|
|
120
123
|
|
|
121
124
|
# ---------------------------------------------------
|
|
122
125
|
# Instantiate permission backends
|
|
@@ -129,8 +132,6 @@ async def add_indexes(db: InfrahubDatabase) -> None:
|
|
|
129
132
|
index_manager: IndexManagerBase = IndexManagerMemgraph(db=db)
|
|
130
133
|
index_manager = IndexManagerNeo4j(db=db)
|
|
131
134
|
|
|
132
|
-
if config.SETTINGS.experimental_features.value_db_index:
|
|
133
|
-
node_indexes.append(attr_value_index)
|
|
134
135
|
index_manager.init(nodes=node_indexes, rels=rel_indexes)
|
|
135
136
|
log.debug("Loading database indexes ..")
|
|
136
137
|
await index_manager.add()
|
|
@@ -321,7 +322,7 @@ async def create_ipam_namespace(
|
|
|
321
322
|
return obj
|
|
322
323
|
|
|
323
324
|
|
|
324
|
-
async def create_super_administrator_role(db: InfrahubDatabase) ->
|
|
325
|
+
async def create_super_administrator_role(db: InfrahubDatabase) -> CoreAccountRole:
|
|
325
326
|
permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
|
|
326
327
|
await permission.new(
|
|
327
328
|
db=db,
|
|
@@ -333,15 +334,15 @@ async def create_super_administrator_role(db: InfrahubDatabase) -> Node:
|
|
|
333
334
|
log.info(f"Created global permission: {GlobalPermissions.SUPER_ADMIN}")
|
|
334
335
|
|
|
335
336
|
role_name = "Super Administrator"
|
|
336
|
-
|
|
337
|
-
await
|
|
338
|
-
await
|
|
337
|
+
role = await Node.init(db=db, schema=CoreAccountRole)
|
|
338
|
+
await role.new(db=db, name=role_name, permissions=[permission])
|
|
339
|
+
await role.save(db=db)
|
|
339
340
|
log.info(f"Created account role: {role_name}")
|
|
340
341
|
|
|
341
|
-
return
|
|
342
|
+
return role
|
|
342
343
|
|
|
343
344
|
|
|
344
|
-
async def
|
|
345
|
+
async def create_default_role(db: InfrahubDatabase) -> CoreAccountRole:
|
|
345
346
|
repo_permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
|
|
346
347
|
await repo_permission.new(
|
|
347
348
|
db=db,
|
|
@@ -370,20 +371,13 @@ async def create_default_roles(db: InfrahubDatabase) -> Node:
|
|
|
370
371
|
await proposed_change_permission.save(db=db)
|
|
371
372
|
|
|
372
373
|
# Other permissions, created to keep references of them from the start
|
|
373
|
-
for permission_action
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
374
|
+
for permission_action in (
|
|
375
|
+
GlobalPermissions.EDIT_DEFAULT_BRANCH,
|
|
376
|
+
GlobalPermissions.MANAGE_ACCOUNTS,
|
|
377
|
+
GlobalPermissions.MANAGE_PERMISSIONS,
|
|
378
|
+
GlobalPermissions.MERGE_BRANCH,
|
|
378
379
|
):
|
|
379
|
-
|
|
380
|
-
await permission.new(
|
|
381
|
-
db=db,
|
|
382
|
-
action=permission_action.value,
|
|
383
|
-
decision=PermissionDecision.ALLOW_ALL.value,
|
|
384
|
-
description=permission_description,
|
|
385
|
-
)
|
|
386
|
-
await permission.save(db=db)
|
|
380
|
+
await get_or_create_global_permission(db=db, permission=permission_action)
|
|
387
381
|
|
|
388
382
|
view_permission = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
|
|
389
383
|
await view_permission.new(
|
|
@@ -408,7 +402,7 @@ async def create_default_roles(db: InfrahubDatabase) -> Node:
|
|
|
408
402
|
await modify_permission.save(db=db)
|
|
409
403
|
|
|
410
404
|
role_name = "General Access"
|
|
411
|
-
role = await Node.init(db=db, schema=
|
|
405
|
+
role = await Node.init(db=db, schema=CoreAccountRole)
|
|
412
406
|
await role.new(
|
|
413
407
|
db=db,
|
|
414
408
|
name=role_name,
|
|
@@ -423,16 +417,42 @@ async def create_default_roles(db: InfrahubDatabase) -> Node:
|
|
|
423
417
|
await role.save(db=db)
|
|
424
418
|
log.info(f"Created account role: {role_name}")
|
|
425
419
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
420
|
+
return role
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
async def create_proposed_change_reviewer_role(db: InfrahubDatabase) -> CoreAccountRole:
|
|
424
|
+
edit_default_branch_permission = await get_or_create_global_permission(
|
|
425
|
+
db=db, permission=GlobalPermissions.EDIT_DEFAULT_BRANCH
|
|
426
|
+
)
|
|
427
|
+
reviewer_permission = await get_or_create_global_permission(
|
|
428
|
+
db=db, permission=GlobalPermissions.REVIEW_PROPOSED_CHANGE
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
proposed_change_update_permission = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
|
|
432
|
+
await proposed_change_update_permission.new(
|
|
433
|
+
db=db,
|
|
434
|
+
name="ProposedChange",
|
|
435
|
+
namespace="Core",
|
|
436
|
+
action=PermissionAction.UPDATE.value,
|
|
437
|
+
decision=PermissionDecision.ALLOW_ALL.value,
|
|
438
|
+
description="Allow a user to update proposed changes",
|
|
439
|
+
)
|
|
440
|
+
await proposed_change_update_permission.save(db=db)
|
|
441
|
+
|
|
442
|
+
role_name = "Proposed Change Reviewer"
|
|
443
|
+
role = await Node.init(db=db, schema=CoreAccountRole)
|
|
444
|
+
await role.new(
|
|
445
|
+
db=db,
|
|
446
|
+
name=role_name,
|
|
447
|
+
permissions=[edit_default_branch_permission, reviewer_permission, proposed_change_update_permission],
|
|
448
|
+
)
|
|
449
|
+
await role.save(db=db)
|
|
450
|
+
log.info(f"Created account role: {role_name}")
|
|
431
451
|
|
|
432
452
|
return role
|
|
433
453
|
|
|
434
454
|
|
|
435
|
-
async def create_anonymous_role(db: InfrahubDatabase) ->
|
|
455
|
+
async def create_anonymous_role(db: InfrahubDatabase) -> CoreAccountRole:
|
|
436
456
|
deny_permission = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
|
|
437
457
|
await deny_permission.new(
|
|
438
458
|
db=db, name="*", namespace="*", action=PermissionAction.ANY.value, decision=PermissionDecision.DENY.value
|
|
@@ -445,7 +465,7 @@ async def create_anonymous_role(db: InfrahubDatabase) -> Node:
|
|
|
445
465
|
hfid=["*", "*", PermissionAction.VIEW.value, str(PermissionDecision.ALLOW_ALL.value)],
|
|
446
466
|
)
|
|
447
467
|
|
|
448
|
-
role = await Node.init(db=db, schema=
|
|
468
|
+
role = await Node.init(db=db, schema=CoreAccountRole)
|
|
449
469
|
await role.new(
|
|
450
470
|
db=db, name=config.SETTINGS.main.anonymous_access_role, permissions=[deny_permission, view_permission]
|
|
451
471
|
)
|
|
@@ -455,23 +475,39 @@ async def create_anonymous_role(db: InfrahubDatabase) -> Node:
|
|
|
455
475
|
return role
|
|
456
476
|
|
|
457
477
|
|
|
458
|
-
async def
|
|
459
|
-
db: InfrahubDatabase,
|
|
460
|
-
) ->
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
await group.new(db=db, name=group_name, roles=[role])
|
|
478
|
+
async def create_accounts_group(
|
|
479
|
+
db: InfrahubDatabase, name: str, roles: Sequence[CoreAccountRole], accounts: Sequence[CoreAccount]
|
|
480
|
+
) -> CoreAccountGroup:
|
|
481
|
+
group = await Node.init(db=db, schema=CoreAccountGroup)
|
|
482
|
+
await group.new(db=db, name=name, roles=list(roles))
|
|
464
483
|
await group.save(db=db)
|
|
465
|
-
log.info(f"Created account group: {
|
|
484
|
+
log.info(f"Created account group: {name}")
|
|
466
485
|
|
|
467
|
-
for
|
|
468
|
-
await group.members.add(db=db, data=
|
|
469
|
-
await group.members.save(db=db)
|
|
470
|
-
log.info(f"Assigned account group: {
|
|
486
|
+
for account in accounts:
|
|
487
|
+
await group.members.add(db=db, data=account) # type: ignore[arg-type]
|
|
488
|
+
await group.members.save(db=db)
|
|
489
|
+
log.info(f"Assigned account group: {name} to {account.name.value}")
|
|
471
490
|
|
|
472
491
|
return group
|
|
473
492
|
|
|
474
493
|
|
|
494
|
+
async def create_default_account_groups(
|
|
495
|
+
db: InfrahubDatabase,
|
|
496
|
+
admin_accounts: Sequence[CoreAccount] | None = None,
|
|
497
|
+
accounts: Sequence[CoreAccount] | None = None,
|
|
498
|
+
) -> None:
|
|
499
|
+
administrator_role = await create_super_administrator_role(db=db)
|
|
500
|
+
await create_accounts_group(
|
|
501
|
+
db=db, name="Super Administrators", roles=[administrator_role], accounts=admin_accounts or []
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
default_role = await create_default_role(db=db)
|
|
505
|
+
proposed_change_reviewer_role = await create_proposed_change_reviewer_role(db=db)
|
|
506
|
+
await create_accounts_group(
|
|
507
|
+
db=db, name="Infrahub Users", roles=[default_role, proposed_change_reviewer_role], accounts=accounts or []
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
|
|
475
511
|
async def first_time_initialization(db: InfrahubDatabase) -> None:
|
|
476
512
|
# --------------------------------------------------
|
|
477
513
|
# Create the default Branch
|
|
@@ -522,12 +558,10 @@ async def first_time_initialization(db: InfrahubDatabase) -> None:
|
|
|
522
558
|
)
|
|
523
559
|
|
|
524
560
|
# --------------------------------------------------
|
|
525
|
-
# Create
|
|
561
|
+
# Create default account roles, groups and permissions
|
|
526
562
|
# --------------------------------------------------
|
|
527
|
-
|
|
528
|
-
await create_super_administrators_group(db=db, role=administrator_role, admin_accounts=admin_accounts)
|
|
563
|
+
await create_default_account_groups(db=db, admin_accounts=admin_accounts)
|
|
529
564
|
|
|
530
|
-
await create_default_roles(db=db)
|
|
531
565
|
if config.SETTINGS.main.allow_anonymous_access:
|
|
532
566
|
await create_anonymous_role(db=db)
|
|
533
567
|
|
infrahub/core/ipam/tasks.py
CHANGED
|
@@ -5,7 +5,7 @@ from prefect import flow
|
|
|
5
5
|
|
|
6
6
|
from infrahub.core import registry
|
|
7
7
|
from infrahub.core.ipam.reconciler import IpamReconciler
|
|
8
|
-
from infrahub.
|
|
8
|
+
from infrahub.workers.dependencies import get_database
|
|
9
9
|
from infrahub.workflows.utils import add_branch_tag
|
|
10
10
|
|
|
11
11
|
from .model import IpamNodeDetails
|
|
@@ -20,8 +20,9 @@ if TYPE_CHECKING:
|
|
|
20
20
|
description="Ensure the IPAM Tree is up to date",
|
|
21
21
|
persist_result=False,
|
|
22
22
|
)
|
|
23
|
-
async def ipam_reconciliation(branch: str, ipam_node_details: list[IpamNodeDetails]
|
|
24
|
-
|
|
23
|
+
async def ipam_reconciliation(branch: str, ipam_node_details: list[IpamNodeDetails]) -> None:
|
|
24
|
+
database = await get_database()
|
|
25
|
+
async with database.start_session() as db:
|
|
25
26
|
branch_obj = await registry.get_branch(db=db, branch=branch)
|
|
26
27
|
|
|
27
28
|
await add_branch_tag(branch_name=branch_obj.name)
|
infrahub/core/merge.py
CHANGED
|
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
|
|
|
26
26
|
from infrahub.core.schema.manager import SchemaDiff
|
|
27
27
|
from infrahub.core.schema.schema_branch import SchemaBranch
|
|
28
28
|
from infrahub.database import InfrahubDatabase
|
|
29
|
-
from infrahub.services import
|
|
29
|
+
from infrahub.services.adapters.workflow import InfrahubWorkflow
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
log = get_logger()
|
|
@@ -42,7 +42,7 @@ class BranchMerger:
|
|
|
42
42
|
diff_repository: DiffRepository,
|
|
43
43
|
diff_locker: DiffLocker,
|
|
44
44
|
destination_branch: Branch | None = None,
|
|
45
|
-
|
|
45
|
+
workflow: InfrahubWorkflow | None = None,
|
|
46
46
|
):
|
|
47
47
|
self.source_branch = source_branch
|
|
48
48
|
self.destination_branch: Branch = destination_branch or registry.get_branch_from_registry()
|
|
@@ -58,7 +58,7 @@ class BranchMerger:
|
|
|
58
58
|
self._destination_schema: SchemaBranch | None = None
|
|
59
59
|
self._initial_source_schema: SchemaBranch | None = None
|
|
60
60
|
|
|
61
|
-
self.
|
|
61
|
+
self._workflow = workflow
|
|
62
62
|
|
|
63
63
|
@property
|
|
64
64
|
def source_schema(self) -> SchemaBranch:
|
|
@@ -81,10 +81,10 @@ class BranchMerger:
|
|
|
81
81
|
raise ValueError("_initial_source_schema hasn't been initialized")
|
|
82
82
|
|
|
83
83
|
@property
|
|
84
|
-
def
|
|
85
|
-
if not self.
|
|
86
|
-
raise ValueError("BranchMerger hasn't been initialized with a
|
|
87
|
-
return self.
|
|
84
|
+
def workflow(self) -> InfrahubWorkflow:
|
|
85
|
+
if not self._workflow:
|
|
86
|
+
raise ValueError("BranchMerger hasn't been initialized with a workflow object")
|
|
87
|
+
return self._workflow
|
|
88
88
|
|
|
89
89
|
async def get_initial_source_branch(self) -> SchemaBranch:
|
|
90
90
|
"""Retrieve the schema of the source branch when the branch was created.
|
|
@@ -246,6 +246,4 @@ class BranchMerger:
|
|
|
246
246
|
destination_branch_id=str(self.destination_branch.get_uuid()),
|
|
247
247
|
default_branch=repo.default_branch.value,
|
|
248
248
|
)
|
|
249
|
-
await self.
|
|
250
|
-
workflow=GIT_REPOSITORIES_MERGE, parameters={"model": model}
|
|
251
|
-
)
|
|
249
|
+
await self.workflow.submit_workflow(workflow=GIT_REPOSITORIES_MERGE, parameters={"model": model})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from .schema.attribute_kind_update import AttributeKindUpdateMigration
|
|
1
2
|
from .schema.attribute_name_update import AttributeNameUpdateMigration
|
|
2
3
|
from .schema.node_attribute_add import NodeAttributeAddMigration
|
|
3
4
|
from .schema.node_attribute_remove import NodeAttributeRemoveMigration
|
|
@@ -17,6 +18,7 @@ MIGRATION_MAP: dict[str, type[SchemaMigration] | None] = {
|
|
|
17
18
|
"node.relationship.remove": PlaceholderDummyMigration,
|
|
18
19
|
"attribute.name.update": AttributeNameUpdateMigration,
|
|
19
20
|
"attribute.branch.update": None,
|
|
21
|
+
"attribute.kind.update": AttributeKindUpdateMigration,
|
|
20
22
|
"relationship.branch.update": None,
|
|
21
23
|
"relationship.direction.update": None,
|
|
22
24
|
"relationship.identifier.update": PlaceholderDummyMigration,
|
|
@@ -37,6 +37,8 @@ from .m032_cleanup_orphaned_branch_relationships import Migration032
|
|
|
37
37
|
from .m033_deduplicate_relationship_vertices import Migration033
|
|
38
38
|
from .m034_find_orphaned_schema_fields import Migration034
|
|
39
39
|
from .m035_orphan_relationships import Migration035
|
|
40
|
+
from .m036_drop_attr_value_index import Migration036
|
|
41
|
+
from .m037_index_attr_vals import Migration037
|
|
40
42
|
|
|
41
43
|
if TYPE_CHECKING:
|
|
42
44
|
from infrahub.core.root import Root
|
|
@@ -79,6 +81,8 @@ MIGRATIONS: list[type[GraphMigration | InternalSchemaMigration | ArbitraryMigrat
|
|
|
79
81
|
Migration033,
|
|
80
82
|
Migration034,
|
|
81
83
|
Migration035,
|
|
84
|
+
Migration036,
|
|
85
|
+
Migration037,
|
|
82
86
|
]
|
|
83
87
|
|
|
84
88
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Sequence
|
|
4
|
+
|
|
5
|
+
from infrahub.constants.database import IndexType
|
|
6
|
+
from infrahub.core.migrations.shared import MigrationResult
|
|
7
|
+
from infrahub.core.query import Query # noqa: TC001
|
|
8
|
+
from infrahub.database import DatabaseType
|
|
9
|
+
from infrahub.database.index import IndexItem
|
|
10
|
+
from infrahub.database.neo4j import IndexManagerNeo4j
|
|
11
|
+
|
|
12
|
+
from ..shared import GraphMigration
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from infrahub.database import InfrahubDatabase
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
INDEX_TO_DELETE = IndexItem(name="attr_value", label="AttributeValue", properties=["value"], type=IndexType.RANGE)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Migration036(GraphMigration):
|
|
22
|
+
name: str = "036_drop_attr_value_index"
|
|
23
|
+
queries: Sequence[type[Query]] = []
|
|
24
|
+
minimum_version: int = 35
|
|
25
|
+
|
|
26
|
+
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
27
|
+
result = MigrationResult()
|
|
28
|
+
|
|
29
|
+
# Only execute this migration for Neo4j
|
|
30
|
+
if db.db_type != DatabaseType.NEO4J:
|
|
31
|
+
return result
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
index_manager = IndexManagerNeo4j(db=db)
|
|
35
|
+
index_manager.init(nodes=[INDEX_TO_DELETE], rels=[])
|
|
36
|
+
await index_manager.drop()
|
|
37
|
+
except Exception as exc:
|
|
38
|
+
result.errors.append(str(exc))
|
|
39
|
+
return result
|
|
40
|
+
|
|
41
|
+
return result
|
|
42
|
+
|
|
43
|
+
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
44
|
+
result = MigrationResult()
|
|
45
|
+
return result
|