#!/usr/bin/env nu # Start the provisioning orchestrator def main [ --port (-p): int = 8080 # HTTP server port --data-dir (-d): string = "./data" # Data directory for persistence --nu-path: string = "nu" # Path to Nushell executable --provisioning-path: string = "../../core/nulib/provisioning" # Path to provisioning script --background (-b) # Run in background --pid-file: string = "./data/orchestrator.pid" # PID file location --log-file: string = "./data/orchestrator.log" # Log file location --check # Check if orchestrator is running --stop # Stop the orchestrator ] { if $check { check_orchestrator_status $pid_file return } if $stop { stop_orchestrator $pid_file return } # Always stop any running orchestrator instances before starting print "๐Ÿ” Checking for existing orchestrator processes..." let existing_processes = (ps | where name =~ "provisioning-orchestrator" | length) if $existing_processes > 0 { print $"๐Ÿ›‘ Found ($existing_processes) existing orchestrator processes. Stopping them..." try { bash -c 'pkill -f "provisioning-orchestrator" && echo "โœ… Existing orchestrator stopped" || echo "โš ๏ธ No orchestrator process found"' sleep 2sec } catch { print "โš ๏ธ Could not stop existing orchestrator processes" } } else { print "โœ… No existing orchestrator processes found" } # Clean up stale PID file if it exists if ($pid_file | path exists) { print "๐Ÿงน Removing stale PID file" rm -f $pid_file } let orchestrator_bin = "../target/release/provisioning-orchestrator" if not ($orchestrator_bin | path exists) { print "๐Ÿ›‘ Orchestrator binary not found. Building..." cd ..; cargo build --release --bin provisioning-orchestrator; cd orchestrator if not ($orchestrator_bin | path exists) { print "โŒ Failed to build orchestrator" exit 1 } } if $background { start_orchestrator_background $orchestrator_bin $port $data_dir $nu_path $provisioning_path $pid_file $log_file } else { start_orchestrator_foreground $orchestrator_bin $port $data_dir $nu_path $provisioning_path } } def start_orchestrator_foreground [ bin_path: string port: int data_dir: string nu_path: string provisioning_path: string ] { print $"๐Ÿš€ Starting orchestrator on port ($port)..." print $"๐Ÿ“ Data directory: ($data_dir)" print $"๐Ÿš Nushell path: ($nu_path)" print $"๐Ÿ“œ Provisioning script: ($provisioning_path)" print "" ^$bin_path --port $port --data-dir $data_dir --nu-path $nu_path --provisioning-path $provisioning_path } def start_orchestrator_background [ bin_path: string port: int data_dir: string nu_path: string provisioning_path: string pid_file: string log_file: string ] { # PID file cleanup and process termination already handled in main function mkdir ($data_dir | path dirname) mkdir ($log_file | path dirname) print $"๐Ÿš€ Starting orchestrator in background..." print $"๐Ÿ“ Data directory: ($data_dir)" print $"๐Ÿ“„ Log file: ($log_file)" print $"๐Ÿ†” PID file: ($pid_file)" # Start in background and capture PID let cmd = $"($bin_path) --port ($port) --data-dir '($data_dir)' --nu-path '($nu_path)' --provisioning-path '($provisioning_path)' >> '($log_file)' 2>&1 & echo $!" let pid = (bash -c $cmd | str trim) $pid | save $pid_file sleep 1sec # Verify it started if (ps | where pid == ($pid | into int) | length) > 0 { print $"โœ… Orchestrator started successfully with PID ($pid)" print $"๐ŸŒ Health check: http://localhost:($port)/health" print $"๐Ÿ“Š API docs: http://localhost:($port)/tasks" print "" print $"To stop: ($env.CURRENT_FILE) --stop" print $"To check status: ($env.CURRENT_FILE) --check" print $"To view logs: tail -f ($log_file)" } else { print "โŒ Failed to start orchestrator" if ($log_file | path exists) { print "๐Ÿ“‹ Last few log lines:" tail $log_file } exit 1 } } def stop_orchestrator [pid_file: string] { if not ($pid_file | path exists) { print "โš ๏ธ No PID file found - orchestrator may not be running" return } let pid = (open $pid_file | str trim) if (ps | where pid == ($pid | into int) | length) == 0 { print $"โš ๏ธ Process with PID ($pid) not found" rm -f $pid_file return } print $"๐Ÿ›‘ Stopping orchestrator (PID: ($pid))..." try { kill $pid sleep 2sec if (ps | where pid == ($pid | into int) | length) > 0 { print "๐Ÿ”จ Force killing..." kill -9 $pid sleep 1sec } rm -f $pid_file print "โœ… Orchestrator stopped successfully" } catch { print $"โŒ Failed to stop process ($pid)" exit 1 } } def check_orchestrator_status [pid_file: string] { if not ($pid_file | path exists) { print "โŒ Orchestrator is not running (no PID file)" return } let pid = (open $pid_file | str trim) if (ps | where pid == ($pid | into int) | length) == 0 { print $"โŒ Orchestrator is not running (PID ($pid) not found)" rm -f $pid_file return } print $"โœ… Orchestrator is running with PID ($pid)" # Try health check try { let health = (http get "http://localhost:8080/health") if ($health | get success) { print "๐ŸŒ Health check: OK" print $"๐Ÿ“Š Status: (($health | get data))" } else { print "โš ๏ธ Health check failed" } } catch { print "โš ๏ธ Could not connect to orchestrator API" } }