refactor: make logic to controller.maker

This commit is contained in:
zhaoyupeng
2025-11-24 23:04:40 +08:00
parent 27fa38aef0
commit 454e0639a0
29 changed files with 1026 additions and 757 deletions

View File

@@ -0,0 +1,36 @@
package maker
import (
"context"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/archiver"
)
func (m *maker) Binary(ctx context.Context) error {
var (
tarURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/k8s-bin.tar"
binDir = filepath.Join(opt.Cfg.Make.Dir, "dependency")
)
logger.Info("☑️ 开始准备 k8s 二进制文件...")
logger.Debug("下载地址: %s", tarURL)
logger.Debug("目标目录: %s", binDir)
if err := archiver.DownloadAndExtract(
ctx,
tarURL,
binDir,
archiver.WithInsecureSkipVerify(),
archiver.WithGzipCompression(true),
); err != nil {
logger.Info("❌ 下载并解压二进制文件失败")
return err
}
logger.Info("✅ 准备 k8s 二进制文件成功!!!")
return nil
}

View File

@@ -0,0 +1,37 @@
package maker
import (
"context"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/archiver"
)
func (m *maker) Deb(ctx context.Context) error {
var (
tarURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/deb/docker.tar.gz"
binDir = filepath.Join(opt.Cfg.Make.Dir, "dependency", "deb")
)
logger.Info("☑️ 开始准备 deb(docker) 文件...")
logger.Debug("下载地址: %s", tarURL)
logger.Debug("目标目录: %s", binDir)
if err := archiver.DownloadAndExtract(
ctx,
tarURL,
binDir,
archiver.WithInsecureSkipVerify(),
archiver.WithGzipCompression(true),
); err != nil {
logger.Info("❌ 下载并解压 deb(docker) 文件失败")
logger.Debug("下载并解压 deb(docker) 文件失败: %v", err)
return err
}
logger.Info("✅ 准备 deb(docker) 文件成功!!!")
return nil
}

View File

