software steht so weit.

jetzt build + docker build und testen
This commit is contained in:
br committed 2026-10-02 13:25:34 +02:00
1 parent 42f0c0accb
commit ca6cdcca63
90 files changed
+10298 -480

No files matched your search

+115
View File
@@ -0,0 +1,115 @@
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)`)
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
}