package maker import ( "context" "encoding/json" "fmt" "os" "path/filepath" "strings" "gitea.loveuer.com/yizhisec/pkg3/logger" "github.com/samber/lo" "yizhisec.com/hsv2/forge/pkg/resource" ) type clientPKGDownload struct { URL string Name string } type ClientPKGOption func(*clientPKGOption) type clientPKGOption struct { Downloads []*clientPKGDownload CMDs []string MakePkg bool } func WithClientPkgMakePkg(pkg bool) ClientPKGOption { return func(o *clientPKGOption) { o.MakePkg = pkg } } func WithClientPKGDownload(url, location string) ClientPKGOption { return func(o *clientPKGOption) { if url == "" || location == "" { return } o.Downloads = append(o.Downloads, &clientPKGDownload{ URL: url, Name: location, }) } } func WithClientPKGCMDs(cmds ...string) ClientPKGOption { return func(o *clientPKGOption) { adds := lo.Filter(cmds, func(cmd string, _ int) bool { return cmd != "" }) o.CMDs = append(o.CMDs, adds...) } } func (m *maker) ClientPKG(ctx context.Context, _os string, _version string, api string, opts ...ClientPKGOption) error { const ( Dockerfile = ` FROM hub.yizhisec.com/hsv2/base/nginx:latest RUN mkdir -p /data COPY version.json /data/version.json %s COPY nginx.conf /etc/nginx/nginx.conf ` ) if !lo.Contains([]string{"mac", "win", "linux"}, _os) { return fmt.Errorf("invalid os: %s", _os) } var ( o = &clientPKGOption{ Downloads: []*clientPKGDownload{}, CMDs: []string{}, } err error location = filepath.Join(m.workdir, "client", _os) _file string _content string ) for _, fn := range opts { fn(o) } logger.Info("☑️ maker.ClientPKG: start build client pkg, os = %s, version = %s, location = %s", _os, _version, location) if err = os.RemoveAll(location); err != nil { logger.Debug("❌ maker.ClientPKG: remove directory failed, directory = %s, err = %s", location, err.Error()) return err } if err = os.MkdirAll(location, 0755); err != nil { logger.Debug("❌ maker.ClientPKG: create directory failed, directory = %s, err = %s", location, err.Error()) return err } vd := map[string]string{ "version": _version, } vbs, _ := json.Marshal(vd) if err = os.WriteFile(filepath.Join(location, "version.txt"), []byte(_version), 0644); err != nil { logger.Debug("❌ maker.ClientPKG: write file failed, file = %s, err = %s", filepath.Join(location, "version.txt"), err.Error()) return err } if err = os.WriteFile(filepath.Join(location, "version.json"), []byte(vbs), 0644); err != nil { logger.Debug("❌ maker.ClientPKG: write file failed, file = %s, err = %s", filepath.Join(location, "version.json"), err.Error()) return err } _file = filepath.Join(location, "nginx.conf") _content = fmt.Sprintf(resource.NGINXClientPKG, api) logger.Debug("☑️ maker.ClientPKG: start write file = %s", _file) if os.WriteFile(_file, []byte(_content), 0644); err != nil { logger.Debug("❌ maker.ClientPKG: write file failed, file = %s, err = %s", _file, err.Error()) return err } logger.Debug("✅ maker.ClientPKG: write file success, file = %s", _file) lines := lo.Map(o.Downloads, func(d *clientPKGDownload, index int) string { return fmt.Sprintf("wget -O /data/%s %s", d.Name, d.URL) }) if len(o.CMDs) > 0 { lines = append(lines, o.CMDs...) } _file = filepath.Join(location, "Dockerfile") _content = fmt.Sprintf(Dockerfile, "RUN "+strings.Join(lines, " && ")) logger.Debug("☑️ maker.ClientPKG: start write file = %s", _file) if os.WriteFile(_file, []byte(_content), 0644); err != nil { logger.Debug("❌ maker.ClientPKG: write file failed, file = %s, err = %s", _file, err.Error()) return err } logger.Debug("✅ maker.ClientPKG: write file success, file = %s", _file) imgName := fmt.Sprintf("hub.yizhisec.com/hsv2/client/%s:%s", _os, _version) logger.Debug("☑️ maker.ClientPKG: build docker image, os = %s, version = %s, full_name = %s", _os, _version, imgName) _cmd := fmt.Sprintf("docker build --network host -t %s -f Dockerfile .", imgName) if err = m.RunCommand(ctx, location, _cmd); err != nil { logger.Debug("❌ maker.ClientPKG: run command failed, cmd = %s, err = %s", _cmd, err.Error()) return err } imgLocation := filepath.Join(location, _os+".tar") logger.Debug("☑️ maker.ClientPKG: save img to %s", imgLocation) _cmd = fmt.Sprintf("docker save hub.yizhisec.com/hsv2/client/%s:%s -o %s", _os, _version, imgLocation) if err = m.RunCommand(ctx, location, _cmd); err != nil { logger.Debug("❌ maker.ClientPKG: run command failed, cmd = %s, err = %s", _cmd, err.Error()) return err } imgNameInCluster := fmt.Sprintf("10.96.123.45:80/hsv2/client/%s:%s", _os, _version) deployment := filepath.Join(location, "deployment.yaml") _content = strings.ReplaceAll( fmt.Sprintf( resource.YAMLClientPKG, 1, // replica 先默认 1 就够了 imgNameInCluster, ), "__os__", _os, ) if err = os.WriteFile(deployment, []byte(_content), 0644); err != nil { logger.Debug("❌ maker.ClientPKG: write file failed, file = %s, err = %s", deployment, err.Error()) return err } if o.MakePkg { _cmd := fmt.Sprintf("7za a -pRrPt7Uo9WM1dkXOJmHps56T8BZY2qA4g -mhe=on client.%s.pkg *", _os) logger.Debug("☑️ maker.ClientPKG: start create client.%s.pkg by 7zip(7za), cmd = '%s'", _os, _cmd) if err = m.RunCommand(ctx, location, _cmd); err != nil { logger.Debug("❌ maker.ClientPKG: run command failed, cmd = %s, err = %s", _cmd, err.Error()) return err } } logger.Info("️✅ maker.ClientPKG: build client pkg success, os = %s, version = %s, location = %s", _os, _version, location) return nil }