Add kctl-tui doctor command for health checks

This commit is contained in:
2026-08-09 20:26:55 +02:00
parent 36a7cc5e3a
commit 697017e496
2 changed files with 116 additions and 0 deletions
+1
View File
@@ -205,6 +205,7 @@ ln -s /mnt/c/Users/<your-windows-username>/.kube/config ~/.kube/config
kctl-tui # start the TUI (full navigation mode)
kctl-tui --version # print version
kctl-tui --verbose # enable debug logging to stderr
kctl-tui doctor # check if all tools, config and connections are OK
kctl-tui config check # validate ~/.kctl-tui/config.yaml
kctl-tui panel --context=... --ns=... --team=... # internal (called by tmux)
```
+115
View File
@@ -48,6 +48,12 @@ func main() {
os.Exit(1)
}
return
case "doctor":
if err := runDoctor(); err != nil {
fmt.Fprintln(os.Stderr, "kctl-tui doctor error:", err)
os.Exit(1)
}
return
}
}
@@ -110,3 +116,112 @@ func runConfig(args []string) error {
}
return nil
}
func runDoctor() error {
pass := "ok"
fail := "FAIL"
warn := "WARN"
status := pass
errs := 0
check := func(label string, err error) {
if err != nil {
fmt.Printf(" [%s] %s: %v\n", fail, label, err)
status = fail
errs++
} else {
fmt.Printf(" [%s] %s\n", pass, label)
}
}
warnCheck := func(label string, err error) {
if err != nil {
fmt.Printf(" [%s] %s: %v\n", warn, label, err)
} else {
fmt.Printf(" [%s] %s\n", pass, label)
}
}
// --- Tools ---
fmt.Println("\nTools:")
check("kubectl", kubeexec.CheckTool("kubectl"))
check("tmux/psmux", kubeexec.CheckTool("tmux"))
check("k9s", kubeexec.CheckTool("k9s"))
warnCheck("aws CLI (optional)", kubeexec.CheckTool("aws"))
// --- Config ---
fmt.Println("\nConfig:")
cfgPath, err := config.DefaultPath()
if err != nil {
fmt.Printf(" [%s] config path: %v\n", fail, err)
errs++
status = fail
} else {
cfg, err := config.Load(cfgPath)
if err != nil {
fmt.Printf(" [%s] load config: %v\n", fail, err)
errs++
status = fail
} else {
check("config file exists", nil)
if len(cfg.Contexts) == 0 {
fmt.Printf(" [%s] contexts configured\n", fail)
errs++
status = fail
} else {
fmt.Printf(" [%s] contexts configured (%d)\n", pass, len(cfg.Contexts))
}
if len(cfg.Envs) == 0 {
fmt.Printf(" [%s] envs configured\n", fail)
errs++
status = fail
} else {
fmt.Printf(" [%s] envs configured (%d)\n", pass, len(cfg.Envs))
}
if cfg.ContextTemplate != "" {
ctx := cfg.ResolveContext(cfg.Envs[0], cfg.Contexts[0])
fmt.Printf(" [%s] context_template resolves to: %s\n", pass, ctx)
} else {
fmt.Printf(" [%s] context_template is empty\n", fail)
errs++
status = fail
}
if cfg.SecretNameTemplate != "" && len(cfg.Envs) > 0 {
secret := cfg.ResolveSecretName("example-ns", cfg.Envs[0])
fmt.Printf(" [%s] secret_name_template resolves to: %s\n", pass, secret)
}
}
}
// --- Connections ---
fmt.Println("\nConnections:")
if kubeexec.CheckTool("kubectl") == nil {
err := kubeexec.CheckAWSAuth()
if err == nil {
fmt.Printf(" [%s] kubectl cluster reachable\n", pass)
} else {
// Not fatal — cluster might be unreachable from this machine
fmt.Printf(" [%s] kubectl cluster: %v\n", warn, err)
}
}
if kubeexec.CheckTool("aws") == nil {
err := kubeexec.CheckAWSAuth()
if err == nil {
fmt.Printf(" [%s] AWS credentials valid\n", pass)
} else {
fmt.Printf(" [%s] AWS credentials: %v\n", warn, err)
}
} else {
fmt.Printf(" [%s] AWS credentials (aws CLI not installed)\n", warn)
}
// --- Summary ---
fmt.Println()
if status == pass {
fmt.Println("All checks passed. kctl-tui is ready to use.")
} else {
fmt.Printf("%d error(s) found. Fix the issues above and re-run: kctl-tui doctor\n", errs)
os.Exit(1)
}
return nil
}