@@ -0,0 +1,184 @@
package maker
import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/archiver"
"yizhisec.com/hsv2/forge/pkg/resource"
)
type ElasticOpt func(*elasticOpt)
type elasticOpt struct {
MakeHelper bool
MemRate int
Storage string
}
func WithElasticMakeHelper(makeHelper bool) ElasticOpt {
return func(o *elasticOpt) {
o.MakeHelper = makeHelper
}
}
func WithElasticMemRate(memRate int) ElasticOpt {
return func(o *elasticOpt) {
if memRate > 0 {
o.MemRate = memRate
}
}
}
func WithElasticStorageGi(storage string) ElasticOpt {
return func(o *elasticOpt) {
if matched, _ := regexp.MatchString(`^\d+(\.\d+)?[EPTGMK]i?$`, storage); matched {
o.Storage = storage
}
}
}
func (m *maker) Elastic(ctx context.Context, opts ...ElasticOpt) error {
const (
dockerFile = `
FROM docker-mirror.yizhisec.com/library/alpine:3.22.2
WORKDIR /data
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && apk add curl
ENV TZ=Asia/Shanghai
COPY plugins /data/plugins
COPY create_index.sh /data/create_index.sh
RUN chmod +x /data/create_index.sh
`
helperImageName = "hub.yizhisec.com/hybridscope/v2/es-init-helper:alpine-3.22.2"
pluginUrl = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/dependency/elasticsearch/v2-es-plugins.tar.gz"
)
var (
err error
output []byte
location = filepath.Join(opt.Cfg.Make.Dir, "dependency", "elastic")
helperTarLocation = filepath.Join(opt.Cfg.Make.Dir, "dependency", "image", "es-init-helper.alpine-3.22.2.tar")
)
opt := &elasticOpt{
MemRate: 1,
Storage: "100Gi",
}
for _, fn := range opts {
fn(opt)
}
logger.Info("☑️ maker.Elastic: 开始构建 elasticsearch(es) 依赖...")
logger.Debug("☑️ maker.Elastic: 开始构建 elasticsearch(es) 依赖..., opt = %#v", opt)
logger.Debug("☑️ maker.Elastic: 创建目录 %s", location)
if err = os.MkdirAll(location, 0755); err != nil {
logger.Debug("❌ maker.Elastic: 创建目录失败: %v", err)
return err
}
logger.Debug("✅ maker.Elastic: 创建目录 %s 成功", location)
if opt.MakeHelper {
tmp := filepath.Join(os.TempDir(), "make-es")
logger.Debug("☑️ maker.Elastic: 构建 helper..., dir = %s", tmp)
logger.Debug("☑️ maker.Elastic: 删除并创建临时目录 %s", tmp)
if err = os.RemoveAll(tmp); err != nil {
logger.Debug("❌ maker.Elastic: 删除临时目录失败: %v", err)
return err
}
if err = os.MkdirAll(tmp, 0755); err != nil {
logger.Debug("❌ maker.Elastic: 创建临时目录失败: %v", err)
return err
}
logger.Debug("✅ maker.Elastic: 删除并创建临时目录 %s 成功", tmp)
logger.Debug("☑️ maker.Elastic: 写入 Dockerfile ...")
if err = os.WriteFile(filepath.Join(tmp, "Dockerfile"), []byte(dockerFile), 0644); err != nil {
logger.Debug("❌ maker.Elastic: 写入 Dockerfile 失败: %v", err)
return err
}
logger.Debug("✅ maker.Elastic: 写入 Dockerfile 成功")
logger.Debug("☑️ maker.Elastic: 下载 es 插件... url = %s", pluginUrl)
if err = archiver.DownloadAndExtract(
ctx,
pluginUrl,
tmp,
archiver.WithInsecureSkipVerify(),
); err != nil {
logger.Debug("❌ maker.Elastic: 下载 es 插件失败: url = %s, err = %v", pluginUrl, err)
return err
}
logger.Debug("✅ maker.Elastic: 下载 es 插件成功, url = %s", pluginUrl)
logger.Debug("☑️ maker.Elastic: 写入 create_index.sh 文件...")
if err = os.WriteFile(filepath.Join(tmp, "create_index.sh"), resource.BashESInit, 0644); err != nil {
logger.Debug("❌ maker.Elastic: 写入 create_index.sh 文件失败: %v", err)
return err
}
logger.Debug("✅ maker.Elastic: 写入 create_index.sh 文件成功")
helpCmd := exec.CommandContext(ctx, "docker", "build", "-t",
helperImageName,
"-f", filepath.Join(tmp, "Dockerfile"),
tmp,
)
logger.Debug("☑️ maker.Elastic: 重新构建 helper 镜像..., cmd = %s", helpCmd.String())
if output, err = helpCmd.CombinedOutput(); err != nil {
logger.Debug("MakeES: 重新构建 helper 镜像失败, err = %v, output = %s", err, string(output))
return err
}
logger.Debug("✅ maker.Elastic: 重新构建 helper 镜像成功, cmd = %s", helpCmd.String())
logger.Debug("✅ maker.Elastic: 构建 helper 成功, dir = %s", tmp)
}
logger.Debug("☑️ maker.Elastic: 准备 es init helper 镜像..., location = %s", helperTarLocation)
if err = m.Image(
ctx,
helperImageName,
WithImageSave(helperTarLocation),
); err != nil {
logger.Debug("❌ maker.Elastic: 准备 es init helper 镜像失败, location = %s, err = %v", helperTarLocation, err)
return err
}
logger.Debug("✅ maker.Elastic: 准备 es init helper 镜像成功, location = %s", helperTarLocation)
bs := []byte(fmt.Sprintf(resource.YAMLES,
opt.MemRate, opt.MemRate*2,
opt.MemRate, opt.MemRate,
opt.MemRate*2, opt.MemRate*2,
opt.Storage,
))
logger.Debug("☑️ maker.Elastic: 写入 es.yaml 文件...")
if err = os.WriteFile(filepath.Join(location, "es.yaml"), bs, 0644); err != nil {
logger.Debug("❌ maker.Elastic: 写入 es.yaml 文件失败: %v", err)
return err
}
logger.Debug("✅ maker.Elastic: 写入 es.yaml 文件成功")
logger.Debug("☑️ maker.Elastic: 写入 kibana.yaml 文件...")
if err = os.WriteFile(filepath.Join(location, "kibana.yaml"), resource.YAMLKibana, 0644); err != nil {
logger.Debug("❌ maker.Elastic: 写入 kibana.yaml 文件失败: %v", err)
return err
}
logger.Debug("✅ maker.Elastic: 写入 kibana.yaml 文件成功")
logger.Info("✅ maker.Elastic: 构建 elastic(es) 依赖成功!!!")
return nil
}

