infrahub-server 1.5.0b1__py3-none-any.whl → 1.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- infrahub/api/dependencies.py +4 -13
- infrahub/api/internal.py +2 -0
- infrahub/api/oauth2.py +13 -19
- infrahub/api/oidc.py +15 -21
- infrahub/api/schema.py +24 -3
- infrahub/api/transformation.py +22 -20
- infrahub/artifacts/models.py +2 -1
- infrahub/auth.py +137 -3
- infrahub/cli/__init__.py +2 -0
- infrahub/cli/db.py +158 -155
- infrahub/cli/dev.py +118 -0
- infrahub/cli/tasks.py +46 -0
- infrahub/cli/upgrade.py +56 -9
- infrahub/computed_attribute/tasks.py +20 -8
- infrahub/core/attribute.py +10 -2
- infrahub/core/branch/enums.py +1 -1
- infrahub/core/branch/models.py +7 -3
- infrahub/core/branch/tasks.py +68 -7
- infrahub/core/constants/__init__.py +3 -0
- infrahub/core/diff/calculator.py +2 -2
- infrahub/core/diff/query/artifact.py +1 -0
- infrahub/core/diff/query/delete_query.py +9 -5
- infrahub/core/diff/query/field_summary.py +1 -0
- infrahub/core/diff/query/merge.py +39 -23
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/initialization.py +5 -2
- infrahub/core/migrations/__init__.py +3 -0
- infrahub/core/migrations/exceptions.py +4 -0
- infrahub/core/migrations/graph/__init__.py +12 -13
- infrahub/core/migrations/graph/load_schema_branch.py +21 -0
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +1 -1
- infrahub/core/migrations/graph/m037_index_attr_vals.py +11 -30
- infrahub/core/migrations/graph/m039_ipam_reconcile.py +9 -7
- infrahub/core/migrations/graph/m040_duplicated_attributes.py +81 -0
- infrahub/core/migrations/graph/m041_deleted_dup_edges.py +149 -0
- infrahub/core/migrations/graph/m042_profile_attrs_in_db.py +147 -0
- infrahub/core/migrations/graph/m043_create_hfid_display_label_in_db.py +164 -0
- infrahub/core/migrations/graph/m044_backfill_hfid_display_label_in_db.py +864 -0
- infrahub/core/migrations/query/__init__.py +7 -8
- infrahub/core/migrations/query/attribute_add.py +8 -6
- infrahub/core/migrations/query/attribute_remove.py +134 -0
- infrahub/core/migrations/runner.py +54 -0
- infrahub/core/migrations/schema/attribute_kind_update.py +9 -3
- infrahub/core/migrations/schema/attribute_supports_profile.py +90 -0
- infrahub/core/migrations/schema/node_attribute_add.py +30 -2
- infrahub/core/migrations/schema/node_attribute_remove.py +13 -109
- infrahub/core/migrations/schema/node_kind_update.py +2 -1
- infrahub/core/migrations/schema/node_remove.py +2 -1
- infrahub/core/migrations/schema/placeholder_dummy.py +3 -2
- infrahub/core/migrations/shared.py +62 -14
- infrahub/core/models.py +2 -2
- infrahub/core/node/__init__.py +42 -12
- infrahub/core/node/create.py +46 -63
- infrahub/core/node/lock_utils.py +70 -44
- infrahub/core/node/resource_manager/ip_address_pool.py +2 -1
- infrahub/core/node/resource_manager/ip_prefix_pool.py +2 -1
- infrahub/core/node/resource_manager/number_pool.py +2 -1
- infrahub/core/query/attribute.py +55 -0
- infrahub/core/query/diff.py +61 -16
- infrahub/core/query/ipam.py +16 -4
- infrahub/core/query/node.py +51 -43
- infrahub/core/query/relationship.py +1 -0
- infrahub/core/relationship/model.py +10 -5
- infrahub/core/schema/__init__.py +56 -0
- infrahub/core/schema/attribute_schema.py +4 -0
- infrahub/core/schema/definitions/core/check.py +1 -1
- infrahub/core/schema/definitions/core/transform.py +1 -1
- infrahub/core/schema/definitions/internal.py +2 -2
- infrahub/core/schema/generated/attribute_schema.py +2 -2
- infrahub/core/schema/manager.py +22 -1
- infrahub/core/schema/schema_branch.py +180 -22
- infrahub/core/schema/schema_branch_display.py +12 -0
- infrahub/core/schema/schema_branch_hfid.py +6 -0
- infrahub/core/validators/uniqueness/checker.py +2 -1
- infrahub/database/__init__.py +0 -13
- infrahub/database/graph.py +21 -0
- infrahub/display_labels/tasks.py +13 -7
- infrahub/events/branch_action.py +27 -1
- infrahub/generators/tasks.py +3 -7
- infrahub/git/base.py +4 -1
- infrahub/git/integrator.py +1 -1
- infrahub/git/models.py +2 -1
- infrahub/git/repository.py +22 -5
- infrahub/git/tasks.py +66 -10
- infrahub/git/utils.py +123 -1
- infrahub/graphql/analyzer.py +9 -0
- infrahub/graphql/api/endpoints.py +14 -4
- infrahub/graphql/manager.py +4 -9
- infrahub/graphql/mutations/branch.py +5 -0
- infrahub/graphql/mutations/convert_object_type.py +11 -1
- infrahub/graphql/mutations/display_label.py +17 -10
- infrahub/graphql/mutations/hfid.py +17 -10
- infrahub/graphql/mutations/ipam.py +54 -35
- infrahub/graphql/mutations/main.py +27 -28
- infrahub/graphql/mutations/proposed_change.py +6 -0
- infrahub/graphql/schema_sort.py +170 -0
- infrahub/graphql/types/branch.py +4 -1
- infrahub/graphql/types/enums.py +3 -0
- infrahub/hfid/tasks.py +13 -7
- infrahub/lock.py +52 -12
- infrahub/message_bus/types.py +3 -1
- infrahub/permissions/constants.py +2 -0
- infrahub/profiles/queries/get_profile_data.py +4 -5
- infrahub/proposed_change/tasks.py +66 -23
- infrahub/server.py +6 -2
- infrahub/services/__init__.py +2 -2
- infrahub/services/adapters/http/__init__.py +5 -0
- infrahub/services/adapters/workflow/worker.py +14 -3
- infrahub/task_manager/event.py +5 -0
- infrahub/task_manager/models.py +7 -0
- infrahub/task_manager/task.py +73 -0
- infrahub/trigger/setup.py +13 -4
- infrahub/trigger/tasks.py +3 -0
- infrahub/workers/dependencies.py +10 -1
- infrahub/workers/infrahub_async.py +10 -2
- infrahub/workflows/catalogue.py +8 -0
- infrahub/workflows/initialization.py +5 -0
- infrahub/workflows/utils.py +2 -1
- infrahub_sdk/analyzer.py +1 -1
- infrahub_sdk/batch.py +2 -2
- infrahub_sdk/branch.py +14 -2
- infrahub_sdk/checks.py +1 -1
- infrahub_sdk/client.py +15 -14
- infrahub_sdk/config.py +29 -2
- infrahub_sdk/ctl/branch.py +3 -0
- infrahub_sdk/ctl/cli_commands.py +2 -0
- infrahub_sdk/ctl/exceptions.py +1 -1
- infrahub_sdk/ctl/schema.py +22 -7
- infrahub_sdk/ctl/task.py +110 -0
- infrahub_sdk/exceptions.py +18 -18
- infrahub_sdk/graphql/query.py +2 -2
- infrahub_sdk/node/attribute.py +1 -1
- infrahub_sdk/node/property.py +1 -1
- infrahub_sdk/node/related_node.py +3 -3
- infrahub_sdk/node/relationship.py +4 -6
- infrahub_sdk/object_store.py +2 -2
- infrahub_sdk/operation.py +1 -1
- infrahub_sdk/protocols_generator/generator.py +1 -1
- infrahub_sdk/pytest_plugin/exceptions.py +9 -9
- infrahub_sdk/pytest_plugin/items/base.py +1 -1
- infrahub_sdk/pytest_plugin/items/check.py +1 -1
- infrahub_sdk/pytest_plugin/items/python_transform.py +1 -1
- infrahub_sdk/repository.py +1 -1
- infrahub_sdk/schema/__init__.py +33 -5
- infrahub_sdk/spec/models.py +7 -0
- infrahub_sdk/spec/object.py +41 -102
- infrahub_sdk/spec/processors/__init__.py +0 -0
- infrahub_sdk/spec/processors/data_processor.py +10 -0
- infrahub_sdk/spec/processors/factory.py +34 -0
- infrahub_sdk/spec/processors/range_expand_processor.py +56 -0
- infrahub_sdk/task/exceptions.py +4 -4
- infrahub_sdk/task/manager.py +2 -2
- infrahub_sdk/task/models.py +6 -4
- infrahub_sdk/timestamp.py +1 -1
- infrahub_sdk/transfer/exporter/json.py +1 -1
- infrahub_sdk/transfer/importer/json.py +1 -1
- infrahub_sdk/transforms.py +1 -1
- {infrahub_server-1.5.0b1.dist-info → infrahub_server-1.5.1.dist-info}/METADATA +4 -2
- {infrahub_server-1.5.0b1.dist-info → infrahub_server-1.5.1.dist-info}/RECORD +168 -152
- infrahub_testcontainers/container.py +144 -6
- infrahub_testcontainers/docker-compose-cluster.test.yml +5 -0
- infrahub_testcontainers/docker-compose.test.yml +5 -0
- infrahub_testcontainers/helpers.py +19 -4
- infrahub_testcontainers/models.py +8 -6
- infrahub_testcontainers/performance_test.py +6 -4
- infrahub/core/migrations/graph/m040_profile_attrs_in_db.py +0 -166
- infrahub/core/migrations/graph/m041_create_hfid_display_label_in_db.py +0 -97
- infrahub/core/migrations/graph/m042_backfill_hfid_display_label_in_db.py +0 -86
- {infrahub_server-1.5.0b1.dist-info → infrahub_server-1.5.1.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.5.0b1.dist-info → infrahub_server-1.5.1.dist-info}/WHEEL +0 -0
- {infrahub_server-1.5.0b1.dist-info → infrahub_server-1.5.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from rich import print as rprint
|
|
6
|
+
|
|
7
|
+
from infrahub.core.branch import Branch
|
|
8
|
+
from infrahub.core.diff.repository.repository import DiffRepository
|
|
9
|
+
from infrahub.core.initialization import get_root_node
|
|
10
|
+
from infrahub.core.migrations.shared import MigrationResult
|
|
11
|
+
from infrahub.core.query import Query, QueryType
|
|
12
|
+
from infrahub.dependencies.registry import build_component_registry, get_component_registry
|
|
13
|
+
from infrahub.log import get_logger
|
|
14
|
+
|
|
15
|
+
from ..shared import ArbitraryMigration
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from infrahub.database import InfrahubDatabase
|
|
19
|
+
|
|
20
|
+
log = get_logger()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DeletePosthumousEdges(Query):
|
|
24
|
+
name = "delete_posthumous_edges_query"
|
|
25
|
+
type = QueryType.WRITE
|
|
26
|
+
insert_return = False
|
|
27
|
+
|
|
28
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
29
|
+
query = """
|
|
30
|
+
// ------------
|
|
31
|
+
// find deleted nodes
|
|
32
|
+
// ------------
|
|
33
|
+
MATCH (n:Node)-[e:IS_PART_OF]->(:Root)
|
|
34
|
+
WHERE e.status = "deleted" OR e.to IS NOT NULL
|
|
35
|
+
WITH DISTINCT n, e.branch AS delete_branch, e.branch_level AS delete_branch_level, CASE
|
|
36
|
+
WHEN e.status = "deleted" THEN e.from
|
|
37
|
+
ELSE e.to
|
|
38
|
+
END AS delete_time
|
|
39
|
+
// ------------
|
|
40
|
+
// find the edges added to the deleted node after the delete time
|
|
41
|
+
// ------------
|
|
42
|
+
MATCH (n)-[added_e]-(peer)
|
|
43
|
+
WHERE added_e.from > delete_time
|
|
44
|
+
AND type(added_e) <> "IS_PART_OF"
|
|
45
|
+
// if the node was deleted on a branch (delete_branch_level > 1), and then updated on main/global (added_e.branch_level = 1), we can ignore it
|
|
46
|
+
AND added_e.branch_level >= delete_branch_level
|
|
47
|
+
AND (added_e.branch = delete_branch OR delete_branch_level = 1)
|
|
48
|
+
WITH DISTINCT n, delete_branch, delete_time, added_e, peer
|
|
49
|
+
// ------------
|
|
50
|
+
// get the branched_from for the branch on which the node was deleted
|
|
51
|
+
// ------------
|
|
52
|
+
CALL (added_e) {
|
|
53
|
+
MATCH (b:Branch {name: added_e.branch})
|
|
54
|
+
RETURN b.branched_from AS added_e_branched_from
|
|
55
|
+
}
|
|
56
|
+
// ------------
|
|
57
|
+
// account for the following situations, given that the edge update time is after the node delete time
|
|
58
|
+
// - deleted on main/global, updated on branch
|
|
59
|
+
// - illegal if the delete is before branch.branched_from
|
|
60
|
+
// - deleted on branch, updated on branch
|
|
61
|
+
// - illegal
|
|
62
|
+
// ------------
|
|
63
|
+
WITH n, delete_branch, delete_time, added_e, peer
|
|
64
|
+
WHERE delete_branch = added_e.branch
|
|
65
|
+
OR delete_time < added_e_branched_from
|
|
66
|
+
DELETE added_e
|
|
67
|
+
"""
|
|
68
|
+
self.add_to_query(query)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class DeleteDuplicateEdgesForMigratedKindNodes(Query):
|
|
72
|
+
name = "delete_duplicate_edges_for_migrated_kind_nodes_query"
|
|
73
|
+
type = QueryType.WRITE
|
|
74
|
+
insert_return = False
|
|
75
|
+
|
|
76
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
77
|
+
query = """
|
|
78
|
+
// ------------
|
|
79
|
+
// get UUIDs for migrated kind/inheritance nodes
|
|
80
|
+
// ------------
|
|
81
|
+
MATCH (n:Node)
|
|
82
|
+
WITH n.uuid AS node_uuid, count(*) AS num_nodes_with_uuid
|
|
83
|
+
WHERE num_nodes_with_uuid > 1
|
|
84
|
+
CALL (node_uuid) {
|
|
85
|
+
// ------------
|
|
86
|
+
// find any Relationships for these nodes
|
|
87
|
+
// ------------
|
|
88
|
+
MATCH (n:Node {uuid: node_uuid})-[:IS_RELATED]-(rel:Relationship)
|
|
89
|
+
WITH DISTINCT rel
|
|
90
|
+
MATCH (rel)-[e]->(peer)
|
|
91
|
+
WITH
|
|
92
|
+
type(e) AS e_type,
|
|
93
|
+
e.branch AS e_branch,
|
|
94
|
+
e.from AS e_from,
|
|
95
|
+
e.to AS e_to,
|
|
96
|
+
e.status AS e_status,
|
|
97
|
+
e.peer AS e_peer,
|
|
98
|
+
CASE
|
|
99
|
+
WHEN startNode(e) = rel THEN "out" ELSE "in"
|
|
100
|
+
END AS direction,
|
|
101
|
+
collect(e) AS duplicate_edges
|
|
102
|
+
WHERE size(duplicate_edges) > 1
|
|
103
|
+
WITH tail(duplicate_edges) AS duplicate_edges_to_delete
|
|
104
|
+
UNWIND duplicate_edges_to_delete AS edge_to_delete
|
|
105
|
+
DELETE edge_to_delete
|
|
106
|
+
} IN TRANSACTIONS OF 500 ROWS
|
|
107
|
+
"""
|
|
108
|
+
self.add_to_query(query)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class Migration041(ArbitraryMigration):
|
|
112
|
+
"""Clean up improper merges that duplicated edges to nodes with migrated kinds
|
|
113
|
+
|
|
114
|
+
- delete all existing diffs b/c they could contain incorrect nodes linking to deleted nodes with migrated kind/inheritance
|
|
115
|
+
- delete all edges added to any nodes AFTER they were deleted on main
|
|
116
|
+
- delete any duplicate edges touching migrated kind/inheritance nodes on main
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
name: str = "041_deleted_dup_edges"
|
|
120
|
+
minimum_version: int = 40
|
|
121
|
+
|
|
122
|
+
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
123
|
+
result = MigrationResult()
|
|
124
|
+
|
|
125
|
+
return result
|
|
126
|
+
|
|
127
|
+
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
128
|
+
root_node = await get_root_node(db=db)
|
|
129
|
+
default_branch_name = root_node.default_branch
|
|
130
|
+
default_branch = await Branch.get_by_name(db=db, name=default_branch_name)
|
|
131
|
+
|
|
132
|
+
rprint("Deleting all diffs", end="...")
|
|
133
|
+
build_component_registry()
|
|
134
|
+
component_registry = get_component_registry()
|
|
135
|
+
diff_repo = await component_registry.get_component(DiffRepository, db=db, branch=default_branch)
|
|
136
|
+
await diff_repo.delete_all_diff_roots()
|
|
137
|
+
rprint("done")
|
|
138
|
+
|
|
139
|
+
rprint("Deleting edges merged after node deleted", end="...")
|
|
140
|
+
delete_posthumous_edges_query = await DeletePosthumousEdges.init(db=db)
|
|
141
|
+
await delete_posthumous_edges_query.execute(db=db)
|
|
142
|
+
rprint("done")
|
|
143
|
+
|
|
144
|
+
rprint("Deleting duplicate edges for migrated kind/inheritance nodes", end="...")
|
|
145
|
+
delete_duplicate_edges_query = await DeleteDuplicateEdgesForMigratedKindNodes.init(db=db)
|
|
146
|
+
await delete_duplicate_edges_query.execute(db=db)
|
|
147
|
+
rprint("done")
|
|
148
|
+
|
|
149
|
+
return MigrationResult()
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from rich.progress import Progress
|
|
6
|
+
|
|
7
|
+
from infrahub.core.branch.models import Branch
|
|
8
|
+
from infrahub.core.initialization import get_root_node
|
|
9
|
+
from infrahub.core.manager import NodeManager
|
|
10
|
+
from infrahub.core.migrations.shared import MigrationResult, get_migration_console
|
|
11
|
+
from infrahub.core.query import Query, QueryType
|
|
12
|
+
from infrahub.core.timestamp import Timestamp
|
|
13
|
+
from infrahub.log import get_logger
|
|
14
|
+
from infrahub.profiles.node_applier import NodeProfilesApplier
|
|
15
|
+
|
|
16
|
+
from ..shared import MigrationRequiringRebase
|
|
17
|
+
from .load_schema_branch import get_or_load_schema_branch
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from infrahub.database import InfrahubDatabase
|
|
21
|
+
|
|
22
|
+
log = get_logger()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class GetUpdatedProfilesForBranchQuery(Query):
|
|
26
|
+
"""
|
|
27
|
+
Get CoreProfile UUIDs with updated attributes on this branch
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
name = "get_profiles_by_branch"
|
|
31
|
+
type = QueryType.READ
|
|
32
|
+
|
|
33
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
34
|
+
self.params["branch"] = self.branch.name
|
|
35
|
+
query = """
|
|
36
|
+
MATCH (profile:CoreProfile)-[:HAS_ATTRIBUTE]->(attr:Attribute)-[e:HAS_VALUE]->(:AttributeValue)
|
|
37
|
+
WHERE e.branch = $branch
|
|
38
|
+
WITH DISTINCT profile.uuid AS profile_uuid
|
|
39
|
+
"""
|
|
40
|
+
self.add_to_query(query)
|
|
41
|
+
self.return_labels = ["profile_uuid"]
|
|
42
|
+
|
|
43
|
+
def get_profile_ids(self) -> list[str]:
|
|
44
|
+
"""Get list of updated profile UUIDs"""
|
|
45
|
+
return [result.get_as_type("profile_uuid", str) for result in self.get_results()]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class GetNodesWithProfileUpdatesForBranchQuery(Query):
|
|
49
|
+
"""
|
|
50
|
+
Get Node UUIDs by which branches they have updated profiles on
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
name = "get_nodes_with_profile_updates_by_branch"
|
|
54
|
+
type = QueryType.READ
|
|
55
|
+
|
|
56
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
57
|
+
self.params["branch"] = self.branch.name
|
|
58
|
+
query = """
|
|
59
|
+
MATCH (node:Node)-[e:IS_RELATED]->(:Relationship {name: "node__profile"})
|
|
60
|
+
WHERE NOT node:CoreProfile
|
|
61
|
+
AND e.branch = $branch
|
|
62
|
+
WITH DISTINCT node.uuid AS node_uuid
|
|
63
|
+
"""
|
|
64
|
+
self.add_to_query(query)
|
|
65
|
+
self.return_labels = ["node_uuid"]
|
|
66
|
+
|
|
67
|
+
def get_node_ids(self) -> list[str]:
|
|
68
|
+
"""Get list of updated node UUIDs"""
|
|
69
|
+
return [result.get_as_type("node_uuid", str) for result in self.get_results()]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Migration042(MigrationRequiringRebase):
|
|
73
|
+
"""
|
|
74
|
+
Save profile attribute values on each node using the profile in the database
|
|
75
|
+
For any profile that has updates on a given branch (including default branch)
|
|
76
|
+
- run NodeProfilesApplier.apply_profiles on each node related to the profile on that branch
|
|
77
|
+
For any node that has an updated relationship to a profile on a given branch
|
|
78
|
+
- run NodeProfilesApplier.apply_profiles on the node on that branch
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
name: str = "042_profile_attrs_in_db"
|
|
82
|
+
minimum_version: int = 41
|
|
83
|
+
|
|
84
|
+
def _get_profile_applier(self, db: InfrahubDatabase, branch: Branch) -> NodeProfilesApplier:
|
|
85
|
+
return NodeProfilesApplier(db=db, branch=branch)
|
|
86
|
+
|
|
87
|
+
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
88
|
+
return MigrationResult()
|
|
89
|
+
|
|
90
|
+
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
91
|
+
root_node = await get_root_node(db=db, initialize=False)
|
|
92
|
+
default_branch_name = root_node.default_branch
|
|
93
|
+
default_branch = await Branch.get_by_name(db=db, name=default_branch_name)
|
|
94
|
+
return await self._do_execute_for_branch(db=db, branch=default_branch)
|
|
95
|
+
|
|
96
|
+
async def execute_against_branch(self, db: InfrahubDatabase, branch: Branch) -> MigrationResult:
|
|
97
|
+
return await self._do_execute_for_branch(db=db, branch=branch)
|
|
98
|
+
|
|
99
|
+
async def _do_execute_for_branch(self, db: InfrahubDatabase, branch: Branch) -> MigrationResult:
|
|
100
|
+
console = get_migration_console()
|
|
101
|
+
result = MigrationResult()
|
|
102
|
+
await get_or_load_schema_branch(db=db, branch=branch)
|
|
103
|
+
|
|
104
|
+
console.print(f"Gathering profiles for branch {branch.name}...", end="")
|
|
105
|
+
get_updated_profiles_for_branch_query = await GetUpdatedProfilesForBranchQuery.init(db=db, branch=branch)
|
|
106
|
+
await get_updated_profiles_for_branch_query.execute(db=db)
|
|
107
|
+
profile_ids = get_updated_profiles_for_branch_query.get_profile_ids()
|
|
108
|
+
|
|
109
|
+
profiles_map = await NodeManager.get_many(db=db, branch=branch, ids=list(profile_ids))
|
|
110
|
+
console.print("done")
|
|
111
|
+
|
|
112
|
+
node_ids_to_update: set[str] = set()
|
|
113
|
+
with Progress(console=console) as progress:
|
|
114
|
+
gather_nodes_task = progress.add_task(
|
|
115
|
+
f"Gathering affected objects for each profile on branch {branch.name}...", total=len(profiles_map)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
for profile in profiles_map.values():
|
|
119
|
+
node_relationship_manager = profile.get_relationship("related_nodes")
|
|
120
|
+
node_peers = await node_relationship_manager.get_db_peers(db=db)
|
|
121
|
+
node_ids_to_update.update(str(peer.peer_id) for peer in node_peers)
|
|
122
|
+
progress.update(gather_nodes_task, advance=1)
|
|
123
|
+
console.log(f"Collected nodes impacted by profiles on branch {branch.name}.")
|
|
124
|
+
|
|
125
|
+
console.print("Identifying nodes with profile updates by branch...", end="")
|
|
126
|
+
get_nodes_with_profile_updates_by_branch_query = await GetNodesWithProfileUpdatesForBranchQuery.init(
|
|
127
|
+
db=db, branch=branch
|
|
128
|
+
)
|
|
129
|
+
await get_nodes_with_profile_updates_by_branch_query.execute(db=db)
|
|
130
|
+
node_ids_to_update.update(get_nodes_with_profile_updates_by_branch_query.get_node_ids())
|
|
131
|
+
console.print("done")
|
|
132
|
+
|
|
133
|
+
right_now = Timestamp()
|
|
134
|
+
console.log("Applying profiles to nodes...")
|
|
135
|
+
with Progress(console=console) as progress:
|
|
136
|
+
apply_task = progress.add_task("Applying profiles to nodes...", total=len(node_ids_to_update))
|
|
137
|
+
applier = self._get_profile_applier(db=db, branch=branch)
|
|
138
|
+
for node_id in node_ids_to_update:
|
|
139
|
+
node = await NodeManager.get_one(db=db, branch=branch, id=node_id, at=right_now)
|
|
140
|
+
if node:
|
|
141
|
+
updated_field_names = await applier.apply_profiles(node=node)
|
|
142
|
+
if updated_field_names:
|
|
143
|
+
await node.save(db=db, fields=updated_field_names, at=right_now)
|
|
144
|
+
progress.update(apply_task, advance=1)
|
|
145
|
+
console.log("Completed applying profiles to nodes.")
|
|
146
|
+
|
|
147
|
+
return result
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from rich.progress import Progress
|
|
6
|
+
|
|
7
|
+
from infrahub.core import registry
|
|
8
|
+
from infrahub.core.branch import Branch
|
|
9
|
+
from infrahub.core.constants import SchemaPathType
|
|
10
|
+
from infrahub.core.initialization import get_root_node
|
|
11
|
+
from infrahub.core.migrations.schema.node_attribute_add import NodeAttributeAddMigration
|
|
12
|
+
from infrahub.core.migrations.shared import MigrationRequiringRebase, MigrationResult, get_migration_console
|
|
13
|
+
from infrahub.core.path import SchemaPath
|
|
14
|
+
from infrahub.core.query import Query, QueryType
|
|
15
|
+
|
|
16
|
+
from .load_schema_branch import get_or_load_schema_branch
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from infrahub.database import InfrahubDatabase
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class GetAddedNodesByKindForBranchQuery(Query):
|
|
23
|
+
name = "get_added_nodes_by_kind_for_branch_query"
|
|
24
|
+
type = QueryType.READ
|
|
25
|
+
insert_return = True
|
|
26
|
+
|
|
27
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
28
|
+
self.params["branch"] = self.branch.name
|
|
29
|
+
query = """
|
|
30
|
+
MATCH (n:Node)-[e:IS_PART_OF {branch: $branch, status: "active"}]->(:Root)
|
|
31
|
+
WHERE e.to IS NULL
|
|
32
|
+
AND NOT exists((n)-[:IS_PART_OF {branch: $branch, status: "deleted"}]->(:Root))
|
|
33
|
+
WITH n.kind AS kind, collect(n.uuid) AS node_ids
|
|
34
|
+
"""
|
|
35
|
+
self.return_labels = ["kind", "node_ids"]
|
|
36
|
+
self.add_to_query(query)
|
|
37
|
+
|
|
38
|
+
def get_node_ids_by_kind(self) -> dict[str, list[str]]:
|
|
39
|
+
node_ids_by_kind: dict[str, list[str]] = {}
|
|
40
|
+
for result in self.get_results():
|
|
41
|
+
kind = result.get_as_type(label="kind", return_type=str)
|
|
42
|
+
node_ids: list[str] = result.get_as_type(label="node_ids", return_type=list)
|
|
43
|
+
node_ids_by_kind[kind] = node_ids
|
|
44
|
+
return node_ids_by_kind
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Migration043(MigrationRequiringRebase):
|
|
48
|
+
name: str = "043_create_hfid_display_label_in_db"
|
|
49
|
+
minimum_version: int = 42
|
|
50
|
+
|
|
51
|
+
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
52
|
+
result = MigrationResult()
|
|
53
|
+
|
|
54
|
+
root_node = await get_root_node(db=db, initialize=False)
|
|
55
|
+
default_branch_name = root_node.default_branch
|
|
56
|
+
default_branch = await Branch.get_by_name(db=db, name=default_branch_name)
|
|
57
|
+
main_schema_branch = await get_or_load_schema_branch(db=db, branch=default_branch)
|
|
58
|
+
schema_node = main_schema_branch.get_node(name="SchemaNode")
|
|
59
|
+
schema_generic = main_schema_branch.get_node(name="SchemaGeneric")
|
|
60
|
+
|
|
61
|
+
migrations = [
|
|
62
|
+
# HFID is not needed, it was introduced at graph v8
|
|
63
|
+
NodeAttributeAddMigration(
|
|
64
|
+
new_node_schema=schema_node,
|
|
65
|
+
previous_node_schema=schema_node,
|
|
66
|
+
schema_path=SchemaPath(
|
|
67
|
+
schema_kind="SchemaNode", path_type=SchemaPathType.ATTRIBUTE, field_name="display_label"
|
|
68
|
+
),
|
|
69
|
+
),
|
|
70
|
+
NodeAttributeAddMigration(
|
|
71
|
+
new_node_schema=schema_generic,
|
|
72
|
+
previous_node_schema=schema_generic,
|
|
73
|
+
schema_path=SchemaPath(
|
|
74
|
+
schema_kind="SchemaGeneric", path_type=SchemaPathType.ATTRIBUTE, field_name="display_label"
|
|
75
|
+
),
|
|
76
|
+
),
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
for node_schema_kind in main_schema_branch.node_names:
|
|
80
|
+
schema = main_schema_branch.get(name=node_schema_kind, duplicate=False)
|
|
81
|
+
migrations.extend(
|
|
82
|
+
[
|
|
83
|
+
NodeAttributeAddMigration(
|
|
84
|
+
new_node_schema=schema,
|
|
85
|
+
previous_node_schema=schema,
|
|
86
|
+
schema_path=SchemaPath(
|
|
87
|
+
schema_kind=schema.kind, path_type=SchemaPathType.ATTRIBUTE, field_name="human_friendly_id"
|
|
88
|
+
),
|
|
89
|
+
),
|
|
90
|
+
NodeAttributeAddMigration(
|
|
91
|
+
new_node_schema=schema,
|
|
92
|
+
previous_node_schema=schema,
|
|
93
|
+
schema_path=SchemaPath(
|
|
94
|
+
schema_kind=schema.kind, path_type=SchemaPathType.ATTRIBUTE, field_name="display_label"
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
]
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
with Progress(console=get_migration_console()) as progress:
|
|
101
|
+
update_task = progress.add_task("Adding HFID and display label to nodes", total=len(migrations))
|
|
102
|
+
|
|
103
|
+
for migration in migrations:
|
|
104
|
+
try:
|
|
105
|
+
execution_result = await migration.execute(db=db, branch=default_branch)
|
|
106
|
+
result.errors.extend(execution_result.errors)
|
|
107
|
+
progress.update(update_task, advance=1)
|
|
108
|
+
except Exception as exc:
|
|
109
|
+
result.errors.append(str(exc))
|
|
110
|
+
return result
|
|
111
|
+
|
|
112
|
+
return result
|
|
113
|
+
|
|
114
|
+
async def execute_against_branch(self, db: InfrahubDatabase, branch: Branch) -> MigrationResult:
|
|
115
|
+
result = MigrationResult()
|
|
116
|
+
|
|
117
|
+
schema_branch = await registry.schema.load_schema_from_db(db=db, branch=branch)
|
|
118
|
+
|
|
119
|
+
migrations = []
|
|
120
|
+
get_added_nodes_by_kind_for_branch_query = await GetAddedNodesByKindForBranchQuery.init(db=db, branch=branch)
|
|
121
|
+
await get_added_nodes_by_kind_for_branch_query.execute(db=db)
|
|
122
|
+
node_ids_by_kind = get_added_nodes_by_kind_for_branch_query.get_node_ids_by_kind()
|
|
123
|
+
|
|
124
|
+
for node_kind, node_ids in node_ids_by_kind.items():
|
|
125
|
+
schema = schema_branch.get(name=node_kind, duplicate=False)
|
|
126
|
+
migrations.extend(
|
|
127
|
+
[
|
|
128
|
+
NodeAttributeAddMigration(
|
|
129
|
+
uuids=node_ids,
|
|
130
|
+
new_node_schema=schema,
|
|
131
|
+
previous_node_schema=schema,
|
|
132
|
+
schema_path=SchemaPath(
|
|
133
|
+
schema_kind=schema.kind, path_type=SchemaPathType.ATTRIBUTE, field_name="human_friendly_id"
|
|
134
|
+
),
|
|
135
|
+
),
|
|
136
|
+
NodeAttributeAddMigration(
|
|
137
|
+
uuids=node_ids,
|
|
138
|
+
new_node_schema=schema,
|
|
139
|
+
previous_node_schema=schema,
|
|
140
|
+
schema_path=SchemaPath(
|
|
141
|
+
schema_kind=schema.kind, path_type=SchemaPathType.ATTRIBUTE, field_name="display_label"
|
|
142
|
+
),
|
|
143
|
+
),
|
|
144
|
+
]
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
with Progress(console=get_migration_console()) as progress:
|
|
148
|
+
update_task = progress.add_task(
|
|
149
|
+
f"Adding HFID and display label to nodes on branch {branch.name}", total=len(migrations)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
for migration in migrations:
|
|
153
|
+
try:
|
|
154
|
+
execution_result = await migration.execute(db=db, branch=branch)
|
|
155
|
+
result.errors.extend(execution_result.errors)
|
|
156
|
+
progress.update(update_task, advance=1)
|
|
157
|
+
except Exception as exc:
|
|
158
|
+
result.errors.append(str(exc))
|
|
159
|
+
return result
|
|
160
|
+
|
|
161
|
+
return result
|
|
162
|
+
|
|
163
|
+
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
164
|
+
return MigrationResult()
|