2025-10-07 10:32:04 +01:00

359 lines
10 KiB
Plaintext

#!/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"
}
}