Files

117 lines
4.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cli
import (
"context"
"errors"
"flag"
"fmt"
"io"
"log/slog"
"os"
"sultan/pkg/agent"
)
func runAgent(ctx context.Context, args []string, stderr io.Writer) int {
if len(args) > 0 && args[0] == "maintenance" {
return runAgentMaintenance(ctx, args[1:], stderr)
}
cfg, err := parseAgentFlags(args, stderr, os.Getenv)
if errors.Is(err, flag.ErrHelp) {
return 0
}
if err != nil {
fmt.Fprintln(stderr, err)
return 2
}
cfg.Logger = slog.New(slog.NewTextHandler(stderr, nil))
a, err := agent.New(cfg)
if err != nil {
fmt.Fprintln(stderr, err)
return 2
}
if err := a.Run(ctx); err != nil {
fmt.Fprintln(stderr, "Agent beendet mit Fehler:", err)
return 1
}
return 0
}
// parseAgentFlags liest die Flags von `sultan agent`. SULTAN_TOKEN und
// SULTAN_SERVER dienen als Defaults (curl | sh, Compose; Argumente wären über
// ps für andere Benutzer sichtbar) – Flags gewinnen.
func parseAgentFlags(args []string, output io.Writer, getenv func(string) string) (agent.Config, error) {
fs := flag.NewFlagSet("sultan agent", flag.ContinueOnError)
fs.SetOutput(output)
var cfg agent.Config
fs.StringVar(&cfg.ServerURL, "server", "", "Server-Adresse, z. B. https://ingress.example.com:8443 (Override; sonst aus der Einladung)")
fs.StringVar(&cfg.Token, "token", "", "Einladung von `sultan token invite` (nur beim ersten Start)")
fs.StringVar(&cfg.DataDir, "data-dir", "./suldata", "Datenverzeichnis (node.key, node.json)")
fs.StringVar(&cfg.NodeID, "node-id", "", "Knoten-ID (Default: aus dem Hostnamen)")
fs.StringVar(&cfg.DockerSocket, "docker-socket", "/var/run/docker.sock", `Docker-Socket ("none" = ohne Docker)`)
fs.StringVar(&cfg.BackendHost, "backend-host", "", "Adresse, unter der der Ingress die Dienste erreicht (Default: automatisch)")
fs.StringVar(&cfg.BackendInterface, "backend-interface", "", "alternativ: IP dieses Interfaces verwenden (z. B. wt0 für NetBird)")
fs.StringVar(&cfg.ConfigDir, "config-dir", "/etc/sultan.d", `Dienste als YAML (*.yaml) für Hosts ohne Docker-Labels ("none" = aus)`)
fs.StringVar(&cfg.FQDN, "fqdn", "", "vollständiger Name dieses Hosts fürs Inventar (Default: automatisch über DNS)")
annotateEnv(fs)
if err := fs.Parse(args); err != nil {
return agent.Config{}, err
}
if err := applyEnv(fs, getenv); err != nil {
return agent.Config{}, err
}
if fs.NArg() > 0 {
return agent.Config{}, fmt.Errorf("unerwartetes Argument %q", fs.Arg(0))
}
return cfg, nil
}
// runAgentMaintenance: `sultan agent maintenance on|off [--for] [--reason]
// [--public-reason]` – meldet Wartung dieses Knotens beim Server an oder ab,
// z. B. aus einem Patch- oder Reboot-Skript.
func runAgentMaintenance(ctx context.Context, args []string, stderr io.Writer) int {
if len(args) == 0 || (args[0] != "on" && args[0] != "off") {
fmt.Fprintln(stderr, "Aufruf: sultan agent maintenance on|off [--for 4h|0] [--reason TEXT] [--public-reason TEXT] [--data-dir DIR]")
return 2
}
on := args[0] == "on"
fs := flag.NewFlagSet("sultan agent maintenance", flag.ContinueOnError)
fs.SetOutput(stderr)
dataDir := fs.String("data-dir", "./suldata", "Datenverzeichnis des Agenten")
server := fs.String("server", "", "Server-Adresse (Override)")
forRaw := fs.String("for", "4h", "Dauer (z. B. 30m, 4h, 2d; 0 = unbefristet)")
reason := fs.String("reason", "", "interner Grund (Log, Monitoring)")
publicReason := fs.String("public-reason", "", "öffentlicher Grund – ersetzt den Standardtext der Wartungsseite")
annotateEnv(fs)
if err := fs.Parse(args[1:]); err != nil {
if errors.Is(err, flag.ErrHelp) {
return 0
}
return 2
}
if err := applyEnv(fs, os.Getenv); err != nil {
fmt.Fprintln(stderr, err)
return 2
}
d, err := parseMaintenanceFor(*forRaw)
if err != nil {
fmt.Fprintln(stderr, "--for:", err)
return 2
}
a, err := agent.New(agent.Config{DataDir: *dataDir, ServerURL: *server, Logger: slog.New(slog.NewTextHandler(stderr, nil))})
if err != nil {
fmt.Fprintln(stderr, err)
return 2
}
if err := a.SetMaintenance(ctx, on, d, *reason, *publicReason); err != nil {
fmt.Fprintln(stderr, "Fehler:", err)
return 1
}
if on {
fmt.Fprintln(stderr, "Wartung angemeldet – Besucher sehen jetzt die Wartungsseite.")
} else {
fmt.Fprintln(stderr, "Wartung beendet.")
}
return 0
}