feat: 🎉 complete maker nginx(app)

This commit is contained in:
zhaoyupeng
2025-11-26 21:03:41 +08:00
parent 4ec58ce4e5
commit 11523e3e48
26 changed files with 1458 additions and 6 deletions

View File

@@ -17,6 +17,7 @@ func App() *cobra.Command {
appGateway(),
appMie(),
appOEM(),
appNginx(),
)
return _cmd
@@ -118,3 +119,30 @@ func appOEM() *cobra.Command {
return _cmd
}
func appNginx() *cobra.Command {
var (
replica int
disableSeafile bool
)
_cmd := &cobra.Command{
Use: "nginx",
Short: "Make Nginx App",
RunE: func(cmd *cobra.Command, args []string) error {
opts := []maker.NginxOpt{
maker.WithNginxReplica(replica),
}
if disableSeafile {
opts = append(opts, maker.WithoutNginxSeafile())
}
mk := maker.NewMaker()
return mk.AppNginx(cmd.Context(), opts...)
},
}
_cmd.Flags().IntVar(&replica, "replica-count", 2, "Replica count")
_cmd.Flags().BoolVar(&disableSeafile, "disable-seafile", false, "Disable seafile")
return _cmd
}

View File

@@ -0,0 +1,15 @@
package installer
import "context"
func (i *installer) Check(ctx context.Context) error {
var (
err error
)
if err = i.targetOK(ctx); err != nil {
return err
}
return nil
}

View File

