106 lines
2.9 KiB
Go
106 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
)
|
|
|
|
var (
|
|
startupCommand = runStartup
|
|
shutdownCommand = runShutdown
|
|
etcdRestoreCommand = runEtcdRestore
|
|
daemonCommand = runDaemon
|
|
statusCommand = runStatus
|
|
intentCommand = runIntent
|
|
)
|
|
|
|
// main runs one orchestration or CLI step.
|
|
// Signature: main().
|
|
// Why: keeps behavior explicit so startup/shutdown workflows remain maintainable as services evolve.
|
|
func main() {
|
|
logger := log.New(os.Stdout, "[ananke] ", log.LstdFlags)
|
|
os.Exit(runMain(logger, os.Args))
|
|
}
|
|
|
|
// runMain runs one orchestration or CLI step.
|
|
// Signature: runMain(logger *log.Logger, args []string) int.
|
|
// Why: extracting dispatch logic makes command routing testable without spawning subprocesses.
|
|
func runMain(logger *log.Logger, args []string) int {
|
|
if len(args) < 2 {
|
|
usage()
|
|
return 2
|
|
}
|
|
|
|
sub := args[1]
|
|
switch sub {
|
|
case "startup":
|
|
if err := startupCommand(logger, args[2:]); err != nil {
|
|
logger.Printf("startup failed: %v", err)
|
|
return 1
|
|
}
|
|
case "shutdown":
|
|
if err := shutdownCommand(logger, args[2:]); err != nil {
|
|
logger.Printf("shutdown failed: %v", err)
|
|
return 1
|
|
}
|
|
case "etcd-restore":
|
|
if err := etcdRestoreCommand(logger, args[2:]); err != nil {
|
|
logger.Printf("etcd-restore failed: %v", err)
|
|
return 1
|
|
}
|
|
case "daemon":
|
|
if err := daemonCommand(logger, args[2:]); err != nil {
|
|
logger.Printf("daemon failed: %v", err)
|
|
return 1
|
|
}
|
|
case "status":
|
|
if err := statusCommand(logger, args[2:]); err != nil {
|
|
logger.Printf("status failed: %v", err)
|
|
return 1
|
|
}
|
|
case "intent":
|
|
if err := intentCommand(logger, args[2:]); err != nil {
|
|
logger.Printf("intent failed: %v", err)
|
|
return 1
|
|
}
|
|
case "help", "-h", "--help":
|
|
usage()
|
|
default:
|
|
logger.Printf("unknown command: %s", sub)
|
|
usage()
|
|
return 2
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// usage runs one orchestration or CLI step.
|
|
// Signature: usage().
|
|
// Why: keeps behavior explicit so startup/shutdown workflows remain maintainable as services evolve.
|
|
func usage() {
|
|
fmt.Print(`ananke: staged startup/shutdown + UPS-triggered protection
|
|
|
|
Usage:
|
|
ananke <command> [flags]
|
|
|
|
Commands:
|
|
startup Perform staged cluster startup
|
|
shutdown Perform graceful cluster shutdown
|
|
etcd-restore Restore etcd from snapshot on a control plane
|
|
daemon Monitor UPS and auto-trigger shutdown
|
|
status Print current ananke status and estimates
|
|
intent Read or manually set intent state
|
|
|
|
Examples:
|
|
ananke startup --config /etc/ananke/ananke.yaml --execute --force-flux-branch main
|
|
ananke shutdown --config /etc/ananke/ananke.yaml --execute --mode cluster-only --reason "manual-maintenance"
|
|
ananke etcd-restore --config /etc/ananke/ananke.yaml --execute
|
|
ananke daemon --config /etc/ananke/ananke.yaml
|
|
ananke status --config /etc/ananke/ananke.yaml
|
|
ananke intent --config /etc/ananke/ananke.yaml --set normal --reason "manual-clear" --execute
|
|
|
|
Notes:
|
|
shutdown mode is cluster-only by design; host poweroff is intentionally not implemented.
|
|
`)
|
|
}
|