refactor(deploy)!: TUI

This commit is contained in:
Lemon-miaow committed 2026-06-29 20:17:17 +08:00
1 parent 318a724f98
commit e5f1682898
37 files changed
+3622 -1303

No files matched your search

+152
View File
@@ -0,0 +1,152 @@
package main
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"felis.lolicon.best/internal/cfsetup"
"felis.lolicon.best/internal/config"
"github.com/BurntSushi/toml"
)
const podSetupConfigPath = "/etc/felis/felis.pod.toml"
const cloudflaredFelisUnit = "/etc/systemd/system/cloudflared-felis.service"
func applyCloudflareEdge(ctx context.Context, result *cfsetup.Result, panelHost, adminHost, cloudflaredBin string) error {
if result == nil || result.AccessAud == "" {
return fmt.Errorf("edge result did not include an Access audience")
}
if adminHost == "" {
return fmt.Errorf("admin hostname is required")
}
for _, path := range []string{hostSetupConfigPath, podSetupConfigPath} {
if err := updateAuthConfig(path, panelHost, adminHost, result.AccessAud); err != nil {
return err
}
}
if err := applyFelisConfigSecret(ctx); err != nil {
return err
}
if err := kubectl(ctx, "-n", "felis", "rollout", "restart", "deployment/felis-api"); err != nil {
return err
}
if err := installCloudflaredService(ctx, cloudflaredBin, result.ConfigPath); err != nil {
return err
}
return kubectl(ctx, "-n", "felis", "rollout", "status", "deployment/felis-api", "--timeout=180s")
}
func updateAuthConfig(path, panelHost, adminHost, aud string) error {
cfg, err := config.Load(path)
if err != nil {
return err
}
if panelHost != "" {
cfg.Auth.PanelHostname = panelHost
}
cfg.Auth.AdminHostname = adminHost
cfg.Auth.AccessJWTAud = aud
return writeConfig(path, cfg)
}
func writeConfig(path string, cfg *config.Config) error {
tmp, err := os.CreateTemp(filepath.Dir(path), ".felis-*.toml")
if err != nil {
return err
}
tmpPath := tmp.Name()
defer os.Remove(tmpPath)
if err := toml.NewEncoder(tmp).Encode(cfg); err != nil {
_ = tmp.Close()
return err
}
if err := tmp.Close(); err != nil {
return err
}
return os.Rename(tmpPath, path)
}
func applyFelisConfigSecret(ctx context.Context) error {
out, err := kubectlOutput(ctx,
"-n", "felis", "create", "secret", "generic", "felis-config",
"--from-file=felis.toml="+podSetupConfigPath,
"--dry-run=client", "-o", "yaml",
)
if err != nil {
return err
}
return kubectlWithInput(ctx, out, "apply", "-f", "-")
}
func installCloudflaredService(ctx context.Context, cloudflaredBin, configPath string) error {
if cloudflaredBin == "" {
return fmt.Errorf("cloudflared binary path is empty")
}
if configPath == "" {
return fmt.Errorf("cloudflared config path is empty")
}
unit := fmt.Sprintf(`[Unit]
Description=Felis Cloudflare Tunnel
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=%s --config %s tunnel run
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
`, cloudflaredBin, configPath)
if err := os.WriteFile(cloudflaredFelisUnit, []byte(unit), 0o644); err != nil {
return err
}
if err := systemctl(ctx, "daemon-reload"); err != nil {
return err
}
return systemctl(ctx, "enable", "--now", "cloudflared-felis.service")
}
func kubectl(ctx context.Context, args ...string) error {
_, err := kubectlOutput(ctx, args...)
return err
}
func kubectlWithInput(ctx context.Context, input []byte, args ...string) error {
_, err := runK3sKubectl(ctx, input, args...)
return err
}
func kubectlOutput(ctx context.Context, args ...string) ([]byte, error) {
return runK3sKubectl(ctx, nil, args...)
}
func runK3sKubectl(ctx context.Context, input []byte, args ...string) ([]byte, error) {
fullArgs := append([]string{"kubectl"}, args...)
cmd := exec.CommandContext(ctx, "k3s", fullArgs...)
cmd.Env = append(os.Environ(), "KUBECONFIG="+hostBootstrapKubeconfigPath)
if input != nil {
cmd.Stdin = bytes.NewReader(input)
}
out, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("k3s %v: %w: %s", fullArgs, err, string(out))
}
return out, nil
}
func systemctl(ctx context.Context, args ...string) error {
cmd := exec.CommandContext(ctx, "systemctl", args...)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("systemctl %v: %w: %s", args, err, string(out))
}
return nil
}