prvng_core/nulib/main_provisioning/commands/state.nu

128 lines
5.5 KiB
Text
Raw Normal View History

use ../../lib_provisioning/config/accessor.nu *
use ../../lib_provisioning/utils/interface.nu [_print]
use ../../workspace/state.nu *
use ../../workspace/sync.nu *
export def handle_state_command [cmd: string, ops: string, flags: record] {
let workspace_path = if ($env.PROVISIONING_WORKSPACE_PATH? | is-not-empty) {
$env.PROVISIONING_WORKSPACE_PATH
} else {
$env.PWD
}
let infra = ($flags | get -o infra | default "")
let server = ($flags | get -o server | default "")
let taskserv = ($flags | get -o taskserv | default "")
let kubeconfig = ($flags | get -o kubeconfig | default "")
# When help_category == command name ("state"), the subcommand lands in $ops, not $cmd.
let subcmd = if ($ops | is-not-empty) { ($ops | split row " " | first) } else { $cmd }
match $subcmd {
"show" | "s" => {
state-show $workspace_path --server $server
},
"init" | "i" => {
let curr_settings = (find_get_settings --infra $infra)
state-init $workspace_path $curr_settings
_print $"State initialized at (state-path $workspace_path)"
},
"reset" | "r" => {
if ($server | is-empty) or ($taskserv | is-empty) {
error make { msg: "state reset requires --server <hostname> --taskserv <name>" }
}
state-node-reset $workspace_path $server $taskserv
_print $"($server)/($taskserv) reset to pending"
},
"migrate" | "m" => {
state-migrate-from-json $workspace_path
},
"sync" => {
let curr_settings = (find_get_settings --infra $infra)
# 1. Drift detection + reconcile against servers.ncl
let drift_rows = (state-drift $workspace_path $curr_settings --server $server)
let has_drift = ($drift_rows | where drift != "ok" | is-not-empty)
if $has_drift {
_print "── drift ──"
print ($drift_rows | where drift != "ok" | table)
let result = (state-reconcile $workspace_path $curr_settings --server $server)
if ($result.removed | is-not-empty) {
_print $"🗑 Removed ($result.removed | length) orphaned"
}
if ($result.added | is-not-empty) {
_print $" Added ($result.added | length) pending"
}
} else {
_print "✅ No drift against servers.ncl"
}
# 2. External API sync (Hetzner, K8s, SSH)
let skip_ssh = ($flags | get -o skip_ssh | default false)
state-sync $workspace_path $curr_settings --kubeconfig $kubeconfig --skip-ssh=$skip_ssh
},
"drift" | "d" => {
let curr_settings = (find_get_settings --infra $infra)
let rows = (state-drift $workspace_path $curr_settings --server $server)
let has_drift = ($rows | where drift != "ok" | is-not-empty)
if ($rows | is-empty) {
_print "(no state entries to compare)"
} else {
print ($rows | table)
if $has_drift {
_print $"\n⚠ Drift detected. Run (_ansi yellow_bold)provisioning state reconcile(_ansi reset) to fix."
} else {
_print "\n✅ No drift — state matches servers.ncl"
}
}
},
"reconcile" | "rec" => {
let curr_settings = (find_get_settings --infra $infra)
let dry_run = ($flags | get -o dry_run | default false)
# Always show drift first
let drift_rows = (state-drift $workspace_path $curr_settings --server $server)
let has_drift = ($drift_rows | where drift != "ok" | is-not-empty)
if not $has_drift {
_print "✅ No drift — nothing to reconcile"
return
}
print ($drift_rows | where drift != "ok" | table)
if $dry_run {
_print "\n(dry-run: no changes applied)"
return
}
let result = (state-reconcile $workspace_path $curr_settings --server $server)
if ($result.removed | is-not-empty) {
_print $"\n🗑 Removed ($result.removed | length) orphaned entries:"
for r in $result.removed { _print $" ($r.server)/($r.taskserv)" }
}
if ($result.added | is-not-empty) {
_print $"\n Added ($result.added | length) pending entries:"
for a in $result.added { _print $" ($a.server)/($a.taskserv)" }
}
_print "\n✅ State reconciled with servers.ncl"
},
_ => {
_print "Usage: provisioning state <subcommand> [--infra <path>]"
_print ""
_print " show [--server <hostname>] — display state table"
_print " init [--infra <path>] — bootstrap state from settings"
_print " reset --server <hostname> --taskserv <name> — reset node to pending"
_print " migrate — migrate .json → .ncl"
_print " sync [--infra <path>] [--kubeconfig <path>] — reconcile from APIs"
_print " drift [--infra <path>] [--server <hostname>] — detect state vs servers.ncl divergence"
_print " reconcile [--infra <path>] [--server <hostname>] — fix drift (remove orphaned, add missing)"
},
}
}