Skip to content

Commit eb6333a

Browse files
committed
fix template rendering
1 parent 33448ac commit eb6333a

File tree

7 files changed

+128
-97
lines changed

7 files changed

+128
-97
lines changed

scripts/bootstrap.py

Lines changed: 67 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from rich.console import Console
4141
from rich.panel import Panel
4242
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn
43+
from rich.rule import Rule
4344
from rich import box
4445

4546
console = Console()
@@ -49,23 +50,23 @@
4950

5051
def check_infrahub_ready(max_retries: int = 30, sleep_time: int = 2) -> bool:
5152
"""Check if Infrahub is ready to accept requests."""
52-
console.print("\n[cyan]→[/cyan] Checking if Infrahub is ready...")
53+
console.print("\n[bold cyan]→ Checking if Infrahub is ready...[/bold cyan]")
5354

5455
with Progress(
55-
SpinnerColumn(),
56+
SpinnerColumn(spinner_name="dots"),
5657
TextColumn("[progress.description]{task.description}"),
57-
BarColumn(),
58+
BarColumn(bar_width=40),
5859
TimeElapsedColumn(),
5960
console=console,
6061
) as progress:
61-
task = progress.add_task("[cyan]Waiting for Infrahub...", total=max_retries)
62+
task = progress.add_task("[bold magenta]Waiting for Infrahub...", total=max_retries)
6263

6364
for attempt in range(max_retries):
6465
try:
6566
response = requests.get(f"{INFRAHUB_ADDRESS}/api/schema", timeout=2)
6667
if response.status_code == 200:
6768
progress.update(task, completed=max_retries)
68-
console.print("[green]✓[/green] Infrahub is ready!\n")
69+
console.print("[bold green]✓ Infrahub is ready![/bold green]\n")
6970
return True
7071
except requests.exceptions.RequestException:
7172
pass
@@ -87,9 +88,9 @@ def check_infrahub_ready(max_retries: int = 30, sleep_time: int = 2) -> bool:
8788
return False
8889

8990

90-
def run_command(command: str, description: str, step: str) -> bool:
91+
def run_command(command: str, description: str, step: str, color: str = "cyan") -> bool:
9192
"""Run a shell command and display output."""
92-
console.print(f"\n[cyan]{step}[/cyan] {description}")
93+
console.print(f"\n[bold {color} on black]{step}[/bold {color} on black] [bold white]{description}[/bold white]")
9394

9495
try:
9596
subprocess.run(
@@ -99,45 +100,50 @@ def run_command(command: str, description: str, step: str) -> bool:
99100
capture_output=False,
100101
text=True
101102
)
102-
console.print(f"[green]✓[/green] {description} completed")
103+
console.print(f"[bold green]✓[/bold green] [green]{description} completed[/green]")
103104
return True
104105
except subprocess.CalledProcessError as e:
105-
console.print(f"[red]✗[/red] Failed: {description}")
106+
console.print(f"[bold red]✗[/bold red] [red]Failed: {description}[/red]")
106107
console.print(f"[dim]Error: {e}[/dim]")
107108
return False
108109

109110

110111
def wait_for_repository_sync(seconds: int = 120) -> None:
111112
"""Wait for repository synchronization with progress bar."""
112-
console.print(f"\n[cyan]→[/cyan] Waiting for repository sync ({seconds} seconds)...")
113+
console.print(f"\n[bold yellow]⏳ Waiting for repository sync ({seconds} seconds)...[/bold yellow]")
113114

114115
with Progress(
115-
SpinnerColumn(),
116+
SpinnerColumn(spinner_name="point"),
116117
TextColumn("[progress.description]{task.description}"),
117-
BarColumn(),
118+
BarColumn(bar_width=40, complete_style="yellow", finished_style="green"),
118119
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
119120
TimeElapsedColumn(),
120121
console=console,
121122
) as progress:
122-
task = progress.add_task("[cyan]Syncing repository...", total=seconds)
123+
task = progress.add_task("[bold yellow]Syncing repository...", total=seconds)
123124

124125
for _ in range(seconds):
125126
time.sleep(1)
126127
progress.update(task, advance=1)
127128

