ananke/cmd/ananke/builder.go

79 lines
2.5 KiB
Go

package main
import (
"log"
"os"
"path/filepath"
"strings"
"scm.bstein.dev/bstein/ananke/internal/cluster"
"scm.bstein.dev/bstein/ananke/internal/config"
"scm.bstein.dev/bstein/ananke/internal/execx"
"scm.bstein.dev/bstein/ananke/internal/state"
)
// buildOrchestrator runs one orchestration or CLI step.
// Signature: buildOrchestrator(logger *log.Logger, cfgPath string, dryRun bool) (config.Config, *cluster.Orchestrator, error).
// Why: keeps behavior explicit so startup/shutdown workflows remain maintainable as services evolve.
func buildOrchestrator(logger *log.Logger, cfgPath string, dryRun bool) (config.Config, *cluster.Orchestrator, error) {
cfg, err := config.LoadWithFragments(cfgPath, configFragmentPaths(cfgPath)...)
if err != nil {
return config.Config{}, nil, err
}
if err := state.EnsureDir(cfg.State.Dir); err != nil {
return config.Config{}, nil, err
}
if err := state.EnsureDir(cfg.State.ReportsDir); err != nil {
return config.Config{}, nil, err
}
runner := &execx.Runner{
DryRun: dryRun,
Kubeconfig: cfg.Kubeconfig,
Logger: logger,
}
store := state.New(cfg.State.RunHistoryPath)
orch := cluster.New(cfg, runner, store, logger)
return cfg, orch, nil
}
// configFragmentPaths runs one orchestration or CLI step.
// Signature: configFragmentPaths(cfgPath string) []string.
// Why: keeps generated inventory overlays discoverable without changing every
// systemd command line or recovery script invocation.
func configFragmentPaths(cfgPath string) []string {
paths := []string{}
if env := strings.TrimSpace(os.Getenv("ANANKE_CONFIG_FRAGMENTS")); env != "" {
for _, path := range filepath.SplitList(env) {
path = strings.TrimSpace(path)
if path != "" {
paths = append(paths, path)
}
}
}
defaultPath := defaultInventoryFragmentPath(cfgPath)
if defaultPath != "" {
if _, err := os.Stat(defaultPath); err == nil {
paths = append(paths, defaultPath)
}
}
return paths
}
// defaultInventoryFragmentPath runs one orchestration or CLI step.
// Signature: defaultInventoryFragmentPath(cfgPath string) string.
// Why: pairs ananke.yaml with an adjacent Terraform-generated inventory
// fragment using a deterministic host-local convention.
func defaultInventoryFragmentPath(cfgPath string) string {
dir := filepath.Dir(cfgPath)
base := filepath.Base(cfgPath)
ext := filepath.Ext(base)
name := strings.TrimSuffix(base, ext)
if name == "" {
return ""
}
if ext == "" {
return filepath.Join(dir, name+".inventory.yaml")
}
return filepath.Join(dir, name+".inventory"+ext)
}