Befehle login, servers, distros, profiles, presets, vm, lxc, template list|build, batch, status, logs --follow, cancel. Renderer im Aufbau der Vorgabe (zeichengenau per Golden-File), 24-bit/256/ohne Farbe, --ascii, --quiet, --json, --dry-run; live im Terminal, zeilenweise ohne. SSE mit Wiederverbinden und Polling als Rückfall. Typen aus openapi.json per oapi-codegen; Release-Builds per cli/bauen.sh. Refs #013 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
120 lines
4.0 KiB
Go
120 lines
4.0 KiB
Go
package befehle
|
||
|
||
import (
|
||
"bufio"
|
||
"fmt"
|
||
"net/url"
|
||
"os"
|
||
"strings"
|
||
|
||
"github.com/spf13/cobra"
|
||
"golang.org/x/term"
|
||
|
||
"git.wilde-server.de/florian.wilde/proxdeploy/cli/internal/api"
|
||
"git.wilde-server.de/florian.wilde/proxdeploy/cli/internal/konfig"
|
||
)
|
||
|
||
func (u *umgebung) loginBefehl() *cobra.Command {
|
||
var token, benutzer, name, server string
|
||
var tage int
|
||
befehl := &cobra.Command{
|
||
Use: "login <url>",
|
||
Short: "An einer ProxDeploy-Instanz anmelden und das API-Token speichern",
|
||
Long: "Fragt Benutzername und Passwort ab, legt ein API-Token an und speichert es in\n" +
|
||
"~/.config/proxdeploy/config.toml (Rechte 0600). Mit --token wird ein vorhandenes\n" +
|
||
"Token (Web-GUI → Einstellungen → API-Tokens) geprüft und gespeichert.",
|
||
Example: " proxdeploy login https://proxdeploy.example\n proxdeploy login https://proxdeploy.labor --instance labor --token pd_…",
|
||
Args: func(_ *cobra.Command, argumente []string) error {
|
||
if len(argumente) != 1 {
|
||
return bedienfehler("URL fehlt: proxdeploy login <url>")
|
||
}
|
||
return nil
|
||
},
|
||
RunE: func(cmd *cobra.Command, argumente []string) error {
|
||
adresse := strings.TrimRight(strings.TrimSpace(argumente[0]), "/")
|
||
if !strings.Contains(adresse, "://") {
|
||
adresse = "https://" + adresse
|
||
}
|
||
geprueft, err := url.Parse(adresse)
|
||
if err != nil || geprueft.Host == "" || (geprueft.Scheme != "https" && geprueft.Scheme != "http") {
|
||
return bedienfehler("keine gültige URL: %s", argumente[0])
|
||
}
|
||
ctx := cmd.Context()
|
||
c := api.Neu(adresse, "", Version)
|
||
|
||
if token == "" {
|
||
if !term.IsTerminal(int(os.Stdin.Fd())) {
|
||
return bedienfehler("ohne Terminal kein Passwort-Dialog – --token angeben")
|
||
}
|
||
leser := bufio.NewReader(os.Stdin)
|
||
if benutzer == "" {
|
||
fmt.Fprint(u.fehler, "Benutzername: ")
|
||
zeile, err := leser.ReadString('\n')
|
||
if err != nil {
|
||
return bedienfehler("Eingabe abgebrochen")
|
||
}
|
||
benutzer = strings.TrimSpace(zeile)
|
||
}
|
||
fmt.Fprint(u.fehler, "Passwort: ")
|
||
passwort, err := term.ReadPassword(int(os.Stdin.Fd()))
|
||
fmt.Fprintln(u.fehler)
|
||
if err != nil {
|
||
return bedienfehler("Eingabe abgebrochen")
|
||
}
|
||
if name == "" {
|
||
rechner, _ := os.Hostname()
|
||
name = "cli@" + rechner
|
||
}
|
||
anmeldung := api.TokenAnmeldung{Benutzername: benutzer, Passwort: string(passwort), Name: name}
|
||
if tage > 0 {
|
||
anmeldung.Tage = &tage
|
||
}
|
||
neu, err := c.TokenAnmelden(ctx, anmeldung)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
token = neu.Token
|
||
}
|
||
|
||
c.Token = token
|
||
ich, err := c.Ich(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
datei, pfad, err := konfig.Lesen()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
instanz := konfig.Instanz{URL: adresse, Token: token, Server: server}
|
||
if alt, ok := datei.Instanzen[u.opt.instanz]; ok && server == "" {
|
||
instanz.Server = alt.Server
|
||
} else if u.opt.instanz == "" && server == "" {
|
||
instanz.Server = datei.Server
|
||
}
|
||
datei.Setzen(u.opt.instanz, instanz)
|
||
if err := konfig.Schreiben(pfad, datei); err != nil {
|
||
return fmt.Errorf("Konfiguration nicht geschrieben: %w", err)
|
||
}
|
||
if u.opt.json {
|
||
return u.jsonAusgeben(map[string]any{"benutzername": ich.Benutzername, "rolle": ich.Rolle, "version": ich.Version, "konfiguration": pfad})
|
||
}
|
||
s := u.stil()
|
||
symbol := "✓"
|
||
if s.ASCII {
|
||
symbol = "[OK]"
|
||
}
|
||
rolle := map[api.IchRolle]string{api.ADMIN: "Admin", api.OPERATOR: "Operator"}[ich.Rolle]
|
||
fmt.Fprintf(u.aus, "%s Angemeldet als %s %s\n", s.Teal(symbol), s.Fett(ich.Benutzername),
|
||
s.Muted(fmt.Sprintf("(%s) · ProxDeploy v%s · Token in %s", rolle, ich.Version, pfad)))
|
||
return nil
|
||
},
|
||
}
|
||
f := befehl.Flags()
|
||
f.StringVar(&token, "token", "", "vorhandenes API-Token (pd_…) statt Passwort")
|
||
f.StringVar(&benutzer, "user", "", "Benutzername (sonst Abfrage)")
|
||
f.StringVar(&name, "name", "", "Name des Tokens (Standard: cli@<rechner>)")
|
||
f.IntVar(&tage, "days", 0, "Token läuft nach so vielen Tagen ab (Standard: unbefristet)")
|
||
f.StringVar(&server, "default-server", "", "Standard für --server speichern")
|
||
return befehl
|
||
}
|