128-
console.print("[green]✓[/green] Repository sync complete\n")
129+
console.print("[bold green]✓ Repository sync complete[/bold green]\n")
129130

130131

131132
def main(branch: str = "main") -> int:
132133
"""Main bootstrap function."""
133134
console.print()
134135
console.print(Panel(
135-
f"[bold blue]Infrahub Demo Bootstrap[/bold blue]\n"
136-
f"[dim]Branch:[/dim] [bold]{branch}[/bold]\n\n"
137-
"[dim]This will load schemas, menu, bootstrap data, security, and repository[/dim]",
138-
border_style="blue",
139-
box=box.ROUNDED,
140-
title="Bootstrap Process"
136+
f"[bold bright_blue]🚀 Infrahub Demo Bootstrap[/bold bright_blue]\n"
137+
f"[bright_cyan]Branch:[/bright_cyan] [bold yellow]{branch}[/bold yellow]\n\n"
138+
"[dim]This will load:[/dim]\n"
139+
" [blue]•[/blue] Schemas\n"
140+
" [magenta]•[/magenta] Menu definitions\n"
141+
" [yellow]•[/yellow] Bootstrap data\n"
142+
" [green]•[/green] Security data\n"
143+
" [bright_magenta]•[/bright_magenta] Demo repository",
144+
border_style="bright_blue",
145+
box=box.DOUBLE,
146+
title="[bold bright_blue]Bootstrap Process[/bold bright_blue]"
141147
))
142148

143149
# Check if Infrahub is ready
@@ -148,42 +154,52 @@ def main(branch: str = "main") -> int:
148154
{
149155
"step": "[1/7]",
150156
"description": "Loading schemas",
151-
"command": f"uv run infrahubctl schema load schemas --branch {branch}"
157+
"command": f"uv run infrahubctl schema load schemas --branch {branch}",
158+
"color": "blue"
152159
},
153160
{
154161
"step": "[2/7]",
155162
"description": "Loading menu definitions",
156-
"command": f"uv run infrahubctl menu load menu --branch {branch}"
163+
"command": f"uv run infrahubctl menu load menu --branch {branch}",
164+
"color": "magenta"
157165
},
158166
{
159167
"step": "[3/7]",
160168
"description": "Loading bootstrap data (locations, platforms, roles, etc.)",
161-
"command": f"uv run infrahubctl object load objects/bootstrap/ --branch {branch}"
169+
"command": f"uv run infrahubctl object load objects/bootstrap/ --branch {branch}",
170+
"color": "yellow"
162171
},
163172
{
164173
"step": "[4/7]",
165174
"description": "Loading security data (zones, policies, rules)",
166-
"command": f"uv run infrahubctl object load objects/security/ --branch {branch}"
175+
"command": f"uv run infrahubctl object load objects/security/ --branch {branch}",
176+
"color": "green"
167177
},
168178
{
169179
"step": "[5/7]",
170180
"description": "Populating security relationships",
171-
"command": "uv run python scripts/populate_security_relationships.py"
181+
"command": "uv run python scripts/populate_security_relationships.py",
182+
"color": "cyan"
172183
},
173184
]
174185

175186
# Execute all steps
176-
for step_info in steps:
187+
for i, step_info in enumerate(steps):
177188
if not run_command(
178189
step_info["command"],
179190
step_info["description"],
180-
step_info["step"]
191+
step_info["step"],
192+
step_info["color"]
181193
):
182-
console.print("\n[red]Bootstrap failed![/red]")
194+
console.print("\n[bold red]Bootstrap failed![/bold red]")
183195
return 1
184196

197+
# Add visual separator after each step (except the last one)
198+
if i < len(steps) - 1:
199+
console.print(Rule(style=f"dim {step_info['color']}"))
200+
185201
# Add repository (may already exist)
186-
console.print("\n[cyan][6/7][/cyan] Adding demo repository")
202+
console.print("\n[bold bright_magenta on black][6/7][/bold bright_magenta on black] [bold white]Adding demo repository[/bold white]")
187203
result = subprocess.run(
188204
"uv run infrahubctl repository add DEMO https://github.com/opsmill/infrahub-demo.git --ref main --read-only --ref main",
189205
shell=True,
@@ -192,39 +208,46 @@ def main(branch: str = "main") -> int:
192208
)
193209

