Skip to content

Commit b3d1222

Browse files
authored
Merge pull request #7630 from opsmill/pog-release-1.5-into-develop-20251111
Merge 'release-1.5' into 'develop' with resolved conflicts
2 parents bd1f781 + 81a10c4 commit b3d1222

File tree

67 files changed

+1151
-215
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1151
-215
lines changed

.github/workflows/version-upgrade.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ jobs:
126126
run: invoke dev.build
127127

128128
- name: Upgrade Infrahub and apply the latest database migrations
129-
run: invoke dev.upgrade
129+
run: invoke dev.upgrade --rebase-branches
130130

131131
- name: Start Demo
132132
run: invoke dev.start
@@ -136,8 +136,8 @@ jobs:
136136
PORT=$(docker compose -p $INFRAHUB_BUILD_NAME port server 8000 | cut -d: -f2)
137137
echo "INFRAHUB_ADDRESS=http://localhost:${PORT}" >> $GITHUB_ENV
138138
139-
- name: Test branch rebase
140-
run: poetry run invoke dev.test-branch-rebase --branch atl1-delete-upstream --data-to-check $DATA_NAME
139+
- name: Verify branch graph version
140+
run: poetry run invoke dev.test-branch-graph-version --branch atl1-delete-upstream
141141

142142
- name: Containers after tests
143143
if: always()

.vale/styles/spelling-exceptions.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ pseudocode
177177
psutil
178178
PyPI
179179
query_peers
180+
quiescing
180181
rebase
181182
rebased
182183
rebasing
@@ -197,6 +198,7 @@ sdk
197198
SLA
198199
SLAs
199200
Slurp'it
201+
snapshotting
200202
streamlit
201203
Streamlit
202204
subcommand

CHANGELOG.md

Lines changed: 378 additions & 0 deletions
Large diffs are not rendered by default.

backend/infrahub/cli/db.py

Lines changed: 87 additions & 65 deletions
Large diffs are not rendered by default.

backend/infrahub/cli/upgrade.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from deepdiff import DeepDiff
99
from infrahub_sdk.async_typer import AsyncTyper
1010
from prefect.client.orchestration import get_client
11-
from rich import print as rprint
1211

1312
from infrahub import config
1413
from infrahub.core.initialization import (
@@ -18,6 +17,7 @@
1817
initialize_registry,
1918
)
2019
from infrahub.core.manager import NodeManager
20+
from infrahub.core.migrations.shared import get_migration_console
2121
from infrahub.core.protocols import CoreAccount, CoreObjectPermission
2222
from infrahub.dependencies.registry import build_component_registry
2323
from infrahub.lock import initialize_lock
@@ -35,16 +35,19 @@
3535
from .db import (
3636
detect_migration_to_run,
3737
initialize_internal_schema,
38+
mark_branches_needing_rebase,
3839
migrate_database,
3940
trigger_rebase_branches,
4041
update_core_schema,
4142
)
4243

4344
if TYPE_CHECKING:
4445
from infrahub.cli.context import CliContext
46+
from infrahub.core.branch.models import Branch
4547
from infrahub.database import InfrahubDatabase
4648

4749
app = AsyncTyper()
50+
console = get_migration_console()
4851

4952

5053
@app.command(name="upgrade")
@@ -53,6 +56,9 @@ async def upgrade_cmd(
5356
config_file: str = typer.Argument("infrahub.toml", envvar="INFRAHUB_CONFIG"),
5457
check: bool = typer.Option(False, help="Check the state of the system without upgrading."),
5558
rebase_branches: bool = typer.Option(False, help="Rebase and apply migrations to branches if required."),
59+
interactive: bool = typer.Option(
60+
False, help="Use interactive prompt to accept or deny rebase of individual branches."
61+
),
5662
) -> None:
5763
"""Upgrade Infrahub to the latest version."""
5864

