Files
sultan/pkg/cli/cli.go
T
2026-10-01 23:52:15 +02:00

105 lines
3.2 KiB
Go
Raw 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 implementiert die Befehlszeile von sultan:
//
// sultan server Registry, Stream-Hub, Policy-Engine, Traefik-Provider
// sultan agent (noch nicht implementiert)
// sultan token (noch nicht implementiert)
// sultan version
//
// Run ist ohne Prozessgrenzen testbar; main ruft nur Run auf.
package cli
import (
"context"
"errors"
"flag"
"fmt"
"io"
"log/slog"
"time"
"sultan/pkg/server"
)
// Version wird beim Bauen gesetzt: -ldflags "-X sultan/pkg/cli.Version=1.2.3".
var Version = "dev"
const usage = `sultan – verteiltes Ingress-Routing mit ZeroTrust-Service-Discovery
Befehle:
sultan server Server starten (Registry, Agent-Port, Traefik-Provider)
sultan agent Agent starten (noch nicht implementiert)
sultan token Mandanten, Einladungen, Lizenzen verwalten (noch nicht implementiert)
sultan version Version ausgeben
sultan help diese Hilfe
Hilfe zu einem Befehl: sultan <befehl> --help
`
// Run führt die Befehlszeile aus und liefert den Exit-Code (0 ok, 1 Fehler,
// 2 Bedienfehler). ctx endet z. B. bei SIGTERM.
func Run(ctx context.Context, args []string, stdout, stderr io.Writer) int {
if len(args) == 0 {
fmt.Fprint(stderr, usage)
return 2
}
switch args[0] {
case "help", "-h", "--help":
fmt.Fprint(stdout, usage)
return 0
case "version":
fmt.Fprintf(stdout, "sultan %s\n", Version)
return 0
case "server":
return runServer(ctx, args[1:], stdout, stderr)
case "agent", "token":
fmt.Fprintf(stderr, "sultan %s: noch nicht implementiert (siehe Roadmap)\n", args[0])
return 1
default:
fmt.Fprintf(stderr, "unbekannter Befehl %q\n\n%s", args[0], usage)
return 2
}
}
func runServer(ctx context.Context, args []string, stdout, stderr io.Writer) int {
cfg, err := parseServerFlags(args, stderr)
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))
s, err := server.New(ctx, cfg)
if err != nil {
fmt.Fprintln(stderr, "Start fehlgeschlagen:", err)
return 1
}
if err := s.Run(ctx); err != nil {
fmt.Fprintln(stderr, "Server beendet mit Fehler:", err)
return 1
}
return 0
}
// parseServerFlags liest die Flags von `sultan server`; Defaults wie in
// server.Config.
func parseServerFlags(args []string, output io.Writer) (server.Config, error) {
fs := flag.NewFlagSet("sultan server", flag.ContinueOnError)
fs.SetOutput(output)
var cfg server.Config
fs.StringVar(&cfg.DataDir, "data-dir", "./suldata", "Datenverzeichnis (sultan.db, server.key/.crt, master.key)")
fs.StringVar(&cfg.AgentAddr, "agent-addr", ":8443", "Adresse des Agent-Ports (nur TLS)")
fs.StringVar(&cfg.ProviderAddr, "provider-addr", "127.0.0.1:8080",
"Adresse für Traefik (/v1/traefik-config, Klartext – im Container :8080 und nur auf 127.0.0.1 veröffentlichen)")
fs.StringVar(&cfg.InterceptorURL, "interceptor-url", "http://127.0.0.1:8081", "Adresse des Sultan-Interceptors/Landers")
fs.DurationVar(&cfg.RefreshInterval, "refresh", time.Minute, "Intervall der Neubewertung aller Knoten")
if err := fs.Parse(args); err != nil {
return server.Config{}, err
}
if fs.NArg() > 0 {
return server.Config{}, fmt.Errorf("unerwartetes Argument %q", fs.Arg(0))
}
return cfg, nil
}