194210
if result.returncode == 0:
195-
console.print("[green]✓[/green] Repository added")
211+
console.print("[bold green]✓[/bold green] [green]Repository added[/green]")
196212
else:
197213
if "already exists" in result.stderr.lower() or "already exists" in result.stdout.lower():
198-
console.print("[yellow]⚠[/yellow] Repository already exists, skipping...")
214+
console.print("[bold yellow]⚠[/bold yellow] [yellow]Repository already exists, skipping...[/yellow]")
199215
else:
200-
console.print("[red]✗[/red] Failed to add repository")
216+
console.print("[bold red]✗[/bold red] [red]Failed to add repository[/red]")
201217
console.print(f"[dim]{result.stderr}[/dim]")
202218

219+
console.print(Rule(style="dim bright_magenta"))
220+
203221
# Wait for repository sync
204-
console.print("\n[cyan][7/7][/cyan] Waiting for repository sync")
222+
console.print("\n[bold bright_yellow on black][7/7][/bold bright_yellow on black] [bold white]Waiting for repository sync[/bold white]")
205223
wait_for_repository_sync(120)
206224

225+
console.print(Rule(style="dim bright_yellow"))
226+
207227
# Load event actions
208-
console.print("\n[cyan]→[/cyan] Loading event actions")
228+
console.print("\n[bold bright_cyan]→ Loading event actions[/bold bright_cyan]")
209229
if run_command(
210230
f"uv run infrahubctl object load objects/events/ --branch {branch}",
211231
"Event actions loading",
212-
""
232+
"",
233+
"bright_cyan"
213234
):
214-
console.print("[green]✓[/green] Event actions loaded successfully")
235+
console.print("[bold green]✓[/bold green] [green]Event actions loaded successfully[/green]")
236+
237+
console.print(Rule(style="dim bright_cyan"))
215238

216239
# Display completion message
217240
console.print()
218241
console.print(Panel(
219-
f"[bold green]Bootstrap Complete![/bold green]\n\n"
242+
f"[bold bright_green]🎉 Bootstrap Complete![/bold bright_green]\n\n"
220243
f"[dim]All data has been loaded into Infrahub[/dim]\n"
221-
f"[dim]Branch:[/dim] [bold]{branch}[/bold]\n\n"
222-
"[cyan]Next steps:[/cyan]\n"
223-
" Demo a DC design: [bold]uv run invoke demo-dc-arista[/bold]\n"
224-
" Create a Proposed Change",
225-
title="Success",
226-
border_style="green",
227-
box=box.ROUNDED
244+
f"[bright_cyan]Branch:[/bright_cyan] [bold yellow]{branch}[/bold yellow]\n\n"
245+
"[bold bright_magenta]Next steps:[/bold bright_magenta]\n"
246+
" [green]•[/green] Demo a DC design: [bold bright_cyan]uv run invoke demo-dc-arista[/bold bright_cyan]\n"
247+
" [green]•[/green] Create a Proposed Change",
248+
title="[bold bright_green]✓ Success[/bold bright_green]",
249+
border_style="bright_green",
250+
box=box.DOUBLE
228251
))
229252

230253
return 0

scripts/get_configs.py

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import argparse
1414
import asyncio
15+
import sys
1516
from pathlib import Path
1617

1718
from infrahub_sdk import InfrahubClient
@@ -62,7 +63,7 @@ async def get_containerlab_topologies(client: InfrahubClient) -> list[str]:
6263
return saved_topologies
6364

6465

65-
async def get_device_configs(client: InfrahubClient) -> None:
66+
async def get_device_configs(client: InfrahubClient) -> int:
6667
"""Fetch device configuration artifacts and save to files."""
6768
base_path = Path("./generated-configs/devices")
6869
base_path.mkdir(parents=True, exist_ok=True)
@@ -116,8 +117,10 @@ async def get_device_configs(client: InfrahubClient) -> None:
116117
if config_count == 0:
117118
console.print(" [yellow]No device configurations found[/yellow]")
118119