View File

@@ -0,0 +1,33 @@
package maker
import (
"context"
"os"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/resource"
)
func (m *maker) EMQX(ctx context.Context) error {
var (
err error
location = filepath.Join(opt.Cfg.Make.Dir, "emqx")
)
logger.Info("☑️ MakeEMQX: 开始构建 emqx(mqtt) 依赖...")
if err = os.MkdirAll(location, 0755); err != nil {
logger.Debug("❌ MakeEMQX: 创建 emqx 目录失败: %v", err)
return err
}
if err = os.WriteFile(filepath.Join(location, "emqx.yaml"), resource.YAMLEMQX, 0644); err != nil {
logger.Debug("❌ MakeEMQX: 写入 emqx.yaml 失败, err: %v", err)
return err
}
logger.Info("✅ MakeEMQX: 构建 emqx(mqtt) 依赖成功!!!")
return nil
}

View File

@@ -0,0 +1,40 @@
package maker
import (
"context"
"fmt"
"os"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/resource"
)
func (m *maker) Flannel(ctx context.Context, mode string) error {
var (
err error
location = filepath.Join(opt.Cfg.Make.Dir, "dependency", "flannel")
)
logger.Info("☑️ 开始构建 flannel 资源...")
logger.Debug("MakeFlannel location: %s", location)
if err = os.Mkdir(location, 0755); err != nil {
logger.Error("MakeFlannel: 创建目录 %s 失败", location)
logger.Debug("MakeFlannel: 创建目录 %s 失败: %v", location, err)
return err
}
bs := []byte(fmt.Sprintf(resource.YAMLFlannel, mode))
if err = os.WriteFile(filepath.Join(location, "flannel.yaml"), bs, 0644); err != nil {
logger.Error("MakeFlannel: 创建文件 %s 失败", filepath.Join(location, "flannel.yaml"))
logger.Debug("MakeFlannel: 创建文件 %s 失败: %v", filepath.Join(location, "flannel.yaml"), err)
return err
}
logger.Info("✅ 构建 flannel 成功!!!")
return nil
}

View File

@@ -0,0 +1,27 @@
package maker
import (
"context"
"os"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
)
func (m *maker) HSNet(ctx context.Context) error {
var (
err error
location = filepath.Join(opt.Cfg.Make.Dir, "dependency", "hs-net")
)
if err = os.MkdirAll(location, 0755); err != nil {
logger.Error("MakeHSNet: 创建目录失败s")
logger.Debug("MakeHSNet: 创建目录失败: %s", err.Error())
return err
}
logger.Fatal("MakeHSNet: 构建 hs-net 失败!!!(怎么完善,怎么完善,怎么完善???)")
return nil
}

View File