@@ -1,8 +1,39 @@
package controller
package installer
import (
"context"
"errors"
"os/exec"
"gitea.loveuer.com/yizhisec/pkg3/logger"
)
type installer struct {
target string
}
func NewInstaller() *installer {
return &installer{}
func (i *installer) targetOK(ctx context.Context) error {
if i.target == "" {
logger.Debug("🎯 installer.targetOK: target = self")
return nil
}
// run ssh <target>, check if it's reachable, and it's root user
cmd := exec.CommandContext(ctx, "ssh", i.target, "whoami")
output, err := cmd.CombinedOutput()
if err != nil {
logger.Debug("❌ installer.targetOK: check target %s failed, err = %v", i.target, err)
return err
}
if string(output) != "root\n" {
logger.Debug("❌ installer.targetOK: check target %s failed, output = %s", i.target, string(output))
return errors.New("target is not root user")
}
return nil
}
func NewInstaller(target string) *installer {
return &installer{target: target}
}

View File

@@ -0,0 +1,58 @@
package installer
import (
"context"
"github.com/samber/lo"
)
type K0sOpt func(*k0sOpt)
type k0sOpt struct {
Type string // controller, worker
DisableWorker bool
WorkerTokenFile string
}
func WithK0sType(t string) K0sOpt {
types := []string{"controller", "worker"}
return func(o *k0sOpt) {
if lo.Contains(types, t) {
o.Type = t
}
}
}
func WithoutK0sWorker() K0sOpt {
return func(o *k0sOpt) {
o.DisableWorker = true
}
}
func WithK0sWorkerTokenFile(filename string) K0sOpt {
return func(o *k0sOpt) {
if filename != "" {
o.WorkerTokenFile = filename
}
}
}
func (i *installer) K0s(ctx context.Context, opts ...K0sOpt) error {
var (
err error
o = &k0sOpt{
Type: "controller",
DisableWorker: false,
WorkerTokenFile: "/etc/k0s/worker.token",
}
)
if err = i.targetOK(ctx); err != nil {
return err
}
for _, fn := range opts {
fn(o)
}
return nil
}

View File

@@ -0,0 +1,15 @@
package installer
import "context"
func (i *installer) Prepare(ctx context.Context) error {
var (
err error
)
if err = i.targetOK(ctx); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,7 @@
package installer
import "context"
func (i *installer) YosGuard(ctx context.Context) error {
return nil
}

View File

@@ -0,0 +1,180 @@
package maker
import (
"context"
"fmt"
"os"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"github.com/samber/lo"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/resource"
)
type NginxOpt func(*nginxOpt)
type nginxOpt struct {
WithoutSeafile bool
Replica int
}
func WithNginxReplica(replica int) NginxOpt {
return func(o *nginxOpt) {
if replica >= 0 {
o.Replica = replica
}
}
}
func WithoutNginxSeafile() NginxOpt {
return func(o *nginxOpt) {
o.WithoutSeafile = true
}
}
func (m *maker) AppNginx(ctx context.Context, opts ...NginxOpt) error {
const (
_upsert = `#!/bin/bash
kubectl create configmap nginx-main --namespace hsv2 --from-file=nginx.conf=./conf/nginx.conf --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap nginx-user --namespace hsv2 --from-file=user.conf=./conf/user.conf --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap nginx-gateway --namespace hsv2 --from-file=gateway.conf=./conf/gateway.conf --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap nginx-web --namespace hsv2 --from-file=web.conf=./conf/web.conf --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap nginx-client --namespace hsv2 --from-file=client.conf=./conf/client.conf --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap nginx-common --namespace hsv2 --from-file=common.conf=./conf/common.conf --dry-run=client -o yaml | kubectl apply -f -
%s
kubectl create configmap ssl-ca-crt --namespace hsv2 --from-file=ca.crt=./ssl/ca.crt --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-ffdhe2048 --namespace hsv2 --from-file=ffdhe2048.txt=./ssl/ffdhe2048.txt --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-server-crt --namespace hsv2 --from-file=server.crt=./ssl/server.crt --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-server-key --namespace hsv2 --from-file=server.key=./ssl/server.key --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-mqtt-crt --namespace hsv2 --from-file=mqtt.server.crt=./ssl/mqtt.server.crt --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-mqtt-key --namespace hsv2 --from-file=mqtt.server.key=./ssl/mqtt.server.key --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-client-server-crt --namespace hsv2 --from-file=client.server.crt=./ssl/client.server.crt --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-client-server-key --namespace hsv2 --from-file=client.server.key=./ssl/client.server.key --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-web-server-crt --namespace hsv2 --from-file=web.server.crt=./ssl/web.server.crt --dry-run=client -o yaml | kubectl apply -f -
kubectl create configmap ssl-web-server-key --namespace hsv2 --from-file=web.server.key=./ssl/web.server.key --dry-run=client -o yaml | kubectl apply -f -
kubectl apply -f deployment.yaml
kubectl rollout restart deployment nginx-deployment -n hsv2`
)
var (
err error
workdir = filepath.Join(opt.Cfg.Make.Dir, "app", "nginx")
o = nginxOpt{
WithoutSeafile: false,
Replica: 2,
}
applySeafile = "kubectl create configmap nginx-seafile --namespace hsv2 --from-file=seafile.conf=./conf/seafile.conf --dry-run=client -o yaml | kubectl apply -f -"
)
logger.Info(" ☑️ maker.AppNginx: 开始构建 nginx, workdir = %s", workdir)
for _, fn := range opts {
fn(&o)
}
logger.Debug(" ☑️ maker.AppNginx: 创建工作目录 = %s", workdir)
if err = os.MkdirAll(workdir, 0755); err != nil {
return err
}
logger.Debug("✅ maker.AppNginx: 创建工作目录成功 = %s", workdir)
// 子目录: conf 与 ssl
confDir := filepath.Join(workdir, "conf")
sslDir := filepath.Join(workdir, "ssl")
logger.Debug(" ☑️ maker.AppNginx: 创建 conf 与 ssl 子目录")
if err = os.MkdirAll(confDir, 0755); err != nil {
logger.Debug("❌ maker.AppNginx: 创建 conf 目录失败: %v", err)
return err
}
if err = os.MkdirAll(sslDir, 0755); err != nil {
logger.Debug("❌ maker.AppNginx: 创建 ssl 目录失败: %v", err)
return err
}
logger.Debug("✅ maker.AppNginx: 创建 conf 与 ssl 子目录成功")
// 写入 nginx 配置文件到 conf 子目录(列表 + for 循环)
logger.Debug(" ☑️ maker.AppNginx: 写入 nginx 配置文件到 conf 子目录")
confFiles := []struct {
name string
content []byte
}{
{"nginx.conf", resource.NGINXMain},
{"user.conf", resource.NGINXUser},
{"gateway.conf", resource.NGINXGateway},
{"web.conf", resource.NGINXWeb},
{"client.conf", resource.NGINXClient},
{"common.conf", resource.NGINXCommon},
}
// 过滤 seafile.conf 文件
if !o.WithoutSeafile {
confFiles = append(confFiles, struct {
name string
content []byte
}{
"seafile.conf", resource.NGINXSeafile,
})
}
for _, f := range confFiles {
dest := filepath.Join(confDir, f.name)
if err = os.WriteFile(dest, f.content, 0644); err != nil {
logger.Debug("❌ maker.AppNginx: 写入 %s 失败: %v", f.name, err)
return err
}
logger.Debug("✅ maker.AppNginx: 写入 %s 成功, dest = %s", f.name, dest)
}
logger.Debug("✅ maker.AppNginx: 写入 nginx 配置文件成功")
// 写入 ssl 文件到 ssl 子目录
logger.Debug(" ☑️ maker.AppNginx: 写入 SSL 证书与密钥到 ssl 子目录")
sslFiles := []struct{ name, content string }{
{"ffdhe2048.txt", resource.SSLFFDHE2048},
{"ca.crt", resource.SSLCaCrt},
{"server.crt", resource.SSLServerCrt},
{"server.key", resource.SSLServerKey},
{"mqtt.server.crt", resource.SSLMQTTServerCrt},
{"mqtt.server.key", resource.SSLMQTTServerKey},
{"client.server.crt", resource.SSLClientServerCrt},
{"client.server.key", resource.SSLClientServerKey},
{"web.server.crt", resource.SSLWebServerCrt},
{"web.server.key", resource.SSLWebServerKey},
}
for _, f := range sslFiles {
dest := filepath.Join(sslDir, f.name)
if err = os.WriteFile(dest, []byte(f.content), 0644); err != nil {
logger.Debug("❌ maker.AppNginx: 写入 %s 失败: %v", f.name, err)
return err
}
logger.Debug("✅ maker.AppNginx: 写入 %s 成功, dest = %s", f.name, dest)
}
// write nginx deployment yaml
dest := filepath.Join(workdir, "nginx.yaml")
content := []byte(fmt.Sprintf(resource.YAMLAppNGINX, o.Replica))
if err = os.WriteFile(dest, content, 0644); err != nil {
logger.Debug("❌ maker.AppNginx: 写入 nginx.yaml 失败: %v", err)
return err
}
logger.Debug("✅ maker.AppNginx: 写入 nginx.yaml 成功, dest = %s", dest)
// write nginx upsert script
dest = filepath.Join(workdir, "upsert.sh")
content = []byte(fmt.Sprintf(_upsert, lo.If(o.WithoutSeafile, "").Else(applySeafile)))
if err = os.WriteFile(dest, content, 0755); err != nil {
logger.Debug("❌ maker.AppNginx: 写入 upsert.sh 失败: %v", err)
return err
}
logger.Debug("✅ maker.AppNginx: 写入 upsert.sh 成功, dest = %s", dest)
logger.Info("✅ maker.AppNginx: nginx 构建完成")
return nil
}