120+
return config_count
119121

120-
async def get_topology_cabling(client: InfrahubClient) -> None:
122+
123+
async def get_topology_cabling(client: InfrahubClient) -> int:
121124
"""Fetch topology cabling matrix artifacts and save to files."""
122125
directory_path = Path("./generated-configs/cabling")
123126
directory_path.mkdir(parents=True, exist_ok=True)
@@ -152,8 +155,10 @@ async def get_topology_cabling(client: InfrahubClient) -> None:
152155
if cabling_count == 0:
153156
console.print(" [yellow]No cabling matrices found[/yellow]")
154157

158+
return cabling_count
159+
155160

156-
async def main(branch: str | None = None) -> None:
161+
async def main(branch: str | None = None) -> int:
157162
"""Main function to fetch all artifacts."""
158163
# Connect to Infrahub with branch configuration
159164
branch_name = branch if branch else "main"
@@ -171,14 +176,43 @@ async def main(branch: str | None = None) -> None:
171176
else:
172177
client = InfrahubClient()
173178

174-
# Fetch all artifact types
179+
# Fetch all artifact types and track results
175180
saved_topologies = await get_containerlab_topologies(client)
176-
await get_device_configs(client)
177-
await get_topology_cabling(client)
181+
config_count = await get_device_configs(client)
182+
cabling_count = await get_topology_cabling(client)
183+
184+
# Check if any artifacts were retrieved
185+
topology_count = len(saved_topologies)
186+
total_artifacts = topology_count + config_count + cabling_count
178187

179188
console.print()
189+
190+
if total_artifacts == 0:
191+
# Display error panel if no artifacts were found
192+
console.print(Panel(
193+
"[bold red]✗ Artifact Extraction Failed![/bold red]\n\n"
194+
"[yellow]No artifacts were retrieved from Infrahub.[/yellow]\n\n"
195+
"[dim]Possible causes:[/dim]\n"
196+
" • The branch may not have any generated artifacts yet\n"
197+
" • The topology generator may not have been run\n"
198+
" • Artifacts may have failed to generate\n\n"
199+
"[cyan]Next steps:[/cyan]\n"
200+
f" • Check the branch exists: [bold]uv run infrahubctl branch list[/bold]\n"
201+
f" • Run the generator: [bold]uv run infrahubctl generator create_dc --branch {branch_name} name=\"<topology-name>\"[/bold]\n"
202+
" • Check Infrahub logs for errors",
203+
title="[bold red]Error[/bold red]",
204+
border_style="red",
205+
box=box.DOUBLE
206+
))
207+
return 1
208+
209+
# Display success panel if artifacts were found
180210
console.print(Panel(
181-
"[bold green]Configuration extraction complete![/bold green]\n"
211+
"[bold green]Configuration extraction complete![/bold green]\n\n"
212+
f"[dim]Retrieved:[/dim]\n"
213+
f" • [cyan]{topology_count}[/cyan] containerlab topolog{'y' if topology_count == 1 else 'ies'}\n"
214+
f" • [cyan]{config_count}[/cyan] device configuration{'s' if config_count != 1 else ''}\n"
215+
f" • [cyan]{cabling_count}[/cyan] cabling matri{'x' if cabling_count == 1 else 'ces'}\n\n"
182216
f"[dim]Saved to:[/dim] [bold]./generated-configs/[/bold]",
183217
border_style="green",
184218
box=box.ROUNDED
@@ -214,6 +248,8 @@ async def main(branch: str | None = None) -> None:
214248
console.print(deploy_table)
215249
console.print()
216250

251+
return 0
252+
217253

218254
if __name__ == "__main__":
219255
parser = argparse.ArgumentParser(
@@ -228,4 +264,5 @@ async def main(branch: str | None = None) -> None:
228264
)
229265
args = parser.parse_args()
230266

231-
asyncio.run(main(branch=args.branch))
267+
exit_code = asyncio.run(main(branch=args.branch))
268+
sys.exit(exit_code)

0 commit comments

Comments
 (0)