mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-09-10 19:07:30 +08:00
165 lines
5.3 KiB
Go
165 lines
5.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/0xJacky/Nginx-UI/internal/host/setup"
|
|
appsettings "github.com/0xJacky/Nginx-UI/settings"
|
|
"github.com/urfave/cli/v3"
|
|
)
|
|
|
|
var HostSetupCommand = &cli.Command{
|
|
Name: "host-setup",
|
|
Usage: "Generate or verify configuration for host_via_ssh nginx control mode",
|
|
Commands: []*cli.Command{
|
|
hostSetupPrintCommand(),
|
|
hostSetupKeygenCommand(),
|
|
hostSetupTestCommand(),
|
|
},
|
|
}
|
|
|
|
func hostSetupPrintCommand() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "print",
|
|
Usage: "Print setup snippets (compose / override / docker-run / authorized_keys / sudoers / acl)",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{Name: "host-address", Usage: "remote address host:port"},
|
|
&cli.StringFlag{Name: "host-user", Usage: "remote user"},
|
|
&cli.StringFlag{Name: "access-mode", Required: true, Usage: "file access mode: sftp or mounted"},
|
|
&cli.StringFlag{Name: "service-manager", Usage: "host service manager: systemd or launchd", Value: "systemd"},
|
|
&cli.StringFlag{Name: "systemd-unit", Usage: "systemd unit name", Value: "nginx.service"},
|
|
&cli.StringFlag{Name: "systemctl-path", Usage: "absolute path to systemctl on host", Value: "/bin/systemctl"},
|
|
&cli.StringFlag{Name: "launchd-service", Usage: "launchd service label", Value: "homebrew.mxcl.nginx"},
|
|
&cli.StringFlag{Name: "launchctl-path", Usage: "absolute path to launchctl on host", Value: "/bin/launchctl"},
|
|
&cli.StringFlag{Name: "nginx-sbin", Usage: "absolute path to nginx on host"},
|
|
&cli.StringFlag{Name: "config-dir", Usage: "host nginx config dir"},
|
|
&cli.StringFlag{Name: "log-dir", Usage: "host nginx log dir"},
|
|
&cli.StringFlag{Name: "pid-path", Usage: "host nginx PID file path"},
|
|
&cli.StringFlag{Name: "public-key", Usage: "path to public key file"},
|
|
&cli.BoolFlag{Name: "compose", Usage: "print only the compose snippet"},
|
|
&cli.BoolFlag{Name: "override", Usage: "print only the full override file"},
|
|
&cli.BoolFlag{Name: "docker-run", Usage: "print only the docker run command"},
|
|
&cli.BoolFlag{Name: "host", Usage: "print only host-side snippets (sudoers + authorized_keys + acl)"},
|
|
&cli.BoolFlag{Name: "json", Usage: "JSON output"},
|
|
},
|
|
Action: hostSetupPrint,
|
|
}
|
|
}
|
|
|
|
func hostSetupKeygenCommand() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "keygen",
|
|
Usage: "Generate an ed25519 keypair for host SSH",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{Name: "out", Required: true, Usage: "private key output path"},
|
|
},
|
|
Action: func(ctx context.Context, c *cli.Command) error {
|
|
pub, err := setup.GenerateKeypair(c.String("out"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println(pub)
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func hostSetupTestCommand() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "test",
|
|
Usage: "Run the verify pipeline against current settings; print JSON result",
|
|
Action: hostSetupTest,
|
|
}
|
|
}
|
|
|
|
func paramsFromFlags(c *cli.Command) (setup.SetupParams, error) {
|
|
p := setup.SetupParams{
|
|
HostAddress: c.String("host-address"),
|
|
HostUser: c.String("host-user"),
|
|
AccessMode: c.String("access-mode"),
|
|
ServiceManager: c.String("service-manager"),
|
|
SystemdUnit: c.String("systemd-unit"),
|
|
SystemctlPath: c.String("systemctl-path"),
|
|
LaunchdService: c.String("launchd-service"),
|
|
LaunchctlPath: c.String("launchctl-path"),
|
|
NginxSbinPath: c.String("nginx-sbin"),
|
|
HostConfigDir: c.String("config-dir"),
|
|
HostLogDir: c.String("log-dir"),
|
|
PIDPath: c.String("pid-path"),
|
|
}
|
|
if addr := c.String("host-address"); strings.HasPrefix(addr, "host.docker.internal") {
|
|
p.UseHostGateway = true
|
|
}
|
|
if pubPath := c.String("public-key"); pubPath != "" {
|
|
raw, err := os.ReadFile(pubPath)
|
|
if err != nil {
|
|
return p, err
|
|
}
|
|
p.PublicKeyOpenSSH = strings.TrimSpace(string(raw))
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
func hostSetupPrint(ctx context.Context, c *cli.Command) error {
|
|
p, err := paramsFromFlags(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, err := setup.RenderAll(p)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if c.Bool("json") {
|
|
return json.NewEncoder(os.Stdout).Encode(r)
|
|
}
|
|
if c.Bool("compose") {
|
|
fmt.Print(r.ComposeSnippet)
|
|
return nil
|
|
}
|
|
if c.Bool("override") {
|
|
fmt.Print(r.ComposeOverride)
|
|
return nil
|
|
}
|
|
if c.Bool("docker-run") {
|
|
fmt.Print(r.DockerRun)
|
|
return nil
|
|
}
|
|
if c.Bool("host") {
|
|
fmt.Print("# --- /etc/sudoers.d/nginx-ui ---\n")
|
|
fmt.Print(r.Sudoers)
|
|
fmt.Print("\n# --- authorized_keys ---\n")
|
|
fmt.Print(r.AuthorizedKeys)
|
|
fmt.Print("\n# --- ACL commands ---\n")
|
|
fmt.Print(r.ACLCommands)
|
|
return nil
|
|
}
|
|
// Default: everything, sectioned.
|
|
fmt.Print("# === docker-compose snippet ===\n", r.ComposeSnippet)
|
|
fmt.Print("\n# === docker-compose.override.yml ===\n", r.ComposeOverride)
|
|
fmt.Print("\n# === docker run equivalent ===\n", r.DockerRun)
|
|
fmt.Print("\n# === host: /etc/sudoers.d/nginx-ui ===\n", r.Sudoers)
|
|
fmt.Print("\n# === host: authorized_keys ===\n", r.AuthorizedKeys)
|
|
fmt.Print("\n# === host: ACL commands ===\n", r.ACLCommands)
|
|
return nil
|
|
}
|
|
|
|
func hostSetupTest(ctx context.Context, c *cli.Command) error {
|
|
appsettings.Init(c.String("config"))
|
|
|
|
client, err := setup.NewClientFromSettings()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer client.Close()
|
|
|
|
result := setup.Verify(ctx, setup.VerifyOptions{
|
|
Client: client,
|
|
Params: setup.ParamsFromSettings(),
|
|
})
|
|
return json.NewEncoder(os.Stdout).Encode(result)
|
|
}
|