#!/usr/bin/env nu # Pre-flight Check System # Validates service prerequisites before operations use manager.nu [load-service-registry is-service-running get-service-definition] use dependencies.nu [resolve-dependencies get-startup-order] # Check required services for operation export def check-required-services [ operation: string ] -> record { let registry = (load-service-registry) # Find all services required for this operation let required_services = ( $registry | transpose name config | where { |row| $operation in $row.config.required_for } | get name ) if ($required_services | is-empty) { return { operation: $operation required_services: [] all_running: true missing_services: [] can_auto_start: true message: "No services required for this operation" } } # Check which services are running let mut running = [] let mut missing = [] for service in $required_services { if (is-service-running $service) { $running = ($running | append $service) } else { $missing = ($missing | append $service) } } # Check if missing services can be auto-started let can_auto_start = ( $missing | all { |service| let service_def = (get-service-definition $service) $service_def.startup.auto_start } ) { operation: $operation required_services: $required_services running_services: $running missing_services: $missing all_running: ($missing | is-empty) can_auto_start: $can_auto_start message: (if ($missing | is-empty) { "All required services are running" } else if $can_auto_start { $"Services need to be started: ($missing | str join ', ')" } else { $"Required services not running and cannot auto-start: ($missing | str join ', ')" }) } } # Validate service prerequisites export def validate-service-prerequisites [ service_name: string ] -> record { let service_def = (get-service-definition $service_name) let mut issues = [] let mut warnings = [] # Check deployment mode requirements match $service_def.deployment.mode { "docker" | "docker-compose" => { # Check if Docker is available try { docker --version | ignore } catch { $issues = ($issues | append "Docker is not installed or not running") } } "kubernetes" => { # Check if kubectl is available try { kubectl version --client | ignore } catch { $issues = ($issues | append "kubectl is not installed") } } "binary" => { # Check if binary exists let binary_path = ($service_def.deployment.binary.binary_path | str replace -a '${HOME}' $env.HOME) if not ($binary_path | path exists) { $issues = ($issues | append $"Binary not found: ($binary_path)") } } _ => {} } # Check dependencies for dep in $service_def.dependencies { if not (is-service-running $dep) { $warnings = ($warnings | append $"Dependency '($dep)' is not running") } } # Check conflicts for conflict in $service_def.conflicts { if (is-service-running $conflict) { $issues = ($issues | append $"Conflicting service '($conflict)' is running") } } { service: $service_name valid: ($issues | is-empty) issues: $issues warnings: $warnings can_start: ($issues | is-empty) message: (if ($issues | is-empty) { "All prerequisites met" } else { $"Prerequisites not met: ($issues | str join '; ')" }) } } # Auto-start required services export def auto-start-required-services [ operation: string ] -> record { let check = (check-required-services $operation) if $check.all_running { return { success: true message: "All required services already running" started_services: [] } } if not $check.can_auto_start { return { success: false message: "Some required services cannot be auto-started" failed_services: $check.missing_services } } # Get startup order for missing services let startup_order = (get-startup-order $check.missing_services) print $"Starting required services in order: ($startup_order | str join ' -> ')" let mut started = [] let mut failed = [] for service in $startup_order { print $"Starting ($service)..." use manager.nu start-service try { let result = (start-service $service) if $result { $started = ($started | append $service) print $"✅ ($service) started successfully" } else { $failed = ($failed | append $service) print $"❌ Failed to start ($service)" break } } catch { $failed = ($failed | append $service) print $"❌ Error starting ($service)" break } } { success: ($failed | is-empty) message: (if ($failed | is-empty) { $"Successfully started ($started | length) services" } else { $"Failed to start some services: ($failed | str join ', ')" }) started_services: $started failed_services: $failed } } # Check service conflicts export def check-service-conflicts [ service_name: string ] -> record { let service_def = (get-service-definition $service_name) let mut conflicts = [] for conflict in $service_def.conflicts { if (is-service-running $conflict) { $conflicts = ($conflicts | append { service: $conflict status: "running" action_required: "stop" }) } } { service: $service_name has_conflicts: (not ($conflicts | is-empty)) conflicts: $conflicts can_start: ($conflicts | is-empty) message: (if ($conflicts | is-empty) { "No conflicting services running" } else { $"Conflicting services running: (($conflicts | get service) | str join ', ')" }) } } # Validate all services export def validate-all-services [] -> record { let registry = (load-service-registry) let validation_results = ( $registry | transpose name config | each { |row| validate-service-prerequisites $row.name } ) let total = ($validation_results | length) let valid = ($validation_results | where valid | length) let invalid = ($validation_results | where { |r| not $r.valid } | length) { total_services: $total valid_services: $valid invalid_services: $invalid all_valid: ($invalid == 0) results: $validation_results message: $"($valid)/($total) services have valid configurations" } } # Pre-flight check for service start export def preflight-start-service [ service_name: string ] -> record { print $"Running pre-flight checks for ($service_name)..." # 1. Validate prerequisites let prereq_check = (validate-service-prerequisites $service_name) if not $prereq_check.valid { return { can_start: false reason: "prerequisites" details: $prereq_check } } # 2. Check conflicts let conflict_check = (check-service-conflicts $service_name) if $conflict_check.has_conflicts { return { can_start: false reason: "conflicts" details: $conflict_check } } # 3. Check dependencies let service_def = (get-service-definition $service_name) let mut missing_deps = [] for dep in $service_def.dependencies { if not (is-service-running $dep) { let dep_def = (get-service-definition $dep) $missing_deps = ($missing_deps | append { service: $dep auto_start: $dep_def.startup.auto_start }) } } if not ($missing_deps | is-empty) { let can_auto_start = ($missing_deps | all { |d| $d.auto_start }) return { can_start: $can_auto_start reason: "dependencies" details: { missing_dependencies: $missing_deps can_auto_start: $can_auto_start } } } # All checks passed { can_start: true reason: "all_checks_passed" details: { message: "Pre-flight checks passed" } } } # Get service readiness report export def get-readiness-report [] -> record { let registry = (load-service-registry) let services = ( $registry | transpose name config | each { |row| let is_running = (is-service-running $row.name) let prereq_check = (validate-service-prerequisites $row.name) { name: $row.name type: $row.config.type category: $row.config.category running: $is_running auto_start: $row.config.startup.auto_start valid_config: $prereq_check.valid can_start: $prereq_check.can_start issues: ($prereq_check.issues | length) } } ) let total = ($services | length) let running = ($services | where running | length) let ready = ($services | where can_start | length) { total_services: $total running_services: $running ready_to_start: $ready services: $services summary: $"($running) running, ($ready) ready to start out of ($total) total" } }