@@ -90,7 +96,7 @@ async def upgrade_cmd(
9096

9197
if not await migrate_database(db=dbdriver, initialize=False, migrations=migrations):
9298
# A migration failed, stop the upgrade process
93-
rprint("Upgrade cancelled due to migration failure.")
99+
console.log("Upgrade cancelled due to migration failure.")
94100
await dbdriver.close()
95101
return
96102

@@ -115,8 +121,22 @@ async def upgrade_cmd(
115121
# -------------------------------------------
116122
# Perform branch rebase and apply migrations to them
117123
# -------------------------------------------
124+
branches = await mark_branches_needing_rebase(db=dbdriver)
125+
plural = len(branches) != 1
126+
get_migration_console().log(
127+
f"Found {len(branches)} {'branches' if plural else 'branch'} that {'need' if plural else 'needs'} to be rebased"
128+
)
129+
118130
if rebase_branches:
119-
await trigger_rebase_branches(db=dbdriver)
131+
branches_to_rebase: list[Branch] = []
132+
if not interactive:
133+
branches_to_rebase = branches
134+
else:
135+
for branch in branches:
136+
if typer.confirm(f"Rebase branch {branch.name}?"):
137+
branches_to_rebase.append(branch)
138+
139+
await trigger_rebase_branches(db=dbdriver, branches=branches_to_rebase)
120140

121141
await dbdriver.close()
122142

@@ -134,21 +154,21 @@ async def upgrade_menu(db: InfrahubDatabase) -> None:
134154
diff_menu = DeepDiff(menu_items.to_rest(), default_menu_dict.to_rest(), ignore_order=True)
135155

136156
if not diff_menu:
137-
rprint("Menu Up to date, nothing to update")
157+
console.log("Menu Up to date, nothing to update")
138158
return
139159

140160
await menu_repository.update_menu(existing_menu=menu_items, new_menu=default_menu_dict, menu_nodes=menu_nodes)
141-
rprint("Menu has been updated")
161+
console.log("Menu has been updated")
142162

143163

144164
async def upgrade_permissions(db: InfrahubDatabase) -> None:
145165
existing_permissions = await NodeManager.query(schema=CoreObjectPermission, db=db, limit=1)
146166
if existing_permissions:
147-
rprint("Permissions Up to date, nothing to update")
167+
console.log("Permissions Up to date, nothing to update")
148168
return
149169

150170
await setup_permissions(db=db)
151-
rprint("Permissions have been updated")
171+
console.log("Permissions have been updated")
152172

153173

154174
async def setup_permissions(db: InfrahubDatabase) -> None:

backend/infrahub/core/migrations/graph/m037_index_attr_vals.py

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33
from dataclasses import dataclass
44
from typing import TYPE_CHECKING, Any
55

6-
from rich.console import Console
7-
86
from infrahub.constants.database import IndexType
97
from infrahub.core.attribute import MAX_STRING_LENGTH
10-
from infrahub.core.migrations.shared import MigrationResult
8+
from infrahub.core.migrations.shared import MigrationResult, get_migration_console
119
from infrahub.core.query import Query, QueryType
12-
from infrahub.core.timestamp import Timestamp
1310
from infrahub.database.index import IndexItem
1411
from infrahub.database.neo4j import IndexManagerNeo4j
1512
from infrahub.log import get_logger
@@ -467,24 +464,19 @@ async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: #
467464
return result
468465

469466
async def execute(self, db: InfrahubDatabase) -> MigrationResult: # noqa: PLR0915
470-
console = Console()
467+
console = get_migration_console()
471468
result = MigrationResult()
472469

473470
# find the active schema attributes that have a LARGE_ATTRIBUTE_TYPE kind on all branches
474-
console.print(
475-
f"{Timestamp().to_string()} Determining schema attribute types and timestamps on all branches...", end=""
476-
)
471+
console.print("Determining schema attribute types and timestamps on all branches...", end="")
477472
get_large_attribute_types_query = await GetLargeAttributeTypesQuery.init(db=db)
478473
await get_large_attribute_types_query.execute(db=db)
479474
schema_attribute_timeframes = get_large_attribute_types_query.get_large_attribute_type_timeframes()
480475
console.print("done")
481476

482477
# find which schema attributes are large_types in the default branch, but updated to non-large_type on other branches
483478
# {(kind, attr_name): SchemaAttributeTimeframe}
484-
console.print(
485-
f"{Timestamp().to_string()} Determining which schema attributes have been updated to non-large_type on non-default branches...",
486-
end="",
487-
)
479+
console.print("Determining schema attribute updates on non-default branches...", end="")
488480
main_schema_attribute_timeframes_map: dict[tuple[str, str], SchemaAttributeTimeframe] = {}
489481
for schema_attr_time in schema_attribute_timeframes:
490482
if schema_attr_time.is_default_branch:
@@ -508,15 +500,15 @@ async def execute(self, db: InfrahubDatabase) -> MigrationResult: # noqa: PLR09
508500
console.print("done")
509501

510502
# drop the index on the AttributeValueNonIndexed vertex, there won't be any at this point anyway
511-
console.print(f"{Timestamp().to_string()} Dropping index on AttributeValueIndexed vertices...", end="")
503+
console.print("Dropping index on AttributeValueIndexed vertices...", end="")
512504
index_manager = IndexManagerNeo4j(db=db)
513505
index_manager.init(nodes=[AV_INDEXED_INDEX], rels=[])
514506
await index_manager.drop()
515507
console.print("done")
516508

517509
# create the temporary non-indexed attribute value vertices for LARGE_ATTRIBUTE_TYPE attributes
518510
# start with default branch
519-
console.print(f"{Timestamp().to_string()} Update non-indexed attribute values with temporary label...", end="")
511+
console.print("Creating temporary non-indexed attribute values for large attribute types...", end="")
520512
large_schema_attribute_timeframes = [
521513
schema_attr_time for schema_attr_time in schema_attribute_timeframes if schema_attr_time.is_large_type
522514
]
@@ -528,10 +520,7 @@ async def execute(self, db: InfrahubDatabase) -> MigrationResult: # noqa: PLR09
528520
console.print("done")
529521

530522
# re-index attribute values on branches where the type was updated to non-large_type
531-
console.print(
532-
f"{Timestamp().to_string()} Indexing attribute values on branches where the attribute schema was updated to a non-large_type...",
533-
end="",
534-
)
523+
console.print("Re-indexing attribute values on branches updated to non-large types...", end="")
535524
for schema_attr_time in large_type_reverts:
536525
revert_non_index_on_branch_query = await RevertNonIndexOnBranchQuery.init(
537526
db=db, schema_attribute_timeframe=schema_attr_time
@@ -540,35 +529,27 @@ async def execute(self, db: InfrahubDatabase) -> MigrationResult: # noqa: PLR09
540529
console.print("done")
541530

542531
# set the AttributeValue vertices to be AttributeValueIndexed
543-
console.print(
544-
f"{Timestamp().to_string()} Update all AttributeValue vertices to add the AttributeValueIndexed label...",
545-
end="",
546-
)
532+
console.print("Adding AttributeValueIndexed label to AttributeValue vertices...", end="")
547533
set_attribute_value_indexed_query = await SetAttributeValueIndexedQuery.init(db=db)
548534
await set_attribute_value_indexed_query.execute(db=db)
549535
console.print("done")
550536

551537
# set AttributeValueNonIndexed vertices to just AttributeValue
552-
console.print(
553-
f"{Timestamp().to_string()} Update all AttributeValueNonIndexed vertices to be AttributeValue (no index)...",
554-
end="",
555-
)
538+
console.print("Restoring AttributeValue label on AttributeValueNonIndexed vertices...", end="")
556539
finalize_attribute_value_non_indexed_query = await FinalizeAttributeValueNonIndexedQuery.init(db=db)
557540
await finalize_attribute_value_non_indexed_query.execute(db=db)
558541
console.print("done")
559542

560543
# de-index all attribute values too large to be indexed
561-
console.print(
562-
f"{Timestamp().to_string()} De-index any legacy attribute data that is too large to be indexed...", end=""
563-
)
544+
console.print("De-indexing legacy attribute data exceeding index limits...", end="")
564545
de_index_large_attribute_values_query = await DeIndexLargeAttributeValuesQuery.init(
565546
db=db, max_value_size=MAX_STRING_LENGTH
566547
)
567548
await de_index_large_attribute_values_query.execute(db=db)
568549
console.print("done")
569550

570551
# add the index back to the AttributeValueNonIndexed vertex
571-
console.print(f"{Timestamp().to_string()} Add the index back to the AttributeValueIndexed label...", end="")
552+
console.print("Adding index back to the AttributeValueIndexed label...", end="")
572553
index_manager = IndexManagerNeo4j(db=db)
573554
index_manager.init(nodes=[AV_INDEXED_INDEX], rels=[])
574555
await index_manager.add()

backend/infrahub/core/migrations/graph/m039_ipam_reconcile.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44
from dataclasses import dataclass
55
from typing import TYPE_CHECKING, Any
66

7-
from rich.console import Console
87
from rich.progress import Progress
98

109
from infrahub.core.branch.models import Branch
1110
from infrahub.core.constants import InfrahubKind
1211
from infrahub.core.initialization import initialization
1312
from infrahub.core.ipam.reconciler import IpamReconciler
14-
from infrahub.core.migrations.shared import MigrationResult
13+
from infrahub.core.migrations.shared import MigrationResult, get_migration_console
1514
from infrahub.core.query import Query, QueryType
1615
from infrahub.lock import initialize_lock
1716
from infrahub.log import get_logger
@@ -235,13 +234,13 @@ async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: #
235234
return MigrationResult()
236235

237236
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
238-
console = Console()
237+
console = get_migration_console()
239238
result = MigrationResult()
240239
# load schemas from database into registry
241240
initialize_lock()
242241
await initialization(db=db)
243242

244-
console.print("Identifying IP prefixes/addresses to reconcile...", end="")
243+
console.print("Identifying IP prefixes and addresses to reconcile...", end="")
245244
find_nodes_query = await FindNodesToReconcileQuery.init(db=db)
246245
await find_nodes_query.execute(db=db)
247246
console.print("done")
@@ -250,16 +249,17 @@ async def execute(self, db: InfrahubDatabase) -> MigrationResult:
250249
# reconciler cannot correctly handle a prefix that is its own parent
251250
ip_node_details_list = find_nodes_query.get_nodes_to_reconcile()
252251
uuids_to_check = {ip_node_details.node_uuid for ip_node_details in ip_node_details_list}
253-
console.print(f"{len(ip_node_details_list)} IP prefixes/addresses will be reconciled")
252+
console.log(f"{len(ip_node_details_list)} IP prefixes or addresses will be reconciled.")
254253

255-
console.print("Deleting any self-parent relationships...", end="")
254+
console.print("Deleting self-parent relationships prior to reconciliation...", end="")
256255
delete_self_parent_relationships_query = await DeleteSelfParentRelationshipsQuery.init(
257256
db=db, uuids_to_check=list(uuids_to_check)
258257
)
259258
await delete_self_parent_relationships_query.execute(db=db)
260259
console.print("done")
261260

262-
with Progress() as progress:
261+
console.log("Reconciling IP prefixes and addresses across branches...")
262+
with Progress(console=console) as progress:
263263
reconcile_task = progress.add_task("Reconciling IP prefixes/addresses...", total=len(ip_node_details_list))
264264

265265
for ip_node_details in ip_node_details_list:
@@ -271,4 +271,6 @@ async def execute(self, db: InfrahubDatabase) -> MigrationResult:
271271
)
272272
progress.update(reconcile_task, advance=1)
273273

274+
console.log("IP prefix and address reconciliation complete.")
275+
274276
return result

backend/infrahub/core/migrations/graph/m042_profile_attrs_in_db.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
from typing import TYPE_CHECKING, Any
44

5-
from rich.console import Console
65
from rich.progress import Progress
76

87
from infrahub.core.branch.models import Branch
98
from infrahub.core.initialization import get_root_node
109
from infrahub.core.manager import NodeManager
11-
from infrahub.core.migrations.shared import MigrationResult
10+
from infrahub.core.migrations.shared import MigrationResult, get_migration_console
1211
from infrahub.core.query import Query, QueryType
1312
from infrahub.core.timestamp import Timestamp
1413
from infrahub.log import get_logger
@@ -98,7 +97,7 @@ async def execute_against_branch(self, db: InfrahubDatabase, branch: Branch) ->
9897
return await self._do_execute_for_branch(db=db, branch=branch)
9998

10099
async def _do_execute_for_branch(self, db: InfrahubDatabase, branch: Branch) -> MigrationResult:
101-
console = Console()
100+
console = get_migration_console()
102101
result = MigrationResult()
103102
await get_or_load_schema_branch(db=db, branch=branch)
104103

@@ -111,7 +110,7 @@ async def _do_execute_for_branch(self, db: InfrahubDatabase, branch: Branch) ->
111110
console.print("done")
112111

113112
node_ids_to_update: set[str] = set()
114-
with Progress() as progress:
113+
with Progress(console=console) as progress:
115114
gather_nodes_task = progress.add_task(
116115
f"Gathering affected objects for each profile on branch {branch.name}...", total=len(profiles_map)
117116
)
@@ -121,6 +120,7 @@ async def _do_execute_for_branch(self, db: InfrahubDatabase, branch: Branch) ->
121120
node_peers = await node_relationship_manager.get_db_peers(db=db)
122121
node_ids_to_update.update(str(peer.peer_id) for peer in node_peers)
123122
progress.update(gather_nodes_task, advance=1)
123+
console.log(f"Collected nodes impacted by profiles on branch {branch.name}.")
124124

125125
console.print("Identifying nodes with profile updates by branch...", end="")
126126
get_nodes_with_profile_updates_by_branch_query = await GetNodesWithProfileUpdatesForBranchQuery.init(
@@ -131,7 +131,8 @@ async def _do_execute_for_branch(self, db: InfrahubDatabase, branch: Branch) ->
131131
console.print("done")
132132

133133
right_now = Timestamp()
134-
with Progress() as progress:
134+
console.log("Applying profiles to nodes...")
135+
with Progress(console=console) as progress:
135136
apply_task = progress.add_task("Applying profiles to nodes...", total=len(node_ids_to_update))
136137
applier = self._get_profile_applier(db=db, branch=branch)
137138
for node_id in node_ids_to_update:
@@ -141,5 +142,6 @@ async def _do_execute_for_branch(self, db: InfrahubDatabase, branch: Branch) ->
141142
if updated_field_names:
142143
await node.save(db=db, fields=updated_field_names, at=right_now)
143144
progress.update(apply_task, advance=1)
145+
console.log("Completed applying profiles to nodes.")
144146

145147
return result

backend/infrahub/core/migrations/graph/m043_create_hfid_display_label_in_db.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from infrahub.core.constants import SchemaPathType
1010
from infrahub.core.initialization import get_root_node
1111
from infrahub.core.migrations.schema.node_attribute_add import NodeAttributeAddMigration
12-
from infrahub.core.migrations.shared import MigrationRequiringRebase, MigrationResult
12+
from infrahub.core.migrations.shared import MigrationRequiringRebase, MigrationResult, get_migration_console
1313
from infrahub.core.path import SchemaPath
1414
from infrahub.core.query import Query, QueryType
1515

@@ -97,7 +97,7 @@ async def execute(self, db: InfrahubDatabase) -> MigrationResult:
9797
]
9898
)
9999

100-
with Progress() as progress:
100+
with Progress(console=get_migration_console()) as progress:
101101
update_task = progress.add_task("Adding HFID and display label to nodes", total=len(migrations))
102102

103103
for migration in migrations:
@@ -144,7 +144,7 @@ async def execute_against_branch(self, db: InfrahubDatabase, branch: Branch) ->
144144
]
145145
)
146146

147-
with Progress() as progress:
147+
with Progress(console=get_migration_console()) as progress:
148148
update_task = progress.add_task(
149149
f"Adding HFID and display label to nodes on branch {branch.name}", total=len(migrations)
150150
)

0 commit comments

Comments
 (0)