309 lines
9.6 KiB
Text
309 lines
9.6 KiB
Text
|
|
# System Status Module
|
||
|
|
# Provides comprehensive system status checks for provisioning platform
|
||
|
|
|
||
|
|
use std log
|
||
|
|
# Selective imports (ADR-025 Phase 3 Layer 2).
|
||
|
|
# plugins/mod.nu star-import was dead — dropped.
|
||
|
|
use platform/config/accessor/core.nu [config-get]
|
||
|
|
use platform/user/config.nu [load-user-config]
|
||
|
|
|
||
|
|
# Check Nushell version meets requirements
|
||
|
|
def check-nushell-version [] {
|
||
|
|
let current = (version).version
|
||
|
|
let required = "0.107.1"
|
||
|
|
|
||
|
|
let meets_requirement = (($current | str contains $required) or ($current >= $required))
|
||
|
|
|
||
|
|
{
|
||
|
|
component: "Nushell"
|
||
|
|
status: (if $meets_requirement { "✅" } else { "❌" })
|
||
|
|
version: $current
|
||
|
|
required: $required
|
||
|
|
message: (if $meets_requirement {
|
||
|
|
"Version OK"
|
||
|
|
} else {
|
||
|
|
$"Update required: ($required)+"
|
||
|
|
})
|
||
|
|
docs: "https://nushell.sh"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check if Nickel is installed
|
||
|
|
def check-nickel-installed [] {
|
||
|
|
let nickel_bin = (which nickel | get path.0? | default "")
|
||
|
|
let installed = ($nickel_bin | is-not-empty)
|
||
|
|
|
||
|
|
let version_info = if $installed {
|
||
|
|
let result = (do { ^nickel --version } | complete)
|
||
|
|
if $result.exit_code == 0 {
|
||
|
|
let version_full = ($result.stdout | str trim)
|
||
|
|
# Extract version number and revision: "X.Y.Z (rev ...)"
|
||
|
|
let version_short = ($version_full | str replace 'nickel-lang-cli nickel ' '')
|
||
|
|
$version_short
|
||
|
|
} else {
|
||
|
|
"unknown"
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
"not installed"
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
component: "Nickel CLI"
|
||
|
|
status: (if $installed { "✅" } else { "❌" })
|
||
|
|
version: $version_info
|
||
|
|
required: "0.11.2+"
|
||
|
|
message: (if $installed {
|
||
|
|
"Installed and available"
|
||
|
|
} else {
|
||
|
|
"Not found in PATH"
|
||
|
|
})
|
||
|
|
docs: "https://nickel-lang.io/docs/user_docs/getting-started/install"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check required Nushell plugins
|
||
|
|
def check-plugins [] {
|
||
|
|
let required_plugins = [
|
||
|
|
{
|
||
|
|
name: "nickel"
|
||
|
|
description: "Nickel integration"
|
||
|
|
optional: true
|
||
|
|
docs: "docs/user/PLUGIN_INTEGRATION_GUIDE.md"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
name: "tera"
|
||
|
|
description: "Template rendering"
|
||
|
|
optional: false
|
||
|
|
docs: "docs/user/PLUGIN_INTEGRATION_GUIDE.md"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
name: "auth"
|
||
|
|
description: "Authentication"
|
||
|
|
optional: true
|
||
|
|
docs: "docs/user/AUTHENTICATION_LAYER_GUIDE.md"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
name: "kms"
|
||
|
|
description: "Key management"
|
||
|
|
optional: true
|
||
|
|
docs: "docs/user/RUSTYVAULT_KMS_GUIDE.md"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
name: "orchestrator"
|
||
|
|
description: "Orchestrator integration"
|
||
|
|
optional: true
|
||
|
|
docs: ".claude/features/orchestrator-architecture.md"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
|
||
|
|
# Get list of registered plugins - use plugin list which returns structured data
|
||
|
|
let installed = (plugin list)
|
||
|
|
|
||
|
|
$required_plugins | each {|plugin|
|
||
|
|
let is_installed = ($installed | any {|p| $p.name == $plugin.name})
|
||
|
|
|
||
|
|
{
|
||
|
|
component: $plugin.name
|
||
|
|
status: (if $is_installed {
|
||
|
|
"✅"
|
||
|
|
} else if $plugin.optional {
|
||
|
|
"⚠️"
|
||
|
|
} else {
|
||
|
|
"❌"
|
||
|
|
})
|
||
|
|
version: (if $is_installed { "registered" } else { "not registered" })
|
||
|
|
required: (if $plugin.optional { "optional" } else { "required" })
|
||
|
|
message: (if $is_installed {
|
||
|
|
$plugin.description
|
||
|
|
} else if $plugin.optional {
|
||
|
|
$"($plugin.description) - optional, HTTP fallback available"
|
||
|
|
} else {
|
||
|
|
$"($plugin.description) - required for functionality"
|
||
|
|
})
|
||
|
|
docs: $plugin.docs
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check active workspace configuration
|
||
|
|
def check-workspace [] {
|
||
|
|
let user_config = (load-user-config)
|
||
|
|
let active = ($user_config.active_workspace? | default null)
|
||
|
|
|
||
|
|
if $active == null {
|
||
|
|
return {
|
||
|
|
component: "Active Workspace"
|
||
|
|
status: "❌"
|
||
|
|
version: "none"
|
||
|
|
required: "configured"
|
||
|
|
message: "No active workspace set"
|
||
|
|
docs: "docs/user/WORKSPACE_SWITCHING_GUIDE.md"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
let workspace = ($user_config.workspaces | where name == $active | first)
|
||
|
|
let ws_path = ($workspace.path? | default "")
|
||
|
|
let ws_exists = ($ws_path | path exists)
|
||
|
|
|
||
|
|
{
|
||
|
|
component: "Active Workspace"
|
||
|
|
status: (if $ws_exists { "✅" } else { "❌" })
|
||
|
|
version: $active
|
||
|
|
required: "configured"
|
||
|
|
message: (if $ws_exists {
|
||
|
|
$"Using ($active) at ($ws_path)"
|
||
|
|
} else {
|
||
|
|
$"Workspace ($active) path not found"
|
||
|
|
})
|
||
|
|
docs: "docs/user/WORKSPACE_SWITCHING_GUIDE.md"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check available providers
|
||
|
|
def check-providers [] {
|
||
|
|
let providers_path = config-get "paths.providers" "provisioning/catalog/providers"
|
||
|
|
|
||
|
|
let available_providers = if ($providers_path | path exists) {
|
||
|
|
ls $providers_path
|
||
|
|
| where type == dir
|
||
|
|
| where { |item|
|
||
|
|
let provider_name = ($item.name | path basename)
|
||
|
|
let bin_install_sh = ($providers_path | path join $provider_name | path join "bin" | path join "install.sh" | path exists)
|
||
|
|
let bin_install_nu = ($providers_path | path join $provider_name | path join "bin" | path join "install.nu" | path exists)
|
||
|
|
$bin_install_sh or $bin_install_nu
|
||
|
|
}
|
||
|
|
| get name
|
||
|
|
| path basename
|
||
|
|
| str join ", "
|
||
|
|
} else {
|
||
|
|
"none"
|
||
|
|
}
|
||
|
|
|
||
|
|
let has_providers = ($available_providers != "none")
|
||
|
|
|
||
|
|
{
|
||
|
|
component: "Cloud Providers"
|
||
|
|
status: (if $has_providers { "✅" } else { "⚠️" })
|
||
|
|
version: $available_providers
|
||
|
|
required: "at least one"
|
||
|
|
message: (if $has_providers {
|
||
|
|
$"Available: ($available_providers)"
|
||
|
|
} else {
|
||
|
|
"No providers found"
|
||
|
|
})
|
||
|
|
docs: "docs/architecture/multi-repo-strategy.md"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check orchestrator service
|
||
|
|
def check-orchestrator [] {
|
||
|
|
let orchestrator_url = (config-get "platform.orchestrator.url" "http://localhost:9011")
|
||
|
|
|
||
|
|
# Try to ping orchestrator health endpoint (handle connection errors gracefully)
|
||
|
|
let result = (do { ^curl -s -f $"($orchestrator_url)/health" --max-time 2 } | complete)
|
||
|
|
let is_running = ($result.exit_code == 0)
|
||
|
|
|
||
|
|
{
|
||
|
|
component: "Orchestrator Service"
|
||
|
|
status: (if $is_running { "✅" } else { "⚠️" })
|
||
|
|
version: (if $is_running { $"running on ($orchestrator_url)" } else { "not running" })
|
||
|
|
required: "recommended"
|
||
|
|
message: (if $is_running {
|
||
|
|
"Service healthy and responding"
|
||
|
|
} else {
|
||
|
|
"Optional service not running. Review startup options"
|
||
|
|
})
|
||
|
|
docs: ".claude/features/orchestrator-architecture.md"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check platform services
|
||
|
|
def check-platform-services [] {
|
||
|
|
let services = [
|
||
|
|
{
|
||
|
|
name: "Control Center"
|
||
|
|
port: (config-get "control_center.port" 8080)
|
||
|
|
optional: true
|
||
|
|
docs: "provisioning/platform/control-center/README.md"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
name: "MCP Server"
|
||
|
|
port: (config-get "mcp_server.port" 3000)
|
||
|
|
optional: true
|
||
|
|
docs: "provisioning/platform/mcp-server/README.md"
|
||
|
|
}
|
||
|
|
{
|
||
|
|
name: "API Gateway"
|
||
|
|
port: (config-get "api_gateway.port" 8090)
|
||
|
|
optional: true
|
||
|
|
docs: "provisioning/platform/api-gateway/README.md"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
|
||
|
|
$services | each {|svc|
|
||
|
|
let result = (do { ^curl -s -f $"http://localhost:($svc.port)/health" --max-time 1 } | complete)
|
||
|
|
let is_running = ($result.exit_code == 0)
|
||
|
|
|
||
|
|
{
|
||
|
|
component: $svc.name
|
||
|
|
status: (if $is_running { "✅" } else { "⚠️" })
|
||
|
|
version: (if $is_running { $"running on :($svc.port)" } else { "not running" })
|
||
|
|
required: "optional"
|
||
|
|
message: (if $is_running {
|
||
|
|
"Service available"
|
||
|
|
} else {
|
||
|
|
"Service not running - optional"
|
||
|
|
})
|
||
|
|
docs: $svc.docs
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Collect all status checks
|
||
|
|
# Refactored to use immutable pattern per Rule 3 (Nushell 0.110.0 compatibility)
|
||
|
|
def get-all-checks [] {
|
||
|
|
# Concatenate all check results immutably
|
||
|
|
[
|
||
|
|
(check-nushell-version)
|
||
|
|
(check-nickel-installed)
|
||
|
|
(check-plugins)
|
||
|
|
(check-workspace)
|
||
|
|
(check-providers)
|
||
|
|
(check-orchestrator)
|
||
|
|
(check-platform-services)
|
||
|
|
] | flatten
|
||
|
|
}
|
||
|
|
|
||
|
|
# Main system status command
|
||
|
|
# Comprehensive system status check showing all component states
|
||
|
|
export def "provisioning status" [] {
|
||
|
|
print $"(ansi cyan_bold)Provisioning Platform Status(ansi reset)\n"
|
||
|
|
|
||
|
|
let all_checks = (get-all-checks)
|
||
|
|
let results = ($all_checks | select component status version message)
|
||
|
|
print ($results | table)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get status summary (machine-readable)
|
||
|
|
export def "provisioning status-json" [] {
|
||
|
|
let all_checks = (get-all-checks)
|
||
|
|
|
||
|
|
let total = ($all_checks | length)
|
||
|
|
let passing = ($all_checks | where status == "✅" | length)
|
||
|
|
let warnings = ($all_checks | where status == "⚠️" | length)
|
||
|
|
let failing = ($all_checks | where status == "❌" | length)
|
||
|
|
|
||
|
|
{
|
||
|
|
timestamp: (date now | format date "%Y-%m-%dT%H:%M:%SZ")
|
||
|
|
summary: {
|
||
|
|
total: $total
|
||
|
|
passing: $passing
|
||
|
|
warnings: $warnings
|
||
|
|
failing: $failing
|
||
|
|
health_percentage: (($passing / $total) * 100 | math round)
|
||
|
|
}
|
||
|
|
checks: $all_checks
|
||
|
|
ready_for_deployment: ($failing == 0)
|
||
|
|
}
|
||
|
|
}
|