@@ -2,10 +2,13 @@ package maker
import (
"context"
"os"
"os/exec"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"github.com/samber/lo"
"yizhisec.com/hsv2/forge/internal/opt"
)
type imageOpt struct {
@@ -36,7 +39,6 @@ func WithImageForcePull() ImageOpt {
}
func (m *maker) Image(ctx context.Context, name string, opts ...ImageOpt) error {
logger.Info("开始获取镜像: %s", name)
var (
err error
o = &imageOpt{}
@@ -47,50 +49,53 @@ func (m *maker) Image(ctx context.Context, name string, opts ...ImageOpt) error
fn(o)
}
logger.Debug("maker.Image: name = %s, opt = %#v", name, o)
logger.Debug("📋 maker.Image: name = %s, opt = %#v", name, o)
if !o.ForcePull {
_cmd = exec.CommandContext(ctx, "docker", "image", "inspect", name)
if err = _cmd.Run(); err == nil {
logger.Info("💾 镜像 %s 已存在", name)
logger.Debug("💿 镜像 %s 已存在", name)
goto SAVE
}
}
_cmd = exec.CommandContext(ctx, "docker", "pull", name)
if err = _cmd.Run(); err != nil {
logger.Debug("获取原始镜像 %s 失败: %v", name, err)
logger.Debug("获取原始镜像 %s 失败: %v", name, err)
} else {
logger.Info("✅ 成功获取镜像: %s", name)
logger.Debug("✅ 成功获取镜像: %s", name)
goto SAVE
}
for _, fallback := range o.Fallbacks {
logger.Info("开始获取镜像: %s (%s)", name, fallback)
logger.Debug("☑️ 开始获取镜像: %s (%s)", name, fallback)
_cmd := exec.CommandContext(ctx, "docker", "pull", fallback)
if err = _cmd.Run(); err != nil {
logger.Debug("获取镜像 %s (%s) 失败: %v", name, fallback, err)
logger.Debug("获取镜像 %s (%s) 失败: %v", name, fallback, err)
continue
}
// pull success, retag image
_cmd = exec.CommandContext(ctx, "docker", "tag", fallback, name)
if err = _cmd.Run(); err != nil {
logger.Debug("重命名镜像 %s => %s 失败: %s", fallback, name, err)
logger.Debug("重命名镜像 %s => %s 失败: %s", fallback, name, err)
continue
}
logger.Info("✅ 成功获取镜像: %s (%s)", name, fallback)
logger.Debug("✅ 成功获取镜像: %s (%s)", name, fallback)
break
}
SAVE:
if o.Save != "" {
logger.Debug("保存镜像 %s 到 %s", name, o.Save)
logger.Debug("☑️ 保存镜像 %s 到 %s", name, o.Save)
_ = os.MkdirAll(filepath.Dir(o.Save), 0755)
if err = exec.CommandContext(ctx, "docker", "save", "-o", o.Save, name).Run(); err != nil {
logger.Debug("保存镜像 %s 到 %s 失败: %v", name, o.Save, err)
logger.Debug("保存镜像 %s 到 %s 失败: %v", name, o.Save, err)
} else {
logger.Info("✅ 镜像 %s 保存到 %s 成功", name, o.Save)
logger.Debug("✅ 镜像 %s 保存到 %s 成功", name, o.Save)
}
}
@@ -100,3 +105,92 @@ SAVE:
return err
}
func (m *maker) Images(ctx context.Context) error {
type Images struct {
Name string
Fallback string
Save string
Force bool
}
var images = []*Images{
{Name: "quay.io/k0sproject/apiserver-network-proxy-agent:v0.32.0", Fallback: "hub.yizhisec.com/external/apiserver-network-proxy-agent:v0.32.0", Save: "k0s.apiserver-network-proxy-agent.tar"},
{Name: "quay.io/k0sproject/cni-node:1.7.1-k0s.0", Fallback: "", Save: "k0s.cni-node.tar"},
{Name: "quay.io/k0sproject/coredns:1.12.2", Fallback: "", Save: "k0s.coredns.tar"},
{Name: "quay.io/k0sproject/kube-proxy:v1.33.4", Fallback: "", Save: "k0s.kube-proxy.tar"},
{Name: "quay.io/k0sproject/kube-router:v2.5.0-iptables1.8.11-0", Fallback: "", Save: "k0s.kube-router.tar"},
{Name: "quay.io/k0sproject/metrics-server:v0.7.2-0", Fallback: "", Save: "k0s.metrics-server.tar"},
{Name: "quay.io/k0sproject/pause:3.10.1", Fallback: "", Save: "k0s.pause.tar"},
{Name: "ghcr.io/flannel-io/flannel:v0.27.4", Fallback: "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/flannel-io/flannel:v0.27.4", Save: "flannel.tar"},
{Name: "ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1", Fallback: "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1", Save: "flannel-cni-plugin.tar"},
{Name: "docker.io/longhornio/longhorn-engine:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-engine:v1.10.0", Save: "longhorn.longhorn-engine.tar"},
{Name: "docker.io/longhornio/longhorn-manager:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-manager:v1.10.0", Save: "longhorn.longhorn-manager.tar"},
{Name: "docker.io/longhornio/longhorn-instance-manager:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-instance-manager:v1.10.0", Save: "longhorn.longhorn-instance-manager.tar"},
{Name: "docker.io/longhornio/longhorn-share-manager:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-share-manager:v1.10.0", Save: "longhorn.longhorn-share-manager.tar"},
{Name: "docker.io/longhornio/longhorn-ui:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-ui:v1.10.0", Save: "longhorn.longhorn-ui.tar"},
{Name: "docker.io/longhornio/csi-snapshotter:v8.3.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-snapshotter:v8.3.0-20250826", Save: "longhorn.csi-snapshotter.tar"},
{Name: "docker.io/longhornio/csi-resizer:v1.14.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-resizer:v1.14.0-20250826", Save: "longhorn.csi-resizer.tar"},
{Name: "docker.io/longhornio/csi-provisioner:v5.3.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-provisioner:v5.3.0-20250826", Save: "longhorn.csi-provisioner.tar"},
{Name: "docker.io/longhornio/livenessprobe:v2.16.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/livenessprobe:v2.16.0-20250826", Save: "longhorn.livenessprobe.tar"},
{Name: "docker.io/longhornio/csi-node-driver-registrar:v2.14.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-node-driver-registrar:v2.14.0-20250826", Save: "longhorn.csi-node-driver-registrar.tar"},
{Name: "docker.io/longhornio/csi-attacher:v4.9.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-attacher:v4.9.0-20250826", Save: "longhorn.csi-attacher.tar"},
{Name: "hub.yizhisec.com/external/alpine:3.22.2", Fallback: "", Save: "alpine.tar", Force: true},
{Name: "hub.yizhisec.com/external/nginx:1.29.1-alpine3.22", Fallback: "", Save: "nginx.1.29.1-alpine3.22.tar"},
{Name: "docker.io/bitpoke/mysql-operator:v0.6.3", Fallback: "docker-mirror.yizhisec.com/bitpoke/mysql-operator:v0.6.3", Save: "bitpoke.mysql-operator.v0.6.3.tar"},
{Name: "docker.io/bitpoke/mysql-operator-orchestrator:v0.6.3", Fallback: "docker-mirror.yizhisec.com/bitpoke/mysql-operator-orchestrator:v0.6.3", Save: "bitpoke.mysql-operator-orchestrator.v0.6.3.tar"},
{Name: "docker.io/bitpoke/mysql-operator-sidecar-8.0:v0.6.3", Fallback: "docker-mirror.yizhisec.com/bitpoke/mysql-operator-sidecar-8.0:v0.6.3", Save: "bitpoke.mysql-operator-sidecar-8.0.v0.6.3.tar"},
{Name: "docker.io/library/percona:8.0.28-20", Fallback: "docker-mirror.yizhisec.com/library/percona:8.0.28-20", Save: "percona.8.0.28-20.tar"},
{Name: "docker.io/prom/mysqld-exporter:v0.13.0", Fallback: "docker-mirror.yizhisec.com/prom/mysqld-exporter:v0.13.0", Save: "prom.mysqld-exporter.v0.13.0.tar"},
{Name: "docker.io/bitnami/redis:8.2.2", Fallback: "hub.yizhisec.com/external/bitnami/redis:8.2.2", Save: "bitnami.redis.8.2.2.tar"},
{Name: "hub.yizhisec.com/external/elasticsearch:7.17.28", Fallback: "", Save: "elasticsearch.7.17.28.tar"},
{Name: "hub.yizhisec.com/external/kibana:7.17.28", Fallback: "", Save: "kibana.7.17.28.tar"},
{Name: "hub.yizhisec.com/external/emqx:5.1", Fallback: "", Save: "emqx.5.1.tar"},
{Name: "hub.yizhisec.com/build/hybirdscope/front/admin:latest", Fallback: "", Save: "app.front.admin.tar", Force: true},
{Name: "hub.yizhisec.com/hybridscope/v2/front-user:latest", Fallback: "", Save: "app.front.user.tar", Force: true},
{Name: "hub.yizhisec.com/hybridscope/user_management:latest", Fallback: "", Save: "app.user.tar", Force: true},
{Name: "hub.yizhisec.com/hybridscope/gateway_controller:latest", Fallback: "", Save: "app.gateway.tar", Force: true},
{Name: "hub.yizhisec.com/hybridscope/client_server:latest", Fallback: "", Save: "app.client.tar", Force: true},
{Name: "hub.yizhisec.com/hybridscope/mie-server:latest", Fallback: "", Save: "app.mie.tar", Force: true},
{Name: "hub.yizhisec.com/hybridscope/less_dns_service:latest", Fallback: "", Save: "app.less_dns.tar", Force: true},
{Name: "hub.yizhisec.com/hybridscope/hsnet:release_2.1.0-std", Fallback: "", Save: "app.hsnet.tar", Force: true},
}
for _, image := range images {
image.Save = filepath.Join(opt.Cfg.Make.Dir, "dependency", "image", image.Save)
}
logger.Info("☑️ 开始获取镜像(s)...")
for _, image := range images {
opts := []ImageOpt{
WithImageFallback(image.Fallback),
WithImageSave(image.Save),
}
if image.Force {
opts = append(opts, WithImageForcePull())
}
logger.Info("☑️ 获取镜像: %s", image.Name)
if err := m.Image(ctx, image.Name, opts...); err != nil {
logger.Error("❌ 获取镜像失败: %s, 可以手动获取后重试", image.Name)
logger.Debug("❌ 获取镜像失败: %s, %v", image.Name, err)
return err
}
logger.Info("✅ 获取镜像成功: %s", image.Name)
}
logger.Info("✅ 获取镜像(s)成功!!!")
return nil
}

View File

@@ -0,0 +1,34 @@
package maker
import (
"context"
"os"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/resource"
)
func (m *maker) LessDNS(ctx context.Context) error {
var (
err error
location = filepath.Join(opt.Cfg.Make.Dir, "dependency", "less-dns")
)
logger.Info("MakeLessDNS: 开始构建 less-dns...")
if err = os.MkdirAll(location, 0755); err != nil {
logger.Error("MakeLessDNS: 创建目录失败s")
logger.Debug("MakeLessDNS: 创建目录失败: %s", err.Error())
return err
}
if err = os.WriteFile(filepath.Join(location, "deployment.yaml"), resource.YAMLLessDNS, 0644); err != nil {
logger.Error("MakeLessDNS: 写入文件失败")
logger.Debug("MakeLessDNS: 写入文件失败: %s", err.Error())
return err
}
logger.Info("MakeLessDNS: 构建 less-dns 成功!!!")
return nil
}

View File

@@ -0,0 +1,64 @@
package maker
import (
"context"
"fmt"
"os"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/downloader"
)
func (m *maker) Longhorn(ctx context.Context, replica int) error {
const (
valuesContent = `# 设置 Longhorn 数据存储路径
defaultSettings:
defaultDataPath: "/data/longhorn"
# 设置默认副本数
persistence:
reclaimPolicy: Retain
defaultClassReplicaCount: %d
`
)
var (
err error
chartURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/charts/longhorn-1.10.0.tgz"
longhornDir = filepath.Join(opt.Cfg.Make.Dir, "dependency", "longhorn")
chartFile = filepath.Join(longhornDir, "longhorn-1.10.0.tgz")
valuesFile = filepath.Join(longhornDir, "values.yaml")
)
logger.Info("☑️ 开始准备 Longhorn 资源...")
logger.Debug("下载地址: %s", chartURL)
logger.Debug("目标目录: %s", longhornDir)
if err = os.MkdirAll(filepath.Join(opt.Cfg.Make.Dir, "dependency", "longhorn"), 0755); err != nil {
return err
}
// Download the chart file
if err = downloader.Download(
ctx,
chartURL,
chartFile,
downloader.WithInsecureSkipVerify(),
); err != nil {
logger.Info("❌ 下载 Longhorn chart 失败")
return err
}
// Create values.yaml file
bs := []byte(fmt.Sprintf(valuesContent, replica))
if err := os.WriteFile(valuesFile, bs, 0644); err != nil {
logger.Debug("创建 values.yaml 失败: %v", err)
logger.Info("❌ 创建 values.yaml 失败")
return err
}
logger.Info("✅ 成功创建 longhorn 资源!!!")
return nil
}

View File

@@ -0,0 +1,164 @@
package maker
import (
"context"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"regexp"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/downloader"
)
type MysqlOpt func(*mysqlOpt)
type mysqlOpt struct {
Replica int
Storage string
Password string
}
func WithMySQLReplica(replica int) MysqlOpt {
return func(o *mysqlOpt) {
o.Replica = replica
}
}
func WithMySQLStorage(storage string) MysqlOpt {
return func(o *mysqlOpt) {
// validate Kubernetes storage size string (e.g., "50Gi", "100Mi")
if matched, _ := regexp.MatchString(`^\d+(\.\d+)?[EPTGMK]i?$`, storage); matched {
o.Storage = storage
}
}
}
func WithMySQLPassword(password string) MysqlOpt {
return func(o *mysqlOpt) {
if password != "" {
o.Password = password
}
}
}
func (m *maker) MySQL(ctx context.Context, opts ...MysqlOpt) error {
const (
_yaml = `
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
namespace: db-mysql
type: Opaque
data:
ROOT_PASSWORD: %s
---
apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
name: mysql-cluster
namespace: db-mysql
spec:
mysqlVersion: "8.0"
replicas: %d
image: docker.io/library/percona:8.0.28-20
secretName: mysql-secret
volumeSpec:
persistentVolumeClaim:
accessModes: ["ReadWriteOnce"]
storageClassName: longhorn
resources:
requests:
storage: %s
podSpec:
resources:
requests:
cpu: "250m"
memory: "250Mi"
limits:
cpu: "2"
memory: "4Gi"
# affinity:
# podAntiAffinity:
# requiredDuringSchedulingIgnoredDuringExecution: # 强制规则
# - labelSelector:
# matchExpressions:
# - key: app.kubernetes.io/name
# operator: In
# values: ["mysql"]
# - key: app.kubernetes.io/instance
# operator: In
# values: ["mysql-cluster"]
# topologyKey: "kubernetes.io/hostname" # 确保不同节点
---
apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlDatabase
metadata:
name: my-database-mie
namespace: db-mysql
spec:
database: mie
clusterRef:
name: mysql-cluster
namespace: db-mysql
`
)
var (
o = &mysqlOpt{
Replica: 2,
Storage: "50Gi",
Password: "L0hMysql.",
}
err error
chartURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/charts/mysql-operator-0.6.3.tgz"
mysqlDir = filepath.Join(opt.Cfg.Make.Dir, "dependency", "mysql")
chartFile = filepath.Join(mysqlDir, "mysql-operator-0.6.3.tgz")
clusterFile = filepath.Join(mysqlDir, "cluster.yaml")
)
for _, fn := range opts {
fn(o)
}
logger.Info("☑️ 开始构建 MySQL 资源...")
if err = os.MkdirAll(mysqlDir, 0755); err != nil {
return err
}
o.Password = base64.StdEncoding.EncodeToString([]byte(o.Password))
logger.Debug("正在下载 MySQL operator chart..., url = %s, dir = %s", chartURL, mysqlDir)
if err = downloader.Download(
ctx,
chartURL,
chartFile,
downloader.WithInsecureSkipVerify(),
); err != nil {
logger.Info("❌ 下载 MySQL operator chart 失败")
return err
}
logger.Debug("✅ 成功下载 MySQL operator chart")
bs := []byte(fmt.Sprintf(_yaml, o.Password, o.Replica, o.Storage))
// Generate secret.yaml
if err = os.WriteFile(clusterFile, bs, 0644); err != nil {
logger.Debug("创建 database.yaml 失败: %v", err)
logger.Info("❌ 创建 database.yaml 失败")
return err
}
logger.Debug("✅ 成功创建 database.yaml")
logger.Info("✅ MySQL 资源构建成功!!!")
return nil
}

View File

@@ -0,0 +1,128 @@
package maker
import (
"context"
"fmt"
"os"
"path/filepath"
"regexp"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/downloader"
)
type RedisOpt func(*redisOpt)
type redisOpt struct {
ReplicaCount int
Password string
Storage string
}
func WithRedisReplicaCount(replica int) RedisOpt {
return func(o *redisOpt) {
if replica > 0 {
o.ReplicaCount = replica
}
}
}
func WithRedisPassword(password string) RedisOpt {
return func(o *redisOpt) {
if password != "" {
o.Password = password
}
}
}
func WithRedisStorage(storage string) RedisOpt {
return func(o *redisOpt) {
if matched, _ := regexp.MatchString(`^\d+(\.\d+)?[EPTGMK]i?$`, storage); matched {
o.Storage = storage
}
}
}
func (m *maker) Redis(ctx context.Context, opts ...RedisOpt) error {
const (
valuesTemplate = `# Redis configuration
architecture: replication
image:
registry: docker.io
repository: bitnami/redis
tag: 8.2.2
pullPolicy: IfNotPresent
auth:
enabled: true
password: "%s"
master:
persistence:
enabled: true
storageClass: "longhorn"
size: %s
replica:
replicaCount: %d
persistence:
enabled: true
storageClass: "longhorn"
size: %s
metrics:
enabled: false
serviceMonitor:
enabled: false
`
defaultPassword = "HybridScope0xRed1s."
chartURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/charts/redis-23.2.2.tgz"
chartFilename = "redis-23.2.2.tgz"
)
o := &redisOpt{
ReplicaCount: 2,
Password: "HybridScope0xRed1s.",
Storage: "5Gi",
}
for _, fn := range opts {
fn(o)
}
redisDir := filepath.Join(opt.Cfg.Make.Dir, "dependency", "redis")
chartFile := filepath.Join(redisDir, chartFilename)
valuesFile := filepath.Join(redisDir, "values.yaml")
if err := os.MkdirAll(redisDir, 0755); err != nil {
return err
}
logger.Info("开始构建 Redis 资源...")
logger.Debug("下载地址: %s", chartURL)
logger.Debug("目标目录: %s", redisDir)
logger.Debug("Redis 副本数: %d", o.ReplicaCount)
if err := downloader.Download(
ctx,
chartURL,
chartFile,
downloader.WithInsecureSkipVerify(),
); err != nil {
logger.Debug("❌ 下载 Redis chart 失败")
return err
}
logger.Debug("✅ 成功下载 Redis chart")
bs := fmt.Sprintf(valuesTemplate, o.Password, o.Storage, o.ReplicaCount, o.Storage)
if err := os.WriteFile(valuesFile, []byte(bs), 0644); err != nil {
logger.Info("❌ 创建 values.yaml 失败")
return err
}
logger.Debug("✅ 成功创建 values.yaml")
logger.Info("✅ Redis 资源构建成功")
return nil
}

View File

@@ -0,0 +1,104 @@
package maker
import (
"context"
"os"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/internal/opt"
"yizhisec.com/hsv2/forge/pkg/downloader"
"yizhisec.com/hsv2/forge/pkg/resource"
)
type YosguardOpt func(*yosguardOpt)
type yosguardOpt struct{}
func (m *maker) Yosguard(ctx context.Context, opts ...YosguardOpt) error {
const (
configTemplate = `
Web:
# default listen in docker0
Host: 172.17.0.1
Port: 7788
UUIDFilePath: /etc/yosguard/uuid
# 心跳间隔: 单位秒,默认为5
HeartbeatDuration: 5
# 控制器 yosguard 地址
ControllerServer:
Host: dasheng.zhsftech.debug
Port: 443
# True: 作为控制器运行; False: 不作为控制器运行
AsController: true
# True: 作为网关运行; False: 不作为网关运行
AsGateway: false
Database:
SQLite:
DBPath: "/etc/yosguard/db/yosguard.db"
SQLPath: "/etc/yosguard/db/create.sql"`
systemdService = `
[Unit]
Description=YiZhiSec YOSGuard
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/yosguard web --host __host__
StandardOutput=journal
StandardError=journal
Nice=-20
Restart=always
RestartSec=15
[Install]
WantedBy=multi-user.target`
binURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv2/bin/yosguard"
)
location := filepath.Join(opt.Cfg.Make.Dir, "dependency", "yosguard")
logger.Info("☑️ MakeYosguard: 开始构建 yosguard...")
if err := os.MkdirAll(location, 0755); err != nil {
logger.Debug("❌ MakeYosguard: 创建 yosguard 目录失败: %v", err)
return err
}
if err := downloader.Download(
ctx,
binURL,
filepath.Join(location, "yosguard"),
downloader.WithInsecureSkipVerify(),
downloader.WithFileMode(0755),
); err != nil {
logger.Debug("❌ MakeYosguard: 下载 yosguard 失败: %v", err)
return err
}
if err := os.WriteFile(filepath.Join(location, "config_template.yml"), []byte(configTemplate), 0644); err != nil {
logger.Debug("❌ MakeYosguard: 生成 config_template.yml 失败: %v", err)
return err
}
if err := os.WriteFile(filepath.Join(location, "create.sql"), resource.SQLYosguard, 0644); err != nil {
logger.Debug("❌ MakeYosguard: 生成 create.sql 失败: %v", err)
return err
}
if err := os.WriteFile(filepath.Join(location, "yosguard.service"), []byte(systemdService), 0644); err != nil {
logger.Debug("❌ MakeYosguard: 生成 yosguard.service 失败: %v", err)
return err
}
logger.Info("✅ MakeYosguard: 构建 yosguard成功!!!")
return nil
}