Compare commits
10 Commits
62b680dca8
...
eb87d6fbed
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb87d6fbed | ||
|
|
0bcb138fd5 | ||
|
|
c53c15fa8c | ||
|
|
f4f3590aec | ||
|
|
3a29e6221d | ||
|
|
38def02bf4 | ||
|
|
fdad0eb36c | ||
|
|
11523e3e48 | ||
|
|
4ec58ce4e5 | ||
|
|
1d3c159c00 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,4 +3,5 @@ x-*
|
|||||||
dist
|
dist
|
||||||
.trae
|
.trae
|
||||||
.vscode
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
|
forge
|
||||||
47
AGENTS.md
47
AGENTS.md
@@ -1,47 +0,0 @@
|
|||||||
# AGENTS.md
|
|
||||||
|
|
||||||
This file provides guidance to Qoder (qoder.com) when working with code in this repository.
|
|
||||||
|
|
||||||
## Project Overview
|
|
||||||
|
|
||||||
This is a Go project (`yizhisec.com/hsv2/forge`) using Go 1.25.2.
|
|
||||||
|
|
||||||
## Development Commands
|
|
||||||
|
|
||||||
### Build
|
|
||||||
```bash
|
|
||||||
go build ./...
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run Tests
|
|
||||||
```bash
|
|
||||||
go test ./...
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run Single Test
|
|
||||||
```bash
|
|
||||||
go test -run TestName ./path/to/package
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lint
|
|
||||||
```bash
|
|
||||||
go vet ./...
|
|
||||||
```
|
|
||||||
|
|
||||||
### Format Code
|
|
||||||
```bash
|
|
||||||
go fmt ./...
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tidy Dependencies
|
|
||||||
```bash
|
|
||||||
go mod tidy
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
The codebase structure has not yet been established. As the project grows, update this section with:
|
|
||||||
- Main package organization
|
|
||||||
- Key architectural patterns
|
|
||||||
- Important design decisions
|
|
||||||
- Module relationships
|
|
||||||
3
helper/nginx-with-tool/Dockerfile
Normal file
3
helper/nginx-with-tool/Dockerfile
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
FROM docker-mirror.yizhisec.com/library/nginx:1.29.4-alpine3.23
|
||||||
|
|
||||||
|
RUN apk add curl wget tzdata unzip
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/cmd/installcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func installCmd() *cobra.Command {
|
func installCmd() *cobra.Command {
|
||||||
@@ -11,15 +10,12 @@ func installCmd() *cobra.Command {
|
|||||||
Use: "install",
|
Use: "install",
|
||||||
Short: "Install the project",
|
Short: "Install the project",
|
||||||
Long: `Install the built project to the specified location.`,
|
Long: `Install the built project to the specified location.`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
return runInstall(args)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cmd.AddCommand(
|
||||||
|
installcmd.Check(),
|
||||||
|
installcmd.Prepare(),
|
||||||
|
)
|
||||||
|
|
||||||
return _cmd
|
return _cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runInstall(args []string) error {
|
|
||||||
fmt.Println("Running install command...")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
39
internal/cmd/installcmd/check.go
Normal file
39
internal/cmd/installcmd/check.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package installcmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/installer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Check() *cobra.Command {
|
||||||
|
var (
|
||||||
|
workdir string
|
||||||
|
target string
|
||||||
|
ignoreDisk bool
|
||||||
|
ignoreMemory bool
|
||||||
|
ignoreCPU bool
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "check",
|
||||||
|
Short: "Check system requirements",
|
||||||
|
Long: `Check system requirements for the project.`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
_installer := installer.NewInstaller(workdir, target)
|
||||||
|
return _installer.Check(
|
||||||
|
cmd.Context(),
|
||||||
|
installer.WithIgnoreDiskCheck(ignoreDisk),
|
||||||
|
installer.WithIgnoreMemoryCheck(ignoreMemory),
|
||||||
|
installer.WithIgnoreCPUCheck(ignoreCPU),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().StringVar(&workdir, "workdir", "/root/hs-installation", "Working directory")
|
||||||
|
_cmd.Flags().StringVar(&target, "target", "self", "Target")
|
||||||
|
_cmd.Flags().BoolVar(&ignoreDisk, "ignore-check-disk", false, "ignore disk requirement check result")
|
||||||
|
_cmd.Flags().BoolVar(&ignoreMemory, "ignore-check-memory", false, "ignore memory requirement check result")
|
||||||
|
_cmd.Flags().BoolVar(&ignoreCPU, "ignore-check-cpu", false, "ignore cpu requirement check result")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
29
internal/cmd/installcmd/k0s.go
Normal file
29
internal/cmd/installcmd/k0s.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package installcmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/installer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func K0s() *cobra.Command {
|
||||||
|
|
||||||
|
var (
|
||||||
|
workdir string
|
||||||
|
target string
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "k0s",
|
||||||
|
Short: "Install k0s",
|
||||||
|
Long: "Install k0s",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
_installer := installer.NewInstaller(workdir, target)
|
||||||
|
return _installer.K0s(cmd.Context())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.PersistentFlags().StringVar(&workdir, "workdir", "/root/hs-installation", "working directory")
|
||||||
|
_cmd.PersistentFlags().StringVar(&target, "target", "self", "target directory")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
30
internal/cmd/installcmd/prepare.go
Normal file
30
internal/cmd/installcmd/prepare.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package installcmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/installer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Prepare() *cobra.Command {
|
||||||
|
|
||||||
|
var (
|
||||||
|
workdir string
|
||||||
|
target string
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "prepare",
|
||||||
|
Short: "Prepare for installation",
|
||||||
|
Long: "Prepare for installation",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
_installer := installer.NewInstaller(workdir, target)
|
||||||
|
_installer.Prepare(cmd.Context())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().StringVar(&workdir, "workdir", "/root/hs-installation", "Working directory")
|
||||||
|
_cmd.Flags().StringVar(&target, "target", "self", "Target")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
@@ -35,7 +35,7 @@ func makeCmd() *cobra.Command {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
if err = mk.DependencyCheck(cmd.Context()); err != nil {
|
if err = mk.DependencyCheck(cmd.Context()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -50,20 +50,25 @@ func makeCmd() *cobra.Command {
|
|||||||
_cmd.PersistentFlags().StringVar(&opt.Cfg.Make.Dir, "dir", "/root/hsv2-installation", "make base directory")
|
_cmd.PersistentFlags().StringVar(&opt.Cfg.Make.Dir, "dir", "/root/hsv2-installation", "make base directory")
|
||||||
|
|
||||||
_cmd.AddCommand(
|
_cmd.AddCommand(
|
||||||
|
makecmd.ALL(),
|
||||||
makecmd.Images(),
|
makecmd.Images(),
|
||||||
makecmd.Binaries(),
|
makecmd.K0s(),
|
||||||
makecmd.Debs(),
|
|
||||||
makecmd.Flannel(),
|
makecmd.Flannel(),
|
||||||
makecmd.Longhorn(),
|
makecmd.Longhorn(),
|
||||||
makecmd.Mysql(),
|
makecmd.Mysql(),
|
||||||
makecmd.Redis(),
|
makecmd.Redis(),
|
||||||
makecmd.ES(),
|
makecmd.ES(),
|
||||||
makecmd.EMQX(),
|
makecmd.EMQX(),
|
||||||
|
makecmd.Minio(),
|
||||||
makecmd.Yosguard(),
|
makecmd.Yosguard(),
|
||||||
|
makecmd.Registry(),
|
||||||
makecmd.LessDNS(),
|
makecmd.LessDNS(),
|
||||||
makecmd.HSNet(),
|
makecmd.HSNet(),
|
||||||
makecmd.ConfigMap(),
|
makecmd.ConfigMap(),
|
||||||
|
makecmd.Proxy(),
|
||||||
|
makecmd.Seafile(),
|
||||||
makecmd.App(),
|
makecmd.App(),
|
||||||
|
makecmd.Client(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return _cmd
|
return _cmd
|
||||||
|
|||||||
130
internal/cmd/makecmd/all.go
Normal file
130
internal/cmd/makecmd/all.go
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
package makecmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ALL() *cobra.Command {
|
||||||
|
var (
|
||||||
|
_workdir string
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "all",
|
||||||
|
Short: "Make all",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
mk = maker.NewMaker(_workdir)
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = mk.Images(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.K0s(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Registry(cmd.Context(), "50Gi"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Flannel(cmd.Context(), "host-gw"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Longhorn(cmd.Context(), 2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.MySQL(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Redis(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Elastic(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.EMQX(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Minio(cmd.Context(), "100Gi"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Yosguard(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.LessDNS(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.HSNet(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.ConfigMap(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Proxy(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Seafile(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Proxy(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.Seafile(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.AppOEM(cmd.Context(), "standard", 2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.AppUser(cmd.Context(), 2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.AppClient(cmd.Context(), 2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.AppGateway(cmd.Context(), 2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.AppFront(cmd.Context(), "standard", 2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.AppMie(cmd.Context(), 2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mk.AppNginx(cmd.Context()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.PersistentFlags().StringVar(&_workdir, "workdir", opt.DefaultWorkdir, "Work directory")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ package makecmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func App() *cobra.Command {
|
func App() *cobra.Command {
|
||||||
@@ -12,7 +14,158 @@ func App() *cobra.Command {
|
|||||||
|
|
||||||
_cmd.AddCommand(
|
_cmd.AddCommand(
|
||||||
appUser(),
|
appUser(),
|
||||||
|
appClient(),
|
||||||
|
appGateway(),
|
||||||
|
appMie(),
|
||||||
|
appOEM(),
|
||||||
|
appFront(),
|
||||||
|
appNginx(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return _cmd
|
return _cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appUser() *cobra.Command {
|
||||||
|
var (
|
||||||
|
replica int
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "user",
|
||||||
|
Short: "Make User App",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.AppUser(cmd.Context(), replica)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().IntVar(&replica, "replica-count", 2, "Replica count")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func appClient() *cobra.Command {
|
||||||
|
var (
|
||||||
|
replica int
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "client",
|
||||||
|
Short: "Make Client App",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.AppClient(cmd.Context(), replica)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().IntVar(&replica, "replica-count", 2, "Replica count")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func appGateway() *cobra.Command {
|
||||||
|
var (
|
||||||
|
replica int
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "gateway",
|
||||||
|
Short: "Make Gateway App",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.AppGateway(cmd.Context(), replica)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().IntVar(&replica, "replica-count", 2, "Replica count")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func appMie() *cobra.Command {
|
||||||
|
var (
|
||||||
|
replica int
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "mie",
|
||||||
|
Short: "Make Mie App",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.AppMie(cmd.Context(), replica)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().IntVar(&replica, "replica-count", 2, "Replica count")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func appOEM() *cobra.Command {
|
||||||
|
var (
|
||||||
|
replica int
|
||||||
|
vendor string
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "oem",
|
||||||
|
Short: "Make OEM App",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.AppOEM(cmd.Context(), vendor, replica)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().IntVar(&replica, "replica-count", 2, "Replica count")
|
||||||
|
_cmd.Flags().StringVar(&vendor, "vendor", "standard", "Vendor name")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func appFront() *cobra.Command {
|
||||||
|
var (
|
||||||
|
replica int
|
||||||
|
vendor string
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "front",
|
||||||
|
Short: "Make Front App",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.AppFront(cmd.Context(), vendor, replica)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().IntVar(&replica, "replica-count", 2, "Replica count")
|
||||||
|
_cmd.Flags().StringVar(&vendor, "vendor", "standard", "Vendor name")
|
||||||
|
|
||||||
|
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(opt.Cfg.Make.Dir)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
package makecmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
|
||||||
)
|
|
||||||
|
|
||||||
func appUser() *cobra.Command {
|
|
||||||
var (
|
|
||||||
replica int
|
|
||||||
)
|
|
||||||
|
|
||||||
_cmd := &cobra.Command{
|
|
||||||
Use: "user",
|
|
||||||
Short: "Make User App",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
mk := maker.NewMaker()
|
|
||||||
return mk.AppUser(cmd.Context(), replica)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
_cmd.Flags().IntVar(&replica, "replica-count", 2, "Replica count")
|
|
||||||
|
|
||||||
return _cmd
|
|
||||||
}
|
|
||||||
@@ -3,17 +3,16 @@ package makecmd
|
|||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Binaries() *cobra.Command {
|
func K0s() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "binaries",
|
Use: "k0s",
|
||||||
Aliases: []string{"bin", "B"},
|
Short: "make k0s files(binary, images)",
|
||||||
Short: "Build binary files",
|
|
||||||
Long: `Build all required binary files for the project.`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.Binary(cmd.Context())
|
return mk.K0s(cmd.Context())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
176
internal/cmd/makecmd/client.go
Normal file
176
internal/cmd/makecmd/client.go
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
package makecmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
|
tc "yizhisec.com/hsv2/forge/pkg/tool/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Client() *cobra.Command {
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "client",
|
||||||
|
Short: "make client pkg",
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.AddCommand(
|
||||||
|
clientMac(),
|
||||||
|
clientWin(),
|
||||||
|
clientLinux(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientMac() *cobra.Command {
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "mac",
|
||||||
|
Aliases: []string{"macos"},
|
||||||
|
Short: "make client-mac pkg",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
const (
|
||||||
|
DMG_URL = "https://artifactory.yizhisec.com/artifactory/yizhisec-release/hs_appleclient-csgElink/release/2.1.0-std/hybridscope-client-mac.dmg"
|
||||||
|
PKG_URL = "https://artifactory.yizhisec.com/artifactory/yizhisec-release/hs_appleclient-csgElink/release/2.1.0-std/hybridscope-client-mac.pkg"
|
||||||
|
VERSION_URL = "https://artifactory.yizhisec.com/artifactory/yizhisec-release/hs_appleclient/release/2.1.0-std/mac_version.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
version string
|
||||||
|
)
|
||||||
|
|
||||||
|
if version, err = clientVersion(VERSION_URL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.ClientPKG(
|
||||||
|
cmd.Context(),
|
||||||
|
"mac",
|
||||||
|
version,
|
||||||
|
"/api/v2_2/_client/mac",
|
||||||
|
maker.WithClientPKGDownload(DMG_URL, "hybridscope-client-mac.dmg"),
|
||||||
|
maker.WithClientPKGDownload(PKG_URL, "hybridscope-client-mac.pkg"),
|
||||||
|
maker.WithClientPKGDownload(VERSION_URL, "version.json"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientWin() *cobra.Command {
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "win",
|
||||||
|
Short: "make client-win pkg",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
const (
|
||||||
|
ZIP_URL = "https://artifactory.yizhisec.com/artifactory/yizhisec-release/hs_client-yizhianquan/release/2.1.0-std/hs_client.zip"
|
||||||
|
VERSION_URL = "https://artifactory.yizhisec.com/artifactory/yizhisec-release/hs_client-yizhianquan/release/2.1.0-std/windows_version.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
version string
|
||||||
|
)
|
||||||
|
|
||||||
|
if version, err = clientVersion(VERSION_URL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.ClientPKG(
|
||||||
|
cmd.Context(),
|
||||||
|
"win",
|
||||||
|
version,
|
||||||
|
"/api/v2_2/_client/win",
|
||||||
|
maker.WithClientPKGDownload(ZIP_URL, "hs_client.zip"),
|
||||||
|
maker.WithClientPKGDownload(VERSION_URL, "version.json"),
|
||||||
|
maker.WithClientPKGCMD("unzip /data/hs_client.zip"),
|
||||||
|
maker.WithClientPKGCMD("mv resources/app.7z /data/app.7z"),
|
||||||
|
maker.WithClientPKGCMD("mv resources/hybridscope_offline_installer.exe /data/hybridscope_offline_installer.exe"),
|
||||||
|
maker.WithClientPKGCMD("mv resources/hybridscope-client-setup-zh.exe /data/hybridscope-client-setup-zh.exe"),
|
||||||
|
maker.WithClientPKGCMD("mv resources/hybridscope-client-setup-en.exe /data/hybridscope-client-setup-en.exe"),
|
||||||
|
maker.WithClientPKGCMD("rm -rf /data/hs_client.zip"),
|
||||||
|
maker.WithClientPKGCMD("rm -rf resources"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientLinux() *cobra.Command {
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "linux",
|
||||||
|
Short: "make client-linux pkg",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
const (
|
||||||
|
DEB_URL = "https://artifactory.yizhisec.com/artifactory/yizhisec-release/universal-hsclient-linux/release/2.1.0/hscore-linux-2.1.0-csgElink-amd64.deb"
|
||||||
|
VERSION_URL = "https://artifactory.yizhisec.com/artifactory/yizhisec-release/universal-hsclient-linux/release/2.1.0/hscore-linux-2.1.0-std-amd64.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
version string
|
||||||
|
)
|
||||||
|
|
||||||
|
if version, err = clientVersion(VERSION_URL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.ClientPKG(
|
||||||
|
cmd.Context(),
|
||||||
|
"linux",
|
||||||
|
version,
|
||||||
|
"/api/v2_2/_client/linux",
|
||||||
|
maker.WithClientPKGDownload(DEB_URL, "hybridscope-client-linux.deb"),
|
||||||
|
maker.WithClientPKGDownload(VERSION_URL, "version.json"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientVersion(_url string) (string, error) {
|
||||||
|
type Res struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
rr *http.Response
|
||||||
|
res Res
|
||||||
|
bs []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Debug("clientVersion: getting client version with url = %s", _url)
|
||||||
|
if rr, err = tc.HttpClient().Get(_url); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer rr.Body.Close()
|
||||||
|
|
||||||
|
if bs, err = io.ReadAll(rr.Body); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("clientVersion: got client version body raw: %s, url = %s", string(bs), _url)
|
||||||
|
|
||||||
|
if err = json.Unmarshal(bs, &res); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Version == "" {
|
||||||
|
return "", fmt.Errorf("get version empty, url = %s", _url)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Version, nil
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package makecmd
|
|||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ConfigMap() *cobra.Command {
|
func ConfigMap() *cobra.Command {
|
||||||
@@ -11,7 +12,7 @@ func ConfigMap() *cobra.Command {
|
|||||||
Aliases: []string{"cm"},
|
Aliases: []string{"cm"},
|
||||||
Short: "构建 ConfigMap",
|
Short: "构建 ConfigMap",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.ConfigMap(cmd.Context())
|
return mk.ConfigMap(cmd.Context())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
package makecmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Debs() *cobra.Command {
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "debs",
|
|
||||||
Aliases: []string{"deb"},
|
|
||||||
Short: "Build Debian packages",
|
|
||||||
Long: `Build all required Debian packages for the project.`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
mk := maker.NewMaker()
|
|
||||||
return mk.Deb(cmd.Context())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ package makecmd
|
|||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func EMQX() *cobra.Command {
|
func EMQX() *cobra.Command {
|
||||||
@@ -10,7 +11,7 @@ func EMQX() *cobra.Command {
|
|||||||
Use: "emqx",
|
Use: "emqx",
|
||||||
Short: "Make EMQX",
|
Short: "Make EMQX",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.EMQX(cmd.Context())
|
return mk.EMQX(cmd.Context())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ES() *cobra.Command {
|
func ES() *cobra.Command {
|
||||||
@@ -18,7 +19,7 @@ func ES() *cobra.Command {
|
|||||||
Use: "es",
|
Use: "es",
|
||||||
Aliases: []string{"elastic", "elasticsearch"},
|
Aliases: []string{"elastic", "elasticsearch"},
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.Elastic(
|
return mk.Elastic(
|
||||||
cmd.Context(),
|
cmd.Context(),
|
||||||
maker.WithElasticMakeHelper(makeHelper),
|
maker.WithElasticMakeHelper(makeHelper),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package makecmd
|
|||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Flannel() *cobra.Command {
|
func Flannel() *cobra.Command {
|
||||||
@@ -15,7 +16,7 @@ func Flannel() *cobra.Command {
|
|||||||
Short: "Build Flannel resources",
|
Short: "Build Flannel resources",
|
||||||
Long: `Build and prepare Flannel network resources.`,
|
Long: `Build and prepare Flannel network resources.`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.Flannel(cmd.Context(), _mode)
|
return mk.Flannel(cmd.Context(), _mode)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package makecmd
|
|||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HSNet() *cobra.Command {
|
func HSNet() *cobra.Command {
|
||||||
@@ -11,7 +12,7 @@ func HSNet() *cobra.Command {
|
|||||||
Short: "Build hs-net",
|
Short: "Build hs-net",
|
||||||
Long: `Build hs-net`,
|
Long: `Build hs-net`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.HSNet(cmd.Context())
|
return mk.HSNet(cmd.Context())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func Images() *cobra.Command {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
|
||||||
return mk.Images(cmd.Context())
|
return mk.Images(cmd.Context())
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package makecmd
|
|||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LessDNS() *cobra.Command {
|
func LessDNS() *cobra.Command {
|
||||||
@@ -11,7 +12,7 @@ func LessDNS() *cobra.Command {
|
|||||||
Short: "Build lessdns",
|
Short: "Build lessdns",
|
||||||
Long: `Build lessdns`,
|
Long: `Build lessdns`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.LessDNS(cmd.Context())
|
return mk.LessDNS(cmd.Context())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package makecmd
|
|||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Longhorn() *cobra.Command {
|
func Longhorn() *cobra.Command {
|
||||||
@@ -15,7 +16,7 @@ func Longhorn() *cobra.Command {
|
|||||||
Short: "Build Longhorn resources",
|
Short: "Build Longhorn resources",
|
||||||
Long: `Build and prepare Longhorn storage resources.`,
|
Long: `Build and prepare Longhorn storage resources.`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.Longhorn(cmd.Context(), replicaCount)
|
return mk.Longhorn(cmd.Context(), replicaCount)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
28
internal/cmd/makecmd/minio.go
Normal file
28
internal/cmd/makecmd/minio.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package makecmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Minio() *cobra.Command {
|
||||||
|
var (
|
||||||
|
storage int
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "minio",
|
||||||
|
Short: "Make Minio",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.Minio(cmd.Context(), fmt.Sprintf("%dGi", storage))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().IntVar(&storage, "storage-size", 100, "Storage size(GB)")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Mysql() *cobra.Command {
|
func Mysql() *cobra.Command {
|
||||||
@@ -23,7 +24,7 @@ func Mysql() *cobra.Command {
|
|||||||
maker.WithMySQLStorage(fmt.Sprintf("%dGi", storage)),
|
maker.WithMySQLStorage(fmt.Sprintf("%dGi", storage)),
|
||||||
}
|
}
|
||||||
|
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.MySQL(cmd.Context(), opts...)
|
return mk.MySQL(cmd.Context(), opts...)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
20
internal/cmd/makecmd/proxy.go
Normal file
20
internal/cmd/makecmd/proxy.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package makecmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Proxy() *cobra.Command {
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "proxy",
|
||||||
|
Short: "Make Proxy(by caddy)",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.Proxy(cmd.Context())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
package makecmd
|
package makecmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Redis() *cobra.Command {
|
func Redis() *cobra.Command {
|
||||||
var (
|
var (
|
||||||
replicas int
|
replicas int
|
||||||
password string
|
password string
|
||||||
storage string
|
storage int
|
||||||
)
|
)
|
||||||
|
|
||||||
_cmd := &cobra.Command{
|
_cmd := &cobra.Command{
|
||||||
@@ -17,19 +20,19 @@ func Redis() *cobra.Command {
|
|||||||
Short: "Build Redis resources",
|
Short: "Build Redis resources",
|
||||||
Long: `Build and prepare Redis cache resources.`,
|
Long: `Build and prepare Redis cache resources.`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.Redis(
|
return mk.Redis(
|
||||||
cmd.Context(),
|
cmd.Context(),
|
||||||
maker.WithRedisReplicaCount(replicas),
|
maker.WithRedisReplicaCount(replicas),
|
||||||
maker.WithRedisPassword(password),
|
maker.WithRedisPassword(password),
|
||||||
maker.WithRedisStorage(storage),
|
maker.WithRedisStorage(fmt.Sprintf("%dGi")),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_cmd.Flags().IntVar(&replicas, "replica-count", 2, "Redis 副本数")
|
_cmd.Flags().IntVar(&replicas, "replica-count", 2, "Redis 副本数")
|
||||||
_cmd.Flags().StringVar(&password, "password", "", "Redis 密码")
|
_cmd.Flags().StringVar(&password, "password", "", "Redis 密码")
|
||||||
_cmd.Flags().StringVar(&storage, "storage-size", "5Gi", "Redis 存储大小(如: 5Gi)")
|
_cmd.Flags().IntVar(&storage, "storage-size", 5, "Redis 存储大小(单位Gi)如: 5")
|
||||||
|
|
||||||
return _cmd
|
return _cmd
|
||||||
}
|
}
|
||||||
|
|||||||
28
internal/cmd/makecmd/registry.go
Normal file
28
internal/cmd/makecmd/registry.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package makecmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Registry() *cobra.Command {
|
||||||
|
var (
|
||||||
|
size int
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "registry",
|
||||||
|
Short: "Make registry dependency",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.Registry(cmd.Context(), fmt.Sprintf("%dGi", size))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().IntVar(&size, "storage-size", 50, "Redis 存储大小(单位Gi)如: 100")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
27
internal/cmd/makecmd/seafile.go
Normal file
27
internal/cmd/makecmd/seafile.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package makecmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Seafile() *cobra.Command {
|
||||||
|
|
||||||
|
var (
|
||||||
|
storage int
|
||||||
|
)
|
||||||
|
|
||||||
|
_cmd := &cobra.Command{
|
||||||
|
Use: "seafile",
|
||||||
|
Short: "make seafile dependency",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
|
return mk.Seafile(cmd.Context())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd.Flags().IntVar(&storage, "storage-size", 50, "指定 seafile 空间大小(单位GB)")
|
||||||
|
|
||||||
|
return _cmd
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package makecmd
|
|||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
"yizhisec.com/hsv2/forge/internal/controller/maker"
|
||||||
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Yosguard() *cobra.Command {
|
func Yosguard() *cobra.Command {
|
||||||
@@ -11,7 +12,7 @@ func Yosguard() *cobra.Command {
|
|||||||
Aliases: []string{"YOS"},
|
Aliases: []string{"YOS"},
|
||||||
Short: "Make Yosguard",
|
Short: "Make Yosguard",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mk := maker.NewMaker()
|
mk := maker.NewMaker(opt.Cfg.Make.Dir)
|
||||||
return mk.Yosguard(cmd.Context())
|
return mk.Yosguard(cmd.Context())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
140
internal/controller/installer/installer.check.go
Normal file
140
internal/controller/installer/installer.check.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
package installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/syscheck"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CheckOption func(*checkOpt)
|
||||||
|
type checkOpt struct {
|
||||||
|
ignoreDisk bool
|
||||||
|
ignoreMemory bool
|
||||||
|
ignoreCPU bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithIgnoreDiskCheck(ignore bool) CheckOption {
|
||||||
|
return func(o *checkOpt) {
|
||||||
|
o.ignoreDisk = ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithIgnoreMemoryCheck(ignore bool) CheckOption {
|
||||||
|
return func(o *checkOpt) {
|
||||||
|
o.ignoreMemory = ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithIgnoreCPUCheck(ignore bool) CheckOption {
|
||||||
|
return func(o *checkOpt) {
|
||||||
|
o.ignoreCPU = ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *installer) Check(ctx context.Context, opts ...CheckOption) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
o = &checkOpt{}
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, fn := range opts {
|
||||||
|
fn(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("☑️ installer.Check: Starting system checks...")
|
||||||
|
|
||||||
|
if err = i.targetOK(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Check disk space: >= 500GB
|
||||||
|
logger.Info("☑️ installer.Check: Checking disk space...")
|
||||||
|
diskSpaceResult, err := syscheck.CheckDiskSpace(ctx, i, 500)
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("❌ installer.Check: Failed to check disk space: %v", err)
|
||||||
|
return fmt.Errorf("failed to check disk space: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !diskSpaceResult.Passed {
|
||||||
|
logger.Error("❌ %s: %s (Expected: %s, Actual: %s)", diskSpaceResult.Name, diskSpaceResult.Message, diskSpaceResult.Expected, diskSpaceResult.Actual)
|
||||||
|
if !o.ignoreDisk {
|
||||||
|
return fmt.Errorf("disk space check failed: %s", diskSpaceResult.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ %s: %s", diskSpaceResult.Name, diskSpaceResult.Actual)
|
||||||
|
|
||||||
|
// 2. Check disk performance: write >= 500MB/s, read >= 500MB/s
|
||||||
|
logger.Info("☑️ installer.Check: Checking disk performance...")
|
||||||
|
diskPerfResult, err := syscheck.CheckDiskPerformance(ctx, i, 500, 500)
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("❌ installer.Check: Failed to check disk performance: %v", err)
|
||||||
|
return fmt.Errorf("failed to check disk performance: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !diskPerfResult.Passed {
|
||||||
|
logger.Error("❌ %s: %s (Expected: %s, Actual: %s)", diskPerfResult.Name, diskPerfResult.Message, diskPerfResult.Expected, diskPerfResult.Actual)
|
||||||
|
if !o.ignoreDisk {
|
||||||
|
return fmt.Errorf("disk performance check failed: %s", diskPerfResult.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ %s: %s", diskPerfResult.Name, diskPerfResult.Actual)
|
||||||
|
|
||||||
|
// 3. Check memory size: >= 15.5GB
|
||||||
|
logger.Info("☑️ installer.Check: Checking memory size...")
|
||||||
|
memResult, err := syscheck.CheckMemory(ctx, i, 15.5)
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("❌ installer.Check: Failed to check memory: %v", err)
|
||||||
|
return fmt.Errorf("failed to check memory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !memResult.Passed {
|
||||||
|
logger.Error("❌ %s: %s (Expected: %s, Actual: %s)", memResult.Name, memResult.Message, memResult.Expected, memResult.Actual)
|
||||||
|
if !o.ignoreMemory {
|
||||||
|
return fmt.Errorf("memory check failed: %s", memResult.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ %s: %s", memResult.Name, memResult.Actual)
|
||||||
|
|
||||||
|
// 4. Check CPU cores: >= 8
|
||||||
|
logger.Info("☑️ installer.Check: Checking CPU cores...")
|
||||||
|
cpuCoresResult, err := syscheck.CheckCPUCores(ctx, i, 8)
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("❌ installer.Check: Failed to check CPU cores: %v", err)
|
||||||
|
return fmt.Errorf("failed to check CPU cores: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cpuCoresResult.Passed {
|
||||||
|
logger.Error("❌ %s: %s (Expected: %s, Actual: %s)", cpuCoresResult.Name, cpuCoresResult.Message, cpuCoresResult.Expected, cpuCoresResult.Actual)
|
||||||
|
if !o.ignoreCPU {
|
||||||
|
return fmt.Errorf("CPU cores check failed: %s", cpuCoresResult.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ %s: %s", cpuCoresResult.Name, cpuCoresResult.Actual)
|
||||||
|
|
||||||
|
// 5. Check CPU frequency: >= 2GHz
|
||||||
|
logger.Info("☑️ installer.Check: Checking CPU frequency...")
|
||||||
|
cpuFreqResult, err := syscheck.CheckCPUFrequency(ctx, i, 2.0)
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("❌ installer.Check: Failed to check CPU frequency: %v", err)
|
||||||
|
return fmt.Errorf("failed to check CPU frequency: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cpuFreqResult.Passed {
|
||||||
|
logger.Error("❌ %s: %s (Expected: %s, Actual: %s)", cpuFreqResult.Name, cpuFreqResult.Message, cpuFreqResult.Expected, cpuFreqResult.Actual)
|
||||||
|
if !o.ignoreCPU {
|
||||||
|
return fmt.Errorf("CPU frequency check failed: %s", cpuFreqResult.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ %s: %s", cpuFreqResult.Name, cpuFreqResult.Actual)
|
||||||
|
|
||||||
|
logger.Info("✅ installer.Check: All system checks passed successfully!")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,8 +1,153 @@
|
|||||||
package controller
|
package installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
)
|
||||||
|
|
||||||
type installer struct {
|
type installer struct {
|
||||||
|
workdir string
|
||||||
|
target string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInstaller() *installer {
|
func (i *installer) buildCommand(ctx context.Context, cmds ...string) *exec.Cmd {
|
||||||
return &installer{}
|
if len(cmds) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.target == "self" {
|
||||||
|
return exec.CommandContext(ctx, cmds[0], cmds[1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
sshArgs := append([]string{i.target}, cmds...)
|
||||||
|
return exec.CommandContext(ctx, "ssh", sshArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecuteCommand implements syscheck.CommandExecutor interface
|
||||||
|
func (i *installer) ExecuteCommand(ctx context.Context, cmds ...string) (string, error) {
|
||||||
|
cmd := i.buildCommand(ctx, cmds...)
|
||||||
|
if cmd == nil {
|
||||||
|
return "", fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("command failed: %w, output: %s", err, string(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type CopyFileOption func(*copyFileOptions)
|
||||||
|
type copyFileOptions struct {
|
||||||
|
addExecutable bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func withCopyFileExecutable() func(*copyFileOptions) {
|
||||||
|
return func(o *copyFileOptions) {
|
||||||
|
o.addExecutable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *installer) copyFile(ctx context.Context, src, dst string, opts ...CopyFileOption) error {
|
||||||
|
logger.Debug("☑️ installer.copyFile: Copying file from %s to %s (target: %s)", src, dst, i.target)
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
o = ©FileOptions{}
|
||||||
|
srcFile, dstFile *os.File
|
||||||
|
srcInfo os.FileInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, fn := range opts {
|
||||||
|
fn(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.target == "self" {
|
||||||
|
// Simply copy file locally
|
||||||
|
logger.Debug("Copying file locally: %s -> %s", src, dst)
|
||||||
|
|
||||||
|
// Open source file
|
||||||
|
if srcFile, err = os.Open(src); err != nil {
|
||||||
|
logger.Error("❌ Failed to open source file %s: %v", src, err)
|
||||||
|
return fmt.Errorf("failed to open source file: %w", err)
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
// Create destination directory if needed
|
||||||
|
dstDir := filepath.Dir(dst)
|
||||||
|
if err = os.MkdirAll(dstDir, 0755); err != nil {
|
||||||
|
logger.Error("❌ Failed to create destination directory %s: %v", dstDir, err)
|
||||||
|
return fmt.Errorf("failed to create destination directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create destination file
|
||||||
|
if dstFile, err = os.Create(dst); err != nil {
|
||||||
|
logger.Error("❌ Failed to create destination file %s: %v", dst, err)
|
||||||
|
return fmt.Errorf("failed to create destination file: %w", err)
|
||||||
|
}
|
||||||
|
defer dstFile.Close()
|
||||||
|
|
||||||
|
// Copy file content
|
||||||
|
if _, err = io.Copy(dstFile, srcFile); err != nil {
|
||||||
|
logger.Error("❌ Failed to copy file content: %v", err)
|
||||||
|
return fmt.Errorf("failed to copy file content: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get source file permissions
|
||||||
|
if srcInfo, err = os.Stat(src); err == nil {
|
||||||
|
if err = os.Chmod(dst, srcInfo.Mode()); err != nil {
|
||||||
|
logger.Debug("⚠️ Failed to set file permissions: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ File copied locally: %s -> %s", src, dst)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy file via scp to remote target
|
||||||
|
logger.Debug("Copying file via scp: %s -> %s:%s", src, i.target, dst)
|
||||||
|
|
||||||
|
// Format: scp <src> <target>:<dst>
|
||||||
|
cmd := exec.CommandContext(ctx, "scp", src, fmt.Sprintf("%s:%s", i.target, dst))
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("❌ Failed to copy file via scp: %v, output: %s", err, string(output))
|
||||||
|
return fmt.Errorf("failed to copy file via scp: %w, output: %s", err, string(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ File copied via scp: %s -> %s:%s", src, i.target, dst)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *installer) targetOK(ctx context.Context) error {
|
||||||
|
cmd := i.buildCommand(ctx, "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(workdir, target string) *installer {
|
||||||
|
if target == "" {
|
||||||
|
logger.Warn("🎯 NewInstaller: target empty, set to default(self)")
|
||||||
|
target = "self"
|
||||||
|
}
|
||||||
|
|
||||||
|
return &installer{workdir: workdir, target: target}
|
||||||
}
|
}
|
||||||
|
|||||||
123
internal/controller/installer/installer.k0s.go
Normal file
123
internal/controller/installer/installer.k0s.go
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type K0sOpt func(*k0sOpt)
|
||||||
|
type k0sOpt struct {
|
||||||
|
Type string // controller, worker
|
||||||
|
controllerAsWorker 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 WithK0sControllerAsWorker() K0sOpt {
|
||||||
|
return func(o *k0sOpt) {
|
||||||
|
o.controllerAsWorker = 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",
|
||||||
|
controllerAsWorker: false,
|
||||||
|
WorkerTokenFile: "/etc/k0s/worker.token",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = i.targetOK(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fn := range opts {
|
||||||
|
fn(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
binaries := []string{
|
||||||
|
"dependency/bin/k0s",
|
||||||
|
"dependency/bin/k9s", "dependency/bin/kubectl", "dependency/bin/helm"}
|
||||||
|
if err = i.checkFiles(binaries...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// check image tar files:
|
||||||
|
images := []string{
|
||||||
|
"dependency/image/k0s.apiserver-network-proxy-agent.tar",
|
||||||
|
"dependency/image/k0s.cni-node.tar",
|
||||||
|
"dependency/image/k0s.coredns.tar",
|
||||||
|
"dependency/image/k0s.kube-proxy.tar",
|
||||||
|
"dependency/image/k0s.kube-router.tar",
|
||||||
|
"dependency/image/k0s.metrics-server.tar",
|
||||||
|
"dependency/image/k0s.pause.tar",
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = i.checkFiles(images...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy binaries to /usr/local/bin and add executable permissions
|
||||||
|
if err = i.copyFile(ctx, "dependency/bin/k0s", "/usr/local/bin/k0s", withCopyFileExecutable()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = i.copyFile(ctx, "dependency/bin/k9s", "/usr/local/bin/k9s", withCopyFileExecutable()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = i.copyFile(ctx, "dependency/bin/kubectl", "/usr/local/bin/kubectl", withCopyFileExecutable()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = i.copyFile(ctx, "dependency/bin/helm", "/usr/local/bin/helm", withCopyFileExecutable()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
i.ExecuteCommand(ctx, "k0s", "")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkBinaryFiles checks if the required binary files exist in the dependency/bin directory
|
||||||
|
func (i *installer) checkFiles(fileBaseName ...string) error {
|
||||||
|
logger.Info("☑️ installer.checkFiles: Checking files in %s...", i.workdir)
|
||||||
|
|
||||||
|
for _, file := range fileBaseName {
|
||||||
|
filename := filepath.Join(i.workdir, file)
|
||||||
|
logger.Debug("Checking file: %s", filename)
|
||||||
|
|
||||||
|
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||||
|
logger.Error("❌ File not found: %s", filename)
|
||||||
|
return fmt.Errorf("file not found: %s", filename)
|
||||||
|
} else if err != nil {
|
||||||
|
logger.Error("❌ Failed to check file %s: %v", filename, err)
|
||||||
|
return fmt.Errorf("failed to check file %s: %w", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ File found: %s", file)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ installer.checkBinaryFiles: All binary files verified successfully!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
184
internal/controller/installer/installer.prepare.go
Normal file
184
internal/controller/installer/installer.prepare.go
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
package installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i *installer) Prepare(ctx context.Context) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Info("☑️ installer.Prepare: Starting system preparation...")
|
||||||
|
|
||||||
|
if err = i.targetOK(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Set timezone to Asia/Shanghai
|
||||||
|
logger.Info("☑️ installer.Prepare: Setting timezone to Asia/Shanghai...")
|
||||||
|
if err = i.setTimezone(ctx); err != nil {
|
||||||
|
logger.Debug("❌ installer.Prepare: Failed to set timezone: %v", err)
|
||||||
|
return fmt.Errorf("failed to set timezone: %w", err)
|
||||||
|
}
|
||||||
|
logger.Info("✅ installer.Prepare: Timezone set successfully")
|
||||||
|
|
||||||
|
// 2. Disable swap
|
||||||
|
logger.Info("☑️ installer.Prepare: Disabling swap...")
|
||||||
|
if err = i.disableSwap(ctx); err != nil {
|
||||||
|
logger.Debug("❌ installer.Prepare: Failed to disable swap: %v", err)
|
||||||
|
return fmt.Errorf("failed to disable swap: %w", err)
|
||||||
|
}
|
||||||
|
logger.Info("✅ installer.Prepare: Swap disabled successfully")
|
||||||
|
|
||||||
|
// 3. Load module: iscsi_tcp
|
||||||
|
logger.Info("☑️ installer.Prepare: Loading kernel module iscsi_tcp...")
|
||||||
|
if err = i.loadKernelModule(ctx, "iscsi_tcp"); err != nil {
|
||||||
|
logger.Debug("❌ installer.Prepare: Failed to load iscsi_tcp module: %v", err)
|
||||||
|
return fmt.Errorf("failed to load iscsi_tcp module: %w", err)
|
||||||
|
}
|
||||||
|
logger.Info("✅ installer.Prepare: iscsi_tcp module loaded successfully")
|
||||||
|
|
||||||
|
// 4. Load module: br_netfilter
|
||||||
|
logger.Info("☑️ installer.Prepare: Loading kernel module br_netfilter...")
|
||||||
|
if err = i.loadKernelModule(ctx, "br_netfilter"); err != nil {
|
||||||
|
logger.Debug("❌ installer.Prepare: Failed to load br_netfilter module: %v", err)
|
||||||
|
return fmt.Errorf("failed to load br_netfilter module: %w", err)
|
||||||
|
}
|
||||||
|
logger.Info("✅ installer.Prepare: br_netfilter module loaded successfully")
|
||||||
|
|
||||||
|
// 5. Apply sysctl settings
|
||||||
|
logger.Info("☑️ installer.Prepare: Applying sysctl settings...")
|
||||||
|
if err = i.applySysctlSettings(ctx); err != nil {
|
||||||
|
logger.Debug("❌ installer.Prepare: Failed to apply sysctl settings: %v", err)
|
||||||
|
return fmt.Errorf("failed to apply sysctl settings: %w", err)
|
||||||
|
}
|
||||||
|
logger.Info("✅ installer.Prepare: Sysctl settings applied successfully")
|
||||||
|
|
||||||
|
logger.Info("✅ installer.Prepare: System preparation completed successfully!")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setTimezone sets the system timezone to Asia/Shanghai
|
||||||
|
func (i *installer) setTimezone(ctx context.Context) error {
|
||||||
|
// Check if timezone file exists
|
||||||
|
cmd := i.buildCommand(ctx, "test", "-f", "/usr/share/zoneinfo/Asia/Shanghai")
|
||||||
|
if cmd == nil {
|
||||||
|
return fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("timezone file /usr/share/zoneinfo/Asia/Shanghai not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove old localtime link/file
|
||||||
|
cmd = i.buildCommand(ctx, "rm", "-f", "/etc/localtime")
|
||||||
|
if cmd == nil {
|
||||||
|
return fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
logger.Debug("Failed to remove /etc/localtime: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create symlink
|
||||||
|
cmd = i.buildCommand(ctx, "ln", "-s", "/usr/share/zoneinfo/Asia/Shanghai", "/etc/localtime")
|
||||||
|
if cmd == nil {
|
||||||
|
return fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("failed to create symlink: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// disableSwap disables all swap partitions and removes swap entries from /etc/fstab
|
||||||
|
func (i *installer) disableSwap(ctx context.Context) error {
|
||||||
|
// Turn off all swap
|
||||||
|
cmd := i.buildCommand(ctx, "swapoff", "-a")
|
||||||
|
if cmd == nil {
|
||||||
|
return fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
logger.Debug("Failed to swapoff: %v (may be already off)", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comment out swap entries in /etc/fstab to make it persistent
|
||||||
|
cmd = i.buildCommand(ctx, "sed", "-i", "/swap/s/^/#/", "/etc/fstab")
|
||||||
|
if cmd == nil {
|
||||||
|
return fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
logger.Debug("Failed to comment swap in /etc/fstab: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadKernelModule loads a kernel module and ensures it's loaded on boot
|
||||||
|
func (i *installer) loadKernelModule(ctx context.Context, moduleName string) error {
|
||||||
|
// Load the module immediately
|
||||||
|
cmd := i.buildCommand(ctx, "modprobe", moduleName)
|
||||||
|
if cmd == nil {
|
||||||
|
return fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("failed to load module %s: %w", moduleName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to /etc/modules-load.d/ to load on boot
|
||||||
|
filePath := fmt.Sprintf("/etc/modules-load.d/%s.conf", moduleName)
|
||||||
|
cmd = i.buildCommand(ctx, "bash", "-c", fmt.Sprintf("echo '%s' > %s", moduleName, filePath))
|
||||||
|
if cmd == nil {
|
||||||
|
return fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
logger.Debug("Failed to add module to modules-load.d: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// applySysctlSettings applies required sysctl settings for Kubernetes
|
||||||
|
func (i *installer) applySysctlSettings(ctx context.Context) error {
|
||||||
|
const sysctlConfig = `# Kubernetes required settings
|
||||||
|
net.bridge.bridge-nf-call-iptables = 1
|
||||||
|
net.bridge.bridge-nf-call-ip6tables = 1
|
||||||
|
net.ipv4.ip_forward = 1
|
||||||
|
net.ipv4.conf.all.forwarding = 1
|
||||||
|
net.ipv6.conf.all.forwarding = 1
|
||||||
|
vm.swappiness = 0
|
||||||
|
vm.overcommit_memory = 1
|
||||||
|
vm.panic_on_oom = 0
|
||||||
|
fs.file-max = 1000000
|
||||||
|
fs.inotify.max_user_watches = 2099999999
|
||||||
|
fs.inotify.max_user_instances = 2099999999
|
||||||
|
fs.inotify.max_queued_events = 2099999999
|
||||||
|
net.ipv4.neigh.default.gc_thresh1 = 1024
|
||||||
|
net.ipv4.neigh.default.gc_thresh2 = 4096
|
||||||
|
net.ipv4.neigh.default.gc_thresh3 = 8192
|
||||||
|
`
|
||||||
|
|
||||||
|
// Write sysctl config file
|
||||||
|
cmd := i.buildCommand(ctx, "bash", "-c", fmt.Sprintf("cat > /etc/sysctl.d/99-kubernetes.conf << 'EOF'\n%sEOF", sysctlConfig))
|
||||||
|
if cmd == nil {
|
||||||
|
return fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("failed to write sysctl config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply sysctl settings
|
||||||
|
cmd = i.buildCommand(ctx, "sysctl", "--system")
|
||||||
|
if cmd == nil {
|
||||||
|
return fmt.Errorf("failed to build command")
|
||||||
|
}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("failed to apply sysctl settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
5
internal/controller/installer/installer.redis.go
Normal file
5
internal/controller/installer/installer.redis.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package installer
|
||||||
|
|
||||||
|
func (i *installer) Redis() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
7
internal/controller/installer/installer.yosguard.go
Normal file
7
internal/controller/installer/installer.yosguard.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package installer
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
func (i *installer) YosGuard(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
245
internal/controller/maker/app.client.go
Normal file
245
internal/controller/maker/app.client.go
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *maker) AppClient(ctx context.Context, replica int) error {
|
||||||
|
const (
|
||||||
|
_config = `Version: "3"
|
||||||
|
APNs: /yizhisec/hs_nginx/data/443/oem/data.json
|
||||||
|
BackupSeafile:
|
||||||
|
Host: hs-resource-server
|
||||||
|
Port: 19980
|
||||||
|
ClientDir:
|
||||||
|
CompatibleAppFile: /yizhisec/hs_nginx/resource/compatible_apps.csv
|
||||||
|
OEMFilePath: /yizhisec/hs_nginx/data/443/oem/data.json
|
||||||
|
StorageDir: /data/storage/client_pkg
|
||||||
|
WindowsClient:
|
||||||
|
App7zDir: app7z_0
|
||||||
|
Dir: windows
|
||||||
|
Database:
|
||||||
|
Elastic:
|
||||||
|
Address: http://es-service.db-es:9200
|
||||||
|
IPDBFile: /etc/client_server/ipv4.ipdb
|
||||||
|
Mysql:
|
||||||
|
Address: mysql.db-mysql:3306
|
||||||
|
DBName: mie
|
||||||
|
Password: L0hMysql.
|
||||||
|
UserName: root
|
||||||
|
Redis:
|
||||||
|
Address: redis-master.db-redis:6379
|
||||||
|
Password: HybridScope0xRed1s.
|
||||||
|
DisabledFeatureFilePath: /etc/yizhisec/disabled_features
|
||||||
|
ExportWithBlindWatermark: 1
|
||||||
|
ExternalOA:
|
||||||
|
Host: ""
|
||||||
|
Port: 0
|
||||||
|
ExternalOASecret:
|
||||||
|
HsID: ""
|
||||||
|
HsSecret: ""
|
||||||
|
GatewayLinkPort: 23209
|
||||||
|
Key:
|
||||||
|
Token: TtKVnSzEHO3jRv/GWg3f5k3H1OVfMnPZ1Ke9E6MSCXk=
|
||||||
|
LicensePubKey: /etc/yizhisec/license/pub_key
|
||||||
|
Log:
|
||||||
|
Dir: ./log
|
||||||
|
Level: 1
|
||||||
|
Name: client_server
|
||||||
|
MQTTServer:
|
||||||
|
Host: emqx-service.db-emqx
|
||||||
|
Port: 1883
|
||||||
|
NginxEnvFilePath: /yizhisec/hs_nginx/.env
|
||||||
|
Pipelines:
|
||||||
|
- processor:
|
||||||
|
Script: diA9IGpzb24uZGVjb2RlKGV2ZW50KQpjID0ganNvbi5kZWNvZGUoR2V0UmVzb3VyY2VDb25maWcoImNvbnRyb2xsZXIiKSkKY3B1dCA9IGNbImhhcmR3YXJlX3Jlc291cmNlX3RocmVob2xkIl1bImNwdSJdCm1lbXQgPSBjWyJoYXJkd2FyZV9yZXNvdXJjZV90aHJlaG9sZCJdWyJtZW1vcnkiXQpkaXNrdCA9IGNbImhhcmR3YXJlX3Jlc291cmNlX3RocmVob2xkIl1bImRpc2siXQpzd2l0Y2ggPSBjWyJzd2l0Y2giXQpkZWJ1Z19pbmZvID0ge30KZGVmIGNoZWNrKGNwdSwgbWVtb3J5LCBkaXNrKToKICBpZiBzd2l0Y2ggPT0gRmFsc2U6CiAgICByZXR1cm4KICBtc2cgPSAiIgogIGV2dCA9IHt9CiAgaWYgY3B1ID4gY3B1dDoKICAgICAgbXNnID0gIkNQVeWNoOeUqOi2hei/hyIgKyBzdHIoY3B1dCkgKyAiJSIKICBpZiBtZW1vcnkgPiBtZW10OgogICAgaWYgbGVuKG1zZykgIT0gMDoKICAgICAgbXNnID0gbXNnICsgIu+8jCAiCiAgICBtc2cgPSBtc2cgKyAi5YaF5a2Y5Y2g55So6LaF6L+HIiArIHN0cihtZW10KSArICIlIgogIGlmIGRpc2sgPiBkaXNrdDoKICAgIGlmIGxlbihtc2cpICE9IDA6CiAgICAgIG1zZyA9IG1zZyArICLvvIwgIgogICAgbXNnID0gbXNnICsgIuejgeebmOWNoOeUqOi2hei/hyIgKyBzdHIoZGlza3QpICsgIiUiCiAgaWYgbGVuKG1zZykgIT0gMDoKICAgIG1zZyA9IG1zZyArICLjgILor7flj4rml7bmn6XnnIvmnI3liqHlmajnmoTkvb/nlKjmg4XlhrXmiJbph43mlrDosIPmlbTpmIjlgLzjgIIiCiAgaWYgbGVuKG1zZykgPT0gMDoKICAgIHJldHVybiBldnQKICBpZ25vcmUgPSBDb21wYXJlQW5kU2V0KCJfcGlwZWxpbmVfbHN0X2N0IiwgR2V0VGltZVNlYygpLCA2MCo2MCkKICBpZiBpZ25vcmUgPT0gMDoKICAgIGRlYnVnX2luZm9bImluZm8iXSA9ICJyYXRlIGxpbWl0IGlnbm9yZSIKICAgIHJldHVybgogIG1zZyA9ICLnrZbnlaXmjqfliLblmajnmoQiICsgbXNnCiAgZXZ0WyJkZXRhaWwiXSA9IG1zZwogIGV2dFsiZG9tYWluX2lkIl0gPSAwCiAgZXZ0WyJtZXNzYWdlX3R5cGUiXSA9IDEwMQogIGV2dFsiY3JlYXRlX3RpbWUiXSA9IEdldFRpbWVTZWMoKQogIHJldHVybiBldnQKCm91dHB1dCA9IGpzb24uZW5jb2RlKGNoZWNrKHZbImNwdSJdWyJwZXJjZW50Il0sIHZbIm1lbSJdWyJwZXJjZW50Il0sIHZbImRpc2siXVsicGVyY2VudCJdKSk=
|
||||||
|
Type: starlark
|
||||||
|
sink:
|
||||||
|
Cols:
|
||||||
|
- create_time
|
||||||
|
- detail
|
||||||
|
- domain_id
|
||||||
|
- message_type
|
||||||
|
DB: mie
|
||||||
|
Host: mysql.db-mysql:3306
|
||||||
|
Pwd: L0hMysql.
|
||||||
|
Table: message_content
|
||||||
|
Type: mysql_sink
|
||||||
|
User: root
|
||||||
|
source:
|
||||||
|
Host: redis-master.db-redis:6379
|
||||||
|
Key: evt_server_state:controller
|
||||||
|
Pwd: HybridScope0xRed1s.
|
||||||
|
Tick: 3
|
||||||
|
Type: redis_source
|
||||||
|
- processor:
|
||||||
|
Script: diA9IGpzb24uZGVjb2RlKGV2ZW50KQpjID0ganNvbi5kZWNvZGUoR2V0UmVzb3VyY2VDb25maWcoImdhdGV3YXkiKSkKY3B1dCA9IGNbImhhcmR3YXJlX3Jlc291cmNlX3RocmVob2xkIl1bImNwdSJdCm1lbXQgPSBjWyJoYXJkd2FyZV9yZXNvdXJjZV90aHJlaG9sZCJdWyJtZW1vcnkiXQpkaXNrdCA9IGNbImhhcmR3YXJlX3Jlc291cmNlX3RocmVob2xkIl1bImRpc2siXQpzd2l0Y2ggPSBjWyJzd2l0Y2giXQpkZWJ1Z19pbmZvID0ge30KZGVmIGNoZWNrKCk6CiAgaWYgc3dpdGNoID09IEZhbHNlOgogICAgcmV0dXJuCiAga3MgPSB2LmtleXMoKQogIGlmIGxlbihrcykgPiAwOgogICAgayA9IGtzWzBdCiAgY3B1ID0gdltrXVsiY3B1Il0KICBtZW0gPSB2W2tdWyJtZW0iXQogIGRpc2sgPSB2W2tdWyJkaXNrIl0KICBtc2cgPSAiIgogIGV2dCA9IHt9CiAgaWYgY3B1ID4gY3B1dDoKICAgICAgbXNnID0gIkNQVeWNoOeUqOi2hei/hyIgKyBzdHIoY3B1dCkgKyAiJSIKICBpZiBtZW0gPiBtZW10OgogICAgaWYgbGVuKG1zZykgIT0gMDoKICAgICAgbXNnID0gbXNnICsgIu+8jCAiCiAgICBtc2cgPSBtc2cgKyAi5YaF5a2Y5Y2g55So6LaF6L+HIiArIHN0cihtZW10KSArICIlIgogIGlmIGRpc2sgPiBkaXNrdDoKICAgIGlmIGxlbihtc2cpICE9IDA6CiAgICAgIG1zZyA9IG1zZyArICLvvIwgIgogICAgbXNnID0gbXNnICsgIuejgeebmOWNoOeUqOi2hei/hyIgKyBzdHIoZGlza3QpICsgIiUiCiAgaWYgbGVuKG1zZykgIT0gMDoKICAgIG1zZyA9IG1zZyArICLjgILor7flj4rml7bmn6XnnIvmnI3liqHlmajnmoTkvb/nlKjmg4XlhrXmiJbph43mlrDosIPmlbTpmIjlgLzjgIIiCiAgaWYgbGVuKG1zZykgPT0gMDoKICAgIHJldHVybiBldnQKICBpZ25vcmUgPSBDb21wYXJlQW5kU2V0KCJfcGlwZWxpbmVfbHN0X2d0IiwgR2V0VGltZVNlYygpLCA2MCo2MCkKICBpZiBpZ25vcmUgPT0gMDoKICAgIGRlYnVnX2luZm9bImluZm8iXSA9ICJyYXRlIGxpbWl0IGlnbm9yZSIKICAgIHJldHVybgogIG1zZyA9ICLnvZHlhbPnmoQiICsgbXNnCiAgZXZ0WyJkZXRhaWwiXSA9IG1zZwogIGV2dFsiZG9tYWluX2lkIl0gPSAwCiAgZXZ0WyJtZXNzYWdlX3R5cGUiXSA9IDEwMgogIGV2dFsiY3JlYXRlX3RpbWUiXSA9IEdldFRpbWVTZWMoKQogIHJldHVybiBldnQKCm91dHB1dCA9IGpzb24uZW5jb2RlKGNoZWNrKCkp
|
||||||
|
Type: starlark
|
||||||
|
sink:
|
||||||
|
Cols:
|
||||||
|
- create_time
|
||||||
|
- detail
|
||||||
|
- domain_id
|
||||||
|
- message_type
|
||||||
|
DB: mie
|
||||||
|
Host: mysql.db-mysql:3306
|
||||||
|
Pwd: L0hMysql.
|
||||||
|
Table: message_content
|
||||||
|
Type: mysql_sink
|
||||||
|
User: root
|
||||||
|
source:
|
||||||
|
Host: redis-master.db-redis:6379
|
||||||
|
Key: evt_server_state:gateway
|
||||||
|
Pwd: HybridScope0xRed1s.
|
||||||
|
Tick: 3
|
||||||
|
Type: redis_source
|
||||||
|
- processor:
|
||||||
|
Script: diA9IGpzb24uZGVjb2RlKGV2ZW50KQpjID0ganNvbi5kZWNvZGUoR2V0TGljZW5zZUNvbmZpZygibGljZW5zZSIpKQpsZWZ0ID0gY1sibGljZW5zZV90aHJlaG9sZCJdWyJyZW1haW5pbmdfZGF5Il0Kc3dpdGNoID0gY1sic3dpdGNoIl0KZGVidWdfaW5mbyA9IHt9CmRlZiBjaGVjaygpOgogIGlmIHN3aXRjaCA9PSBGYWxzZToKICAgIHJldHVybgogIAogIGV0ID0gdlsiZXhwaXJlX3RpbWUiXQogIGV2dCA9IHt9CiAgY3VyID0gR2V0VGltZVNlYygpCiAgaWYgZXQgPCAoY3VyICsgbGVmdCAqIDg2NDAwKToKICAgIGlnbm9yZSA9IENvbXBhcmVBbmRTZXQoIl9waXBlbGluZV9sc3RfbCIsIEdldFRpbWVTZWMoKSwgNjAqNjAqMjQpCiAgICBpZiBpZ25vcmUgPT0gMDoKICAgICAgZGVidWdfaW5mb1siaW5mbyJdID0gInJhdGUgbGltaXQgaWdub3JlIgogICAgICByZXR1cm4KICAgIGV2dFsiZGV0YWlsIl0gPSAi5Lqn5ZOB5o6I5p2D5Ymp5L2Z5aSp5pWw5bCP5LqOIiArIHN0cihsZWZ0KSArICLlpKnjgILor7flj4rml7bmn6XnnIvkvb/nlKjmg4XlhrXjgIHph43mlrDosIPmlbTpmIjlgLzmiJbogZTns7vnrqHnkIblkZjmt7vliqDmjojmnYPjgIIiCiAgICBldnRbImRvbWFpbl9pZCJdID0gMAogICAgZXZ0WyJtZXNzYWdlX3R5cGUiXSA9IDIwMgogICAgZXZ0WyJjcmVhdGVfdGltZSJdID0gR2V0VGltZVNlYygpCiAgICByZXR1cm4gZXZ0Cm91dHB1dCA9IGpzb24uZW5jb2RlKGNoZWNrKCkp
|
||||||
|
Type: starlark
|
||||||
|
sink:
|
||||||
|
Cols:
|
||||||
|
- create_time
|
||||||
|
- detail
|
||||||
|
- domain_id
|
||||||
|
- message_type
|
||||||
|
DB: mie
|
||||||
|
Host: mysql.db-mysql:3306
|
||||||
|
Pwd: L0hMysql.
|
||||||
|
Table: message_content
|
||||||
|
Type: mysql_sink
|
||||||
|
User: root
|
||||||
|
source:
|
||||||
|
Host: redis-master.db-redis:6379
|
||||||
|
Key: license_state_cache:expire
|
||||||
|
Pwd: HybridScope0xRed1s.
|
||||||
|
Tick: 3
|
||||||
|
Type: redis_source
|
||||||
|
- processor:
|
||||||
|
Script: diA9IGpzb24uZGVjb2RlKGV2ZW50KQpjID0ganNvbi5kZWNvZGUoR2V0TGljZW5zZUNvbmZpZygibGljZW5zZV9kZXZpY2UiKSkKY2wgPSBjWyJsaWNlbnNlX2RldmljZV90aHJlaG9sZCJdWyJjbGllbnRfbGVmdCJdCm1sID0gY1sibGljZW5zZV9kZXZpY2VfdGhyZWhvbGQiXVsibW9iaWxlX2xlZnQiXQptYyA9IHZbIm1heF9jbGllbnRfY291bnQiXQptYiA9IHZbIm1heF9tb2JpbGVfY2xpZW50X2NvdW50Il0KY2MgPSB2WyJjdXJyZW50X2NsaWVudF9jb3VudCJdCmNtID0gdlsiY3VycmVudF9tb2JpbGVfY2xpZW50X2NvdW50Il0Kc3dpdGNoID0gY1sic3dpdGNoIl0KZGVidWdfaW5mbyA9IHt9CmRlZiBjaGVjaygpOgogIGlmIHN3aXRjaCA9PSBGYWxzZToKICAgIHJldHVybgogIGV2dCA9IHt9CiAgbXNnID0gIiIKICBpZiAobWMtY2MpIDwgY2w6CiAgICBtc2cgPSBtc2cgKyAi5a6i5oi356uv5L2/55So5pWw6YeP5bCR5LqOIitzdHIoY2wpKyLkuKoiCiAgaWYgbGVuKG1zZykgPiAwOgogICAgbXNnID0gbXNnICsgIu+8jCIKICBpZiAobWItY20pIDwgbWw6CiAgICBtc2cgPSBtc2cgKyAi56e75Yqo56uv5L2/55So5pWw6YeP5bCR5LqOIitzdHIobWwpKyLkuKrjgIIiCiAgaWYgbGVuKG1zZykgPiAwOgogICAgaWdub3JlID0gQ29tcGFyZUFuZFNldCgiX3BpcGVsaW5lX2xzdF9sZCIsIEdldFRpbWVTZWMoKSwgNjAqNjApCiAgICBpZiBpZ25vcmUgPT0gMDoKICAgICAgZGVidWdfaW5mb1siaW5mbyJdID0gInJhdGUgbGltaXQgaWdub3JlIgogICAgICByZXR1cm4KICAgIGV2dFsiZGV0YWlsIl0gPSBtc2cgKyAi6K+35Y+K5pe25p+l55yL5L2/55So5oOF5Ya144CB6YeN5paw6LCD5pW06ZiI5YC85oiW6IGU57O7566h55CG5ZGY5re75Yqg5o6I5p2D44CCIgogICAgZXZ0WyJkb21haW5faWQiXSA9IDAKICAgIGV2dFsibWVzc2FnZV90eXBlIl0gPSAyMDIKICAgIGV2dFsiY3JlYXRlX3RpbWUiXSA9IEdldFRpbWVTZWMoKQogICAgcmV0dXJuIGV2dApvdXRwdXQgPSBqc29uLmVuY29kZShjaGVjaygpKQ==
|
||||||
|
Type: starlark
|
||||||
|
sink:
|
||||||
|
Cols:
|
||||||
|
- create_time
|
||||||
|
- detail
|
||||||
|
- domain_id
|
||||||
|
- message_type
|
||||||
|
DB: mie
|
||||||
|
Host: mysql.db-mysql:3306
|
||||||
|
Pwd: L0hMysql.
|
||||||
|
Table: message_content
|
||||||
|
Type: mysql_sink
|
||||||
|
User: root
|
||||||
|
source:
|
||||||
|
Host: redis-master.db-redis:6379
|
||||||
|
Key: license_state_cache:online
|
||||||
|
Pwd: HybridScope0xRed1s.
|
||||||
|
Tick: 3
|
||||||
|
Type: redis_source
|
||||||
|
- processor:
|
||||||
|
Script: diA9IGpzb24uZGVjb2RlKGV2ZW50KQpkZWJ1Z19pbmZvID0ge30KZGVmIGNoZWNrKCk6CiAgZXZ0ID0ge30KICBtc2cgPSAiIgogIAogIGRpZCA9IHZbImRvbWFpbl9pZCJdCiAgdWlkID0gdlsidXNlcl9pZCJdCiAgdW5hbWUgPSBHZXRVc2VyTmFtZSh1aWQpCiAgbGltaXQgPSB2WyJsaW1pdCJdCiAgcmFuZ2UgPSB2WyJyYW5nZSJdCiAgcnUgPSB2WyJyYW5nZV91bml0Il0KICBzdSA9IHZbInNpemVfdW5pdCJdCiAgZSA9IHZbImV2dCJdCiAgaWYgZSA9PSAiY291bnQiOgogICAgZXZ0WyJtZXNzYWdlX3R5cGUiXSA9IDMwMQogICAgdW5pdCA9IHN0cihyYW5nZSkKICAgIGlmIHJ1ID09ICJIIiBvciBydSA9PSAiaCI6CiAgICAgICAgdW5pdCA9IHVuaXQgKyAi5bCP5pe2IgogICAgaWYgcnUgPT0gIkQiIG9yIHJ1ID09ICJkIjoKICAgICAgICB1bml0ID0gdW5pdCArICLlpKkiCiAgICBtc2cgPSAi5ZyoIiArIHVuaXQgKyAi5YaF77yMIiArIHVuYW1lICsgIueahOWfn+WGheaWh+S7tuWvvOWHuuaVsOmHj+i2hei/hyIgKyBzdHIobGltaXQpICsgIuS4qu+8jCIKICBpZiBlID09ICJzaXplIjoKICAgIGV2dFsibWVzc2FnZV90eXBlIl0gPSAzMDIKICAgIHVuaXQgPSBzdHIocmFuZ2UpCiAgICBpZiBydSA9PSAiSCIgb3IgcnUgPT0gImgiOgogICAgICAgIHVuaXQgPSB1bml0ICsgIuWwj+aXtiIKICAgIGlmIHJ1ID09ICJEIiBvciBydSA9PSAiZCI6CiAgICAgICAgdW5pdCA9IHVuaXQgKyAi5aSpIgogICAgbXNnID0gIuWcqCIgKyB1bml0ICsgIuWGhe+8jCIgKyB1bmFtZSArICLnmoTln5/lhoXmlofku7blr7zlh7rlpKflsI/otoXov4ciICsgc3RyKGxpbWl0KQogICAgaWYgc3UgPT0gIk0iIG9yIHN1ID09ICJtIjoKICAgICAgICBtc2cgPSBtc2cgKyAiTULvvIwiCiAgICBpZiBzdSA9PSAiRyIgb3Igc3UgPT0gImciOgogICAgICAgIG1zZyA9IG1zZyArICJHQu+8jCIKICAgIGlmIHN1ID09ICJUIiBvciBzdSA9PSAidCI6CiAgICAgICAgbXNnID0gbXNnICsgIlRC77yMIgoKICBpZiBsZW4obXNnKSA+IDA6CiAgICBldnRbImRldGFpbCJdID0gbXNnICsgIuivt+WPiuaXtui3n+i4quWvvOWHuuaWh+S7tueahOaVj+aEn+eoi+W6puaIlumHjeaWsOiwg+aVtOmYiOWAvOOAgiIKICAgIGV2dFsiZG9tYWluX2lkIl0gPSBkaWQKICAgIGV2dFsiY3JlYXRlX3RpbWUiXSA9IEdldFRpbWVTZWMoKQogICAgcmV0dXJuIGV2dApvdXRwdXQgPSBqc29uLmVuY29kZShjaGVjaygpKQ==
|
||||||
|
Type: starlark
|
||||||
|
sink:
|
||||||
|
Cols:
|
||||||
|
- create_time
|
||||||
|
- detail
|
||||||
|
- domain_id
|
||||||
|
- message_type
|
||||||
|
DB: mie
|
||||||
|
Host: mysql.db-mysql:3306
|
||||||
|
Pwd: L0hMysql.
|
||||||
|
Table: message_content
|
||||||
|
Type: mysql_sink
|
||||||
|
User: root
|
||||||
|
source:
|
||||||
|
DB: mie
|
||||||
|
Host: mysql.db-mysql:3306
|
||||||
|
Pwd: L0hMysql.
|
||||||
|
Table: evt_export_file_over
|
||||||
|
Type: mysql_source
|
||||||
|
User: root
|
||||||
|
Sentry:
|
||||||
|
TracesSampleRate: 1
|
||||||
|
StaticURLPathPrefix:
|
||||||
|
NetworkAppIcon: /user/avatar
|
||||||
|
Storage:
|
||||||
|
PublicFolderFileDir: /data/storage/public_folder_file
|
||||||
|
TmpDir: /data/storage/tmp
|
||||||
|
UploadedFilesDir: /data/storage/uploaded_files
|
||||||
|
TranslationPath: translation.csv
|
||||||
|
UpgradeCheckFilePath: /yizhisec/hs_nginx/resource/release_version_record.csv
|
||||||
|
UserManagement:
|
||||||
|
Host: user-service
|
||||||
|
Port: 9013
|
||||||
|
WatermarkServer:
|
||||||
|
Host: hs-watermark
|
||||||
|
Port: 9014
|
||||||
|
Web:
|
||||||
|
Host: 0.0.0.0
|
||||||
|
Mode: release
|
||||||
|
Port: 9129
|
||||||
|
Web2:
|
||||||
|
Host: 0.0.0.0
|
||||||
|
Mode: release
|
||||||
|
Port: 9024
|
||||||
|
WebMessages:
|
||||||
|
Host: 0.0.0.0
|
||||||
|
Mode: release
|
||||||
|
Port: 9025
|
||||||
|
WorkDir: /yizhisec/client_server
|
||||||
|
YosGuard:
|
||||||
|
Host: 172.17.0.1
|
||||||
|
Port: 7788`
|
||||||
|
_upsert = `#!/bin/bash
|
||||||
|
|
||||||
|
kubectl create configmap config-client --namespace hsv2 --from-file=config.yml=./config.yml --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
kubectl apply -f deployment.yaml
|
||||||
|
kubectl rollout restart deployment client-deployment -n hsv2`
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
workdir = filepath.Join(m.workdir, "app", "client")
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Info("☑️ maker.AppClient: 开始构建 client 应用..., dir = %s", workdir)
|
||||||
|
logger.Debug("☑️ maker.AppClient: 开始创建工作目录 = %s", workdir)
|
||||||
|
if err = os.MkdirAll(workdir, 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppClient: 创建目录失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppClient: 创建工作目录成功 = %s", workdir)
|
||||||
|
|
||||||
|
if replica < 1 {
|
||||||
|
replica = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppClient: 开始构建 yaml 资源文件")
|
||||||
|
content := []byte(fmt.Sprintf(resource.YAMLAppClient, replica))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "deployment.yaml"), content, 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppClient: 写入 deployment.yaml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppClient: 开始 yaml 资源文件成功")
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppClient: 开始构建 config 文件")
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "config.yml"), []byte(_config), 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppClient: 写入 config.yml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppClient: 构建 config 文件成功")
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppClient: 开始构建 upsert.sh 脚本")
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "upsert.sh"), []byte(_upsert), 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppClient: 写入 upsert.sh 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppClient: 构建 upsert.sh 脚本成功")
|
||||||
|
|
||||||
|
logger.Info("✅ maker.AppClient: 构建 client 应用成功!!!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
73
internal/controller/maker/app.front.go
Normal file
73
internal/controller/maker/app.front.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *maker) AppFront(ctx context.Context, vendor string, replica int) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
location = filepath.Join(m.workdir, "app", "front")
|
||||||
|
bs []byte
|
||||||
|
_vendor = model.GetVendor(vendor)
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Info("☑️ maker.Front: 开始构建 front app..., workdir = %s", location)
|
||||||
|
|
||||||
|
if _vendor == nil {
|
||||||
|
logger.Debug("❌ maker.Front: vendor not supported, vendor = %s", vendor)
|
||||||
|
return fmt.Errorf("vendor not supported: %s", vendor)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.MkdirAll(location, 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.Front: 创建目录失败: path = %s, err = %v", location, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
path := filepath.Join(location, "front.user.yaml")
|
||||||
|
logger.Debug("☑️ maker.Front: writing front.user.yaml, path = %s", path)
|
||||||
|
bs = []byte(fmt.Sprintf(resource.YAMLAppFrontUser, replica))
|
||||||
|
if err = os.WriteFile(path, bs, 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.Front: 写入 front.user.yaml 失败: path = %s, err = %v", path, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Front: write front.user.yaml success, path = %s", path)
|
||||||
|
|
||||||
|
path = filepath.Join(location, "front.admin.yaml")
|
||||||
|
logger.Debug("☑️ maker.Front: writing front.admin.yaml, path = %s", path)
|
||||||
|
bs = []byte(fmt.Sprintf(resource.YAMLAppFrontAdmin, replica))
|
||||||
|
if err = os.WriteFile(path, bs, 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.Front: 写入 front.admin.yaml 失败: path = %s, err = %v", path, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Front: write front.admin.yaml success, path = %s", path)
|
||||||
|
|
||||||
|
// todo, pull front images
|
||||||
|
// 1. make image dir
|
||||||
|
imgDir := filepath.Join(m.workdir, "dependency", "image")
|
||||||
|
if err = os.MkdirAll(imgDir, 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.Front: 创建目录失败: path = %s, err = %v", imgDir, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.Front: pulling front images, vendor = %s", vendor)
|
||||||
|
if err = m.Image(ctx, _vendor.AppFrontUserImageName, WithImageSave(filepath.Join(imgDir, "app.front.user.tar")), WithImageForcePull(true)); err != nil {
|
||||||
|
logger.Debug("❌ maker.Front: 拉取 front 用户镜像失败: %s, err = %v", _vendor.AppFrontUserImageName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = m.Image(ctx, _vendor.AppFrontAdminImageName, WithImageSave(filepath.Join(imgDir, "app.front.admin.tar")), WithImageForcePull(true)); err != nil {
|
||||||
|
logger.Debug("❌ maker.Front: 拉取 front 管理镜像失败: %s, err = %v", _vendor.AppFrontAdminImageName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ maker.Front: 构建 front app 完成")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
98
internal/controller/maker/app.gateway.go
Normal file
98
internal/controller/maker/app.gateway.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *maker) AppGateway(ctx context.Context, replica int) error {
|
||||||
|
const (
|
||||||
|
_config = `Version: "3"
|
||||||
|
Database:
|
||||||
|
Elastic:
|
||||||
|
Address: http://es-service.db-es:9200
|
||||||
|
Mysql:
|
||||||
|
Address: mysql.db-mysql:3306
|
||||||
|
DBName: mie
|
||||||
|
Password: L0hMysql.
|
||||||
|
UserName: root
|
||||||
|
Redis:
|
||||||
|
Address: redis-master.db-redis:6379
|
||||||
|
Password: HybridScope0xRed1s.
|
||||||
|
Gateway:
|
||||||
|
Cert:
|
||||||
|
ClientCrt: /yizhisec/ssl/client.crt
|
||||||
|
ClientKey: /yizhisec/ssl/client.key
|
||||||
|
TokenFilePath: /etc/yizhisec/token
|
||||||
|
Key:
|
||||||
|
Token: TtKVnSzEHO3jRv/GWg3f5k3H1OVfMnPZ1Ke9E6MSCXk=
|
||||||
|
Log:
|
||||||
|
Dir: ./log
|
||||||
|
Level: 1
|
||||||
|
Name: gateway_controller
|
||||||
|
Sentry:
|
||||||
|
TracesSampleRate: 1
|
||||||
|
UserManagement:
|
||||||
|
Host: user-service
|
||||||
|
Port: 9013
|
||||||
|
Web:
|
||||||
|
Host: 0.0.0.0
|
||||||
|
Mode: release
|
||||||
|
Port: 9012
|
||||||
|
WorkDir: /yizhisec/gateway_controller/workspace
|
||||||
|
YosGuard:
|
||||||
|
Host: 172.17.0.1
|
||||||
|
Port: 7788`
|
||||||
|
_upsert = `#!/bin/bash
|
||||||
|
|
||||||
|
kubectl create configmap config-gateway --namespace hsv2 --from-file=config.yml=./config.yml --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
kubectl apply -f deployment.yaml
|
||||||
|
kubectl rollout restart deployment gateway-deployment -n hsv2`
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
workdir = filepath.Join(m.workdir, "app", "gateway")
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Info("☑️ maker.AppGateway: 开始构建 gateway 应用..., dir = %s", workdir)
|
||||||
|
logger.Debug("☑️ maker.AppGateway: 开始创建工作目录 = %s", workdir)
|
||||||
|
if err = os.MkdirAll(workdir, 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppGateway: 创建目录失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppGateway: 创建工作目录成功 = %s", workdir)
|
||||||
|
|
||||||
|
if replica < 1 {
|
||||||
|
replica = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppGateway: 开始构建 yaml 资源文件")
|
||||||
|
content := []byte(fmt.Sprintf(resource.YAMLAppGateway, replica))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "deployment.yaml"), content, 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppGateway: 写入 deployment.yaml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppGateway: 开始 yaml 资源文件成功")
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppGateway: 开始构建 config 文件")
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "config.yml"), []byte(_config), 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppGateway: 写入 config.yml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppGateway: 构建 config 文件成功")
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppGateway: 开始构建 upsert.sh 脚本")
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "upsert.sh"), []byte(_upsert), 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppGateway: 写入 upsert.sh 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppGateway: 构建 upsert.sh 脚本成功")
|
||||||
|
|
||||||
|
logger.Info("✅ maker.AppGateway: 构建 gateway 应用成功!!!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
196
internal/controller/maker/app.mie.go
Normal file
196
internal/controller/maker/app.mie.go
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *maker) AppMie(ctx context.Context, replica int) error {
|
||||||
|
const (
|
||||||
|
_config = `Version: "3"
|
||||||
|
BackupSeafile:
|
||||||
|
Host: hs-resource-server
|
||||||
|
Port: 19980
|
||||||
|
account_manager:
|
||||||
|
address: http://user-service:9013
|
||||||
|
client_server:
|
||||||
|
msg: http://client-service:9025
|
||||||
|
api: http://client-service:9024
|
||||||
|
web: http://client-service:9129
|
||||||
|
backend_queue_names:
|
||||||
|
request: request_que
|
||||||
|
web: web_que
|
||||||
|
backup_database_server:
|
||||||
|
host: hs-backup-server
|
||||||
|
port: 9349
|
||||||
|
backup_seafile_server:
|
||||||
|
host: hs-resource-server
|
||||||
|
port: 19980
|
||||||
|
clientPKG:
|
||||||
|
android:
|
||||||
|
client_pkg_dir: /data/storage/client_pkg/android
|
||||||
|
client_pkg_file_path: /data/storage/client_pkg/android/SecureApplication-Client-Android.apk
|
||||||
|
client_pkg_name: SecureApplication-Client-Android.apk
|
||||||
|
client_version_file_path: /data/storage/client_pkg/android/android_version.json
|
||||||
|
dir: /data/storage/client_pkg
|
||||||
|
ios:
|
||||||
|
client_pkg_dir: /data/storage/client_pkg/ios
|
||||||
|
client_pkg_file_path: ''
|
||||||
|
client_pkg_name: ''
|
||||||
|
client_version_file_path: /data/storage/client_pkg/ios/ios_version.json
|
||||||
|
linux:
|
||||||
|
client_pkg_dir: /data/storage/client_pkg/linux
|
||||||
|
client_pkg_file_path: /data/storage/client_pkg/linux/hscore-ubuntu-22.04-amd64.deb
|
||||||
|
client_pkg_name: hscore-ubuntu-22.04-amd64.deb
|
||||||
|
client_version_file_path: /data/storage/client_pkg/linux/linux_version.json
|
||||||
|
mac:
|
||||||
|
client_pkg_beta_file_path: /yizhisec/hs_nginx/resource/hybridscope-client-mac-beta.pkg
|
||||||
|
client_pkg_beta_name: hybridscope-client-mac-beta.pkg
|
||||||
|
client_pkg_dir: /data/storage/client_pkg/mac
|
||||||
|
client_pkg_file_path: /yizhisec/hs_nginx/resource/hybridscope-client-mac.pkg
|
||||||
|
client_pkg_name: hybridscope-client-mac.pkg
|
||||||
|
client_version_file_path: /data/storage/client_pkg/mac/mac_version.json
|
||||||
|
oem_dir: /yizhisec/hs_nginx/data/443/oem
|
||||||
|
oem_file_path: /yizhisec/hs_nginx/data/443/oem/data.json
|
||||||
|
windows:
|
||||||
|
client_main_zip_name: app.7z
|
||||||
|
client_pkg_cfg_file_name: login.conf
|
||||||
|
client_pkg_dir: /data/storage/client_pkg/windows
|
||||||
|
client_pkg_unzip_dir: package
|
||||||
|
client_pkg_zip: /data/storage/client_pkg/windows/dsclient.zip
|
||||||
|
client_zip_version: version
|
||||||
|
databases:
|
||||||
|
elasticsearch:
|
||||||
|
host: es-service.db-es
|
||||||
|
port: 9200
|
||||||
|
ipdb:
|
||||||
|
path: /etc/mie-server/ipdb/ip.ipdb
|
||||||
|
mysql:
|
||||||
|
db: mie
|
||||||
|
host: mysql-cluster-mysql-master.db-mysql
|
||||||
|
password: L0hMysql.
|
||||||
|
port: 3306
|
||||||
|
username: root
|
||||||
|
redis:
|
||||||
|
host: redis-master.db-redis
|
||||||
|
password: HybridScope0xRed1s.
|
||||||
|
port: 6379
|
||||||
|
username: ''
|
||||||
|
exe_root_license:
|
||||||
|
path: /etc/mie-server/root.pem
|
||||||
|
gateway_service:
|
||||||
|
host: gateway-service.hsv2
|
||||||
|
port: 9012
|
||||||
|
host: 0.0.0.0
|
||||||
|
license:
|
||||||
|
version: 3
|
||||||
|
license_init_conf: /etc/mie-server/server_license_init.conf
|
||||||
|
public_key: /etc/mie-server/license/pub_key
|
||||||
|
log_level: 20
|
||||||
|
mqtt_server:
|
||||||
|
host: emqx-service.db-emqx
|
||||||
|
port: 1883
|
||||||
|
port: 9002
|
||||||
|
resource_server:
|
||||||
|
address: http://hs-resource-server:19980
|
||||||
|
secret_key: i345piuh48776lkjsdhfsdfljho
|
||||||
|
sentry_dsn: null
|
||||||
|
static_urlpath_prefix:
|
||||||
|
network_app_icon: /user/avatar
|
||||||
|
storage:
|
||||||
|
avatar_dir: /data/storage/avatar
|
||||||
|
mobile_app_dir: /yizhisec/hs_nginx
|
||||||
|
network_app_icon: network_app
|
||||||
|
patch_dir: /data/storage/patch
|
||||||
|
public_folder_file_dir: /data/storage/public_folder_file
|
||||||
|
share_file_storage: /data/storage/share_file
|
||||||
|
sync_avatar_dir: sync
|
||||||
|
tmp_dir: /data/storage/tmp
|
||||||
|
upload_avatar_dir: local
|
||||||
|
uploaded_files: /data/storage/uploaded_files
|
||||||
|
token_key: TtKVnSzEHO3jRv/GWg3f5k3H1OVfMnPZ1Ke9E6MSCXk=
|
||||||
|
translation_path: /etc/mie-server/translation.csv
|
||||||
|
yosguard_service:
|
||||||
|
host: 172.17.0.1
|
||||||
|
port: 7788
|
||||||
|
ElinkLogin: true
|
||||||
|
export_with_blind_watermark: true`
|
||||||
|
_upsert = `#!/bin/bash
|
||||||
|
|
||||||
|
kubectl create configmap config-api --namespace hsv2 --from-file=conf.yml=./conf.yml --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
kubectl apply -f deployment-api.yaml
|
||||||
|
kubectl apply -f deployment-sweeper.yaml
|
||||||
|
kubectl apply -f deployment-worker.yaml
|
||||||
|
kubectl apply -f deployment-cron.yaml
|
||||||
|
|
||||||
|
kubectl rollout restart deployment api-deployment -n hsv2`
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
workdir = filepath.Join(m.workdir, "app", "mie")
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Info("☑️ maker.AppMie: 开始构建 mie ... workdir = %s", workdir)
|
||||||
|
logger.Debug("☑️ maker.AppMie: 开始创建工作目录 = %s", workdir)
|
||||||
|
if err = os.MkdirAll(workdir, 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppMie: 创建目录失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppMie: 创建工作目录成功 = %s", workdir)
|
||||||
|
|
||||||
|
if replica < 1 {
|
||||||
|
replica = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppMie: 写入 conf.yml 文件..., dest = %s", filepath.Join(workdir, "conf.yml"))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "conf.yml"), []byte(_config), 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppMie: 写入 conf.yml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppMie: 写入 conf.yml 文件成功, dest = %s", filepath.Join(workdir, "conf.yml"))
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppMie: 写入 deployment-api.yaml 文件..., dest = %s", filepath.Join(workdir, "deployment-api.yaml"))
|
||||||
|
apiYaml := []byte(fmt.Sprintf(resource.YAMLAppMieAPI, replica))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "deployment-api.yaml"), apiYaml, 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppMie: 写入 deployment-api.yaml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppMie: 写入 deployment-api.yaml 文件成功, dest = %s", filepath.Join(workdir, "deployment-api.yaml"))
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppMie: 写入 deployment-sweeper.yaml 文件..., dest = %s", filepath.Join(workdir, "deployment-sweeper.yaml"))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "deployment-sweeper.yaml"), resource.YAMLAppMieSweeper, 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppMie: 写入 deployment-sweeper.yaml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppMie: 写入 deployment-sweeper.yaml 文件成功, dest = %s", filepath.Join(workdir, "deployment-sweeper.yaml"))
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppMie: 写入 deployment-worker.yaml 文件..., dest = %s", filepath.Join(workdir, "deployment-worker.yaml"))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "deployment-worker.yaml"), resource.YAMLAppMieWorker, 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppMie: 写入 deployment-worker.yaml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppMie: 写入 deployment-worker.yaml 文件成功, dest = %s", filepath.Join(workdir, "deployment-worker.yaml"))
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppMie: 写入 deployment-cron.yaml 文件..., dest = %s", filepath.Join(workdir, "deployment-cron.yaml"))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "deployment-cron.yaml"), resource.YAMLAppMieCron, 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppMie: 写入 deployment-cron.yaml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppMie: 写入 deployment-cron.yaml 文件成功, dest = %s", filepath.Join(workdir, "deployment-cron.yaml"))
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppMie: 写入 upsert.sh 文件..., dest = %s", filepath.Join(workdir, "upsert.sh"))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "upsert.sh"), []byte(_upsert), 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppMie: 写入 upsert.sh 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppMie: 写入 upsert.sh 文件成功, dest = %s", filepath.Join(workdir, "upsert.sh"))
|
||||||
|
|
||||||
|
logger.Info("✅ maker.AppMie: 构建 mie 成功!!! workdir = %s", workdir)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
179
internal/controller/maker/app.nginx.go
Normal file
179
internal/controller/maker/app.nginx.go
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"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 nginx.yaml
|
||||||
|
kubectl rollout restart deployment nginx-deployment -n hsv2`
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
workdir = filepath.Join(m.workdir, "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
|
||||||
|
}
|
||||||
159
internal/controller/maker/app.oem.go
Normal file
159
internal/controller/maker/app.oem.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/archiver"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *maker) AppOEM(ctx context.Context, vendor string, replica int) error {
|
||||||
|
const (
|
||||||
|
_nginx = `user root;
|
||||||
|
worker_processes auto;
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
client_max_body_size 10M;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
|
||||||
|
root /data;
|
||||||
|
location / {
|
||||||
|
try_files \$uri \$uri/ =404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
_dockerfile = `FROM hub.yizhisec.com/external/nginx:1.29.1-alpine3.22
|
||||||
|
|
||||||
|
WORKDIR /data
|
||||||
|
COPY oem /data/oem
|
||||||
|
COPY nginx.conf /etc/nginx/nginx.conf
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]`
|
||||||
|
_image = "hub.yizhisec.com/hybridscope/v2/oem-%s:latest"
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
_vendor = model.GetVendor(vendor)
|
||||||
|
workdir = filepath.Join(m.workdir, "app", "oem")
|
||||||
|
output []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Info("☑️ maker.AppOEM: 开始构建 oem[%s], workdir = %s", vendor, workdir)
|
||||||
|
|
||||||
|
if _vendor == nil {
|
||||||
|
supported := model.GetVendorNames()
|
||||||
|
logger.Debug("❌ maker.AppOEM: vendor not supported, 支持的 vendor 有: %v", supported)
|
||||||
|
return fmt.Errorf("请检查 vendor 是否正确, 支持的 vendor 有: %v", supported)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. make workdir
|
||||||
|
logger.Debug("☑️ maker.AppOEM: 开始创建 workdir = %s", workdir)
|
||||||
|
if err = os.MkdirAll(workdir, 0o755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppOEM: workdir 创建成功 = %s", workdir)
|
||||||
|
|
||||||
|
// 2. download oem.tar.gz
|
||||||
|
logger.Debug("☑️ maker.AppOEM: 开始下载 oem[%s] url = %s", vendor, _vendor)
|
||||||
|
if err = archiver.DownloadAndExtract(ctx, _vendor.OEMUrl, workdir); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppOEM: oem[%s] tar 下载失败, url = %s, err = %v", vendor, _vendor.OEMUrl, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _vendor.OEMDir != "oem" {
|
||||||
|
if err = os.Rename(
|
||||||
|
filepath.Join(workdir, _vendor.OEMDir),
|
||||||
|
filepath.Join(workdir, "oem"),
|
||||||
|
); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppOEM: oem[%s] tar 重命名失败, err = %v", vendor, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppOEM: oem[%s] tar 下载成功", vendor)
|
||||||
|
|
||||||
|
// 3. write nginx.conf
|
||||||
|
logger.Debug("☑️ maker.AppOEM: 开始写入 nginx.conf")
|
||||||
|
if err = os.WriteFile(
|
||||||
|
filepath.Join(workdir, "nginx.conf"),
|
||||||
|
[]byte(_nginx),
|
||||||
|
0o644,
|
||||||
|
); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppOEM: nginx.conf 写入失败, err = %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppOEM: nginx.conf 写入成功")
|
||||||
|
|
||||||
|
// 4. write Dockerfile
|
||||||
|
logger.Debug("☑️ maker.AppOEM: 开始写入 Dockerfile")
|
||||||
|
if err = os.WriteFile(
|
||||||
|
filepath.Join(workdir, "Dockerfile"),
|
||||||
|
[]byte(_dockerfile),
|
||||||
|
0o644,
|
||||||
|
); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppOEM: Dockerfile 写入失败, err = %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppOEM: Dockerfile 写入成功")
|
||||||
|
|
||||||
|
// 5. build docker image
|
||||||
|
imageName := fmt.Sprintf(_image, vendor)
|
||||||
|
logger.Debug("☑️ maker.AppOEM: 开始构建 docker image = %s", imageName)
|
||||||
|
// docker build -t <image_name> -f <workdir/Dockerfile> <workdir>
|
||||||
|
_cmd := exec.CommandContext(ctx, "docker", "build", "-t", imageName, "-f", filepath.Join(workdir, "Dockerfile"), workdir)
|
||||||
|
if output, err = _cmd.CombinedOutput(); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppOEM: docker image 构建失败, err = %v, output = %s", err, string(output))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppOEM: docker image 构建成功, image = %s", imageName)
|
||||||
|
|
||||||
|
// 6. save docker image to image dir
|
||||||
|
logger.Debug("☑️ maker.AppOEM: 开始保存 docker image = %s 到 %s", imageName, filepath.Join(m.workdir, "image", imageName))
|
||||||
|
if err = os.MkdirAll(filepath.Join(m.workdir, "dependency", "image"), 0o755); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppOEM: image 目录创建失败, err = %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = exec.CommandContext(ctx, "docker", "save", "-o", filepath.Join(m.workdir, "dependency", "image", "app.oem.tar"), imageName).Run(); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppOEM: docker image 保存失败, err = %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppOEM: docker image 保存成功, image = %s", imageName)
|
||||||
|
|
||||||
|
// 7. render oem.yaml
|
||||||
|
logger.Debug("☑️ maker.AppOEM: 开始渲染 deployment.yaml")
|
||||||
|
oemYAML := fmt.Sprintf(resource.YAMLAppOEM, replica, imageName)
|
||||||
|
if err = os.WriteFile(
|
||||||
|
filepath.Join(workdir, "deployment.yaml"),
|
||||||
|
[]byte(oemYAML),
|
||||||
|
0o644,
|
||||||
|
); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppOEM: deployment.yaml 写入失败, err = %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppOEM: deployment.yaml 写入成功")
|
||||||
|
|
||||||
|
logger.Info("✅ maker.AppOEM: 开始构建 oem[%s] 成功!!!", vendor)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -2,8 +2,127 @@ package maker
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *maker) AppUser(ctx context.Context, replica int) error {
|
func (m *maker) AppUser(ctx context.Context, replica int) error {
|
||||||
|
const (
|
||||||
|
_config = `Version: "3"
|
||||||
|
Database:
|
||||||
|
Elastic:
|
||||||
|
Address: http://es-service.db-es:9200
|
||||||
|
IPDB:
|
||||||
|
Path: /etc/hs_user_management/ipdb/ip.ipdb
|
||||||
|
Mysql:
|
||||||
|
Address: mysql-cluster-mysql-master.db-mysql:3306
|
||||||
|
DBName: mie
|
||||||
|
Password: L0hMysql.
|
||||||
|
UserName: root
|
||||||
|
Redis:
|
||||||
|
Address: redis-master.db-redis:6379
|
||||||
|
Password: HybridScope0xRed1s.
|
||||||
|
DisabledFeatureFilePath: /etc/yizhisec/disabled_features
|
||||||
|
EnableTenant: false
|
||||||
|
Key:
|
||||||
|
Token: TtKVnSzEHO3jRv/GWg3f5k3H1OVfMnPZ1Ke9E6MSCXk=
|
||||||
|
LicensePubKey: /etc/yizhisec/license/pub_key
|
||||||
|
Log:
|
||||||
|
Dir: ./log
|
||||||
|
Level: 1
|
||||||
|
Name: hs_user_management
|
||||||
|
Sentry:
|
||||||
|
TracesSampleRate: 1
|
||||||
|
Sso:
|
||||||
|
DingTalk:
|
||||||
|
ApiHost: oapi.dingtalk.com
|
||||||
|
LoginUrl: https://oapi.dingtalk.com/connect/qrconnect
|
||||||
|
Feishu:
|
||||||
|
ApiHost: open.feishu.cn
|
||||||
|
LoginUrl: https://open.feishu.cn/open-apis/authen/v1/index
|
||||||
|
Proxy:
|
||||||
|
CallbackHost: hssso.yizhisec.com:33443
|
||||||
|
Cert:
|
||||||
|
ClientCrt: /etc/hs_user_management/proxy/certs/client.crt
|
||||||
|
ClientKey: /etc/hs_user_management/proxy/certs/client.key
|
||||||
|
ServiceHost: hssso.yizhisec.com:33444
|
||||||
|
RedirectPath:
|
||||||
|
BoundFailed: /#/accountSettings/thirdAccount
|
||||||
|
BoundSuccess: /#/accountSettings/thirdAccount
|
||||||
|
LoginFailed: /#/thirdError
|
||||||
|
LoginNeedBoundUser: /#/bind
|
||||||
|
LoginSuccess: /#/
|
||||||
|
WorkWeiXin:
|
||||||
|
ApiHost: qyapi.weixin.qq.com
|
||||||
|
LoginUrl: https://login.work.weixin.qq.com/wwlogin/sso/login
|
||||||
|
Storage:
|
||||||
|
Avatar:
|
||||||
|
ADSyncDir: ad
|
||||||
|
Base: /data/storage/avatar
|
||||||
|
LDAPSyncDir: ldap
|
||||||
|
LocalDir: local
|
||||||
|
SyncDir: sync
|
||||||
|
TranslationPath: translation.csv
|
||||||
|
Web:
|
||||||
|
Host: 0.0.0.0
|
||||||
|
Mode: release
|
||||||
|
Port: 9013
|
||||||
|
WorkDir: /yizhisec/hs_user_management/workspace
|
||||||
|
YosGuard:
|
||||||
|
Host: 172.17.0.1
|
||||||
|
Port: 7788
|
||||||
|
ElinkLogin: false`
|
||||||
|
_upsert = `#!/bin/bash
|
||||||
|
|
||||||
|
kubectl create configmap config-user --namespace hsv2 --from-file=config.yml=./config.yml --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
kubectl apply -f deployment.yaml
|
||||||
|
kubectl rollout restart deployment user-deployment -n hsv2`
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
workdir = filepath.Join(m.workdir, "app", "user")
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Info("☑️ maker.AppUser: 开始构建 user 应用..., dir = %s", workdir)
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppUser: 开始创建工作目录 = %s", workdir)
|
||||||
|
if err = os.MkdirAll(workdir, 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppUser: 创建目录失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppUser: 创建工作目录成功 = %s", workdir)
|
||||||
|
|
||||||
|
if replica < 1 {
|
||||||
|
replica = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppUser: 开始构建 yaml 资源文件")
|
||||||
|
content := []byte(fmt.Sprintf(resource.YAMLAppUser, replica))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "deployment.yaml"), []byte(content), 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppUser: 写入 deployment.yaml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppUser: 开始 yaml 资源文件成功")
|
||||||
|
|
||||||
|
// 写入 config.yml
|
||||||
|
logger.Debug("☑️ maker.AppUser: 开始构建 config 文件")
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "config.yml"), []byte(_config), 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppUser: 写入 config.yml 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppUser: 构建 config 文件成功")
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.AppUser: 开始构建 upsert.sh 脚本")
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "upsert.sh"), []byte(_upsert), 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.AppUser: 写入 upsert.sh 失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.AppUser: 构建 upsert.sh 脚本成功")
|
||||||
|
|
||||||
|
logger.Info("✅ maker.AppUser: 构建 user 应用成功!!!")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,24 +5,24 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
|
||||||
"yizhisec.com/hsv2/forge/pkg/archiver"
|
"yizhisec.com/hsv2/forge/pkg/archiver"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *maker) Binary(ctx context.Context) error {
|
func (m *maker) K0s(ctx context.Context) error {
|
||||||
var (
|
var (
|
||||||
tarURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/k8s-bin.tar"
|
tarURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/k8s-bin.tar"
|
||||||
binDir = filepath.Join(opt.Cfg.Make.Dir, "dependency")
|
location = filepath.Join(m.workdir, "dependency", "k0s")
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.Info("☑️ 开始准备 k8s 二进制文件...")
|
logger.Info("☑️ 开始准备 k0s...")
|
||||||
logger.Debug("下载地址: %s", tarURL)
|
logger.Debug("下载地址: %s", tarURL)
|
||||||
logger.Debug("目标目录: %s", binDir)
|
logger.Debug("目标目录: %s", location)
|
||||||
|
|
||||||
if err := archiver.DownloadAndExtract(
|
if err := archiver.DownloadAndExtract(
|
||||||
ctx,
|
ctx,
|
||||||
tarURL,
|
tarURL,
|
||||||
binDir,
|
location,
|
||||||
archiver.WithInsecureSkipVerify(),
|
archiver.WithInsecureSkipVerify(),
|
||||||
archiver.WithGzipCompression(true),
|
archiver.WithGzipCompression(true),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
@@ -30,7 +30,32 @@ func (m *maker) Binary(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("✅ 准备 k8s 二进制文件成功!!!")
|
logger.Debug("☑️ maker.K0s: 开始准备相关镜像...")
|
||||||
|
var images = []*model.Image{
|
||||||
|
{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"},
|
||||||
|
}
|
||||||
|
for _, image := range images {
|
||||||
|
opts := []ImageOpt{
|
||||||
|
WithImageFallback(image.Fallback),
|
||||||
|
WithImageSave(filepath.Join(location, image.Save)),
|
||||||
|
WithImageForcePull(image.Force),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.Image(ctx, image.Name, opts...); err != nil {
|
||||||
|
logger.Error("❌ maker.K0s: 获取镜像失败: %s, 可以手动获取后重试", image.Name)
|
||||||
|
logger.Debug("❌ maker.K0s: 获取镜像失败: %s, %v", image.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.K0s: 准备相关镜像成功!!!")
|
||||||
|
|
||||||
|
logger.Info("✅ 准备 k0s 成功!!!")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ func (m *maker) DependencyCheck(ctx context.Context) error {
|
|||||||
return fmt.Errorf("docker 命令未找到: %w", err)
|
return fmt.Errorf("docker 命令未找到: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := checkCommand(ctx, "7z"); err != nil {
|
||||||
|
return fmt.Errorf("7z 命令未找到: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
154
internal/controller/maker/client.pkg.go
Normal file
154
internal/controller/maker/client.pkg.go
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 WithClientPKGCMD(cmd string) ClientPKGOption {
|
||||||
|
return func(o *clientPKGOption) {
|
||||||
|
if cmd == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
o.CMDs = append(o.CMDs, cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *maker) ClientPKG(ctx context.Context, _os string, _version string, api string, opts ...ClientPKGOption) error {
|
||||||
|
const (
|
||||||
|
Dockerfile = `
|
||||||
|
FROM hub.yizhisec.com/external/nginx:1.29.4-alpine3.23
|
||||||
|
|
||||||
|
RUN mkdir -p /data
|
||||||
|
%s
|
||||||
|
%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
|
||||||
|
_cmds = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
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.MkdirAll(location, 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.ClientPKG: create directory failed, directory = %s, err = %s", location, err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
_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("RUN wget -O /data/%s %s", d.Name, d.URL)
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(o.CMDs) > 0 {
|
||||||
|
_cmds = fmt.Sprintf("RUN %s", strings.Join(o.CMDs, " && "))
|
||||||
|
}
|
||||||
|
|
||||||
|
_file = filepath.Join(location, "Dockerfile")
|
||||||
|
_content = fmt.Sprintf(Dockerfile, strings.Join(lines, "\n"), _cmds)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("️✅ maker.ClientPKG: build client pkg success, os = %s, version = %s, location = %s", _os, _version, location)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
28
internal/controller/maker/command.go
Normal file
28
internal/controller/maker/command.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *maker) RunCommand(ctx context.Context, dir string, _cmds ...string) error {
|
||||||
|
if len(_cmds) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cmdStr := range _cmds {
|
||||||
|
cmd := exec.CommandContext(ctx, "sh", "-c", cmdStr)
|
||||||
|
|
||||||
|
if dir != "" {
|
||||||
|
cmd.Dir = dir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the command
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("failed to run command '%s' in directory '%s': %w", cmdStr, dir, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
|
||||||
"yizhisec.com/hsv2/forge/pkg/downloader"
|
"yizhisec.com/hsv2/forge/pkg/downloader"
|
||||||
"yizhisec.com/hsv2/forge/pkg/extractor"
|
"yizhisec.com/hsv2/forge/pkg/extractor"
|
||||||
"yizhisec.com/hsv2/forge/pkg/tool/random"
|
"yizhisec.com/hsv2/forge/pkg/tool/random"
|
||||||
@@ -86,6 +85,11 @@ EEuYRYXDouPJ1F//rYraSoJ4mtaipB6z1A==
|
|||||||
-----END EC PRIVATE KEY-----`
|
-----END EC PRIVATE KEY-----`
|
||||||
upsert = `#!/bin/bash
|
upsert = `#!/bin/bash
|
||||||
|
|
||||||
|
# Generate server_license_init.conf
|
||||||
|
uuid=$(cat /proc/sys/kernel/random/uuid)
|
||||||
|
now=$(date +%s)
|
||||||
|
echo "{\"uuid\": \"$uuid\", \"install_time\": $now}" > ./server_license_init.conf
|
||||||
|
|
||||||
kubectl create configmap config-token --namespace hsv2 --from-file=token=./token --dry-run=client -o yaml | kubectl apply -f -
|
kubectl create configmap config-token --namespace hsv2 --from-file=token=./token --dry-run=client -o yaml | kubectl apply -f -
|
||||||
kubectl create configmap config-license-init --namespace hsv2 --from-file=server_license_init.conf=./server_license_init.conf --dry-run=client -o yaml | kubectl apply -f -
|
kubectl create configmap config-license-init --namespace hsv2 --from-file=server_license_init.conf=./server_license_init.conf --dry-run=client -o yaml | kubectl apply -f -
|
||||||
kubectl create configmap config-oem-data --namespace hsv2 --from-file=data.json=./oem_data.json --dry-run=client -o yaml | kubectl apply -f -
|
kubectl create configmap config-oem-data --namespace hsv2 --from-file=data.json=./oem_data.json --dry-run=client -o yaml | kubectl apply -f -
|
||||||
@@ -96,12 +100,22 @@ kubectl create configmap ssl-client-key --namespace hsv2 --from-file=client.key=
|
|||||||
kubectl create configmap ssl-client-ca-crt --namespace hsv2 --from-file=client.ca.crt=./ssl_client_ca.crt --dry-run=client -o yaml | kubectl apply -f -
|
kubectl create configmap ssl-client-ca-crt --namespace hsv2 --from-file=client.ca.crt=./ssl_client_ca.crt --dry-run=client -o yaml | kubectl apply -f -
|
||||||
kubectl create configmap ssl-client-ca-key --namespace hsv2 --from-file=client.ca.key=./ssl_client_ca.key --dry-run=client -o yaml | kubectl apply -f -
|
kubectl create configmap ssl-client-ca-key --namespace hsv2 --from-file=client.ca.key=./ssl_client_ca.key --dry-run=client -o yaml | kubectl apply -f -
|
||||||
kubectl create configmap ssl-web-crt --namespace hsv2 --from-file=web.server.crt=./ssl_web.crt --dry-run=client -o yaml | kubectl apply -f -
|
kubectl create configmap ssl-web-crt --namespace hsv2 --from-file=web.server.crt=./ssl_web.crt --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
`
|
||||||
|
_version_yaml = `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: config-version
|
||||||
|
namespace: hsv2
|
||||||
|
data:
|
||||||
|
version.txt: |
|
||||||
|
__version__
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
dir = filepath.Join(opt.Cfg.Make.Dir, "configmap")
|
dir = filepath.Join(m.workdir, "configmap")
|
||||||
vendorUrlMap = map[string]string{
|
vendorUrlMap = map[string]string{
|
||||||
"standard": "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem.tar.gz",
|
"standard": "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem.tar.gz",
|
||||||
"elink": "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem_csgElink.tar.gz",
|
"elink": "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem_csgElink.tar.gz",
|
||||||
@@ -204,6 +218,12 @@ kubectl create configmap ssl-web-crt --namespace hsv2 --from-file=web.server.crt
|
|||||||
}
|
}
|
||||||
logger.Debug("✅ maker.ConfigMap: 写入 ssl_client_ca.key 文件: %s 成功", filepath.Join(dir, "ssl_client_ca.key"))
|
logger.Debug("✅ maker.ConfigMap: 写入 ssl_client_ca.key 文件: %s 成功", filepath.Join(dir, "ssl_client_ca.key"))
|
||||||
|
|
||||||
|
if err = os.WriteFile(filepath.Join(dir, "version.yaml"), []byte(_version_yaml), 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.ConfigMap: 写入 version.yaml 文件: %s 失败, 错误: %v", filepath.Join(dir, "version.yaml"), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.ConfigMap: 写入 version.yaml 文件: %s 成功", filepath.Join(dir, "version.yaml"))
|
||||||
|
|
||||||
// upsert configmap
|
// upsert configmap
|
||||||
logger.Debug("☑️ maker.ConfigMap: 执行 upsert 脚本: %s", filepath.Join(dir, "upsert.sh"))
|
logger.Debug("☑️ maker.ConfigMap: 执行 upsert 脚本: %s", filepath.Join(dir, "upsert.sh"))
|
||||||
if err = os.WriteFile(filepath.Join(dir, "upsert.sh"), []byte(upsert), 0755); err != nil {
|
if err = os.WriteFile(filepath.Join(dir, "upsert.sh"), []byte(upsert), 0755); err != nil {
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
"yizhisec.com/hsv2/forge/pkg/archiver"
|
"yizhisec.com/hsv2/forge/pkg/archiver"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
"yizhisec.com/hsv2/forge/pkg/resource"
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ func WithElasticMemRate(memRate int) ElasticOpt {
|
|||||||
|
|
||||||
func WithElasticStorageGi(storage string) ElasticOpt {
|
func WithElasticStorageGi(storage string) ElasticOpt {
|
||||||
return func(o *elasticOpt) {
|
return func(o *elasticOpt) {
|
||||||
if matched, _ := regexp.MatchString(`^\d+(\.\d+)?[EPTGMK]i?$`, storage); matched {
|
if opt.StorageSizeReg.MatchString(storage) {
|
||||||
o.Storage = storage
|
o.Storage = storage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,8 +66,8 @@ RUN chmod +x /data/create_index.sh
|
|||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
output []byte
|
output []byte
|
||||||
location = filepath.Join(opt.Cfg.Make.Dir, "dependency", "elastic")
|
location = filepath.Join(m.workdir, "dependency", "elastic")
|
||||||
helperTarLocation = filepath.Join(opt.Cfg.Make.Dir, "dependency", "image", "es-init-helper.alpine-3.22.2.tar")
|
helperTarLocation = filepath.Join(m.workdir, "dependency", "image", "es-init-helper.alpine-3.22.2.tar")
|
||||||
)
|
)
|
||||||
|
|
||||||
opt := &elasticOpt{
|
opt := &elasticOpt{
|
||||||
@@ -179,6 +179,28 @@ RUN chmod +x /data/create_index.sh
|
|||||||
}
|
}
|
||||||
logger.Debug("✅ maker.Elastic: 写入 kibana.yaml 文件成功")
|
logger.Debug("✅ maker.Elastic: 写入 kibana.yaml 文件成功")
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.Elastic: 开始获取所需镜像...")
|
||||||
|
|
||||||
|
var images = []*model.Image{
|
||||||
|
{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"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, image := range images {
|
||||||
|
opts := []ImageOpt{
|
||||||
|
WithImageFallback(image.Fallback),
|
||||||
|
WithImageSave(filepath.Join(location, image.Save)),
|
||||||
|
WithImageForcePull(image.Force),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.Image(ctx, image.Name, opts...); err != nil {
|
||||||
|
logger.Error("❌ maker.Elastic: 获取镜像失败: %s, 可以手动获取后重试", image.Name)
|
||||||
|
logger.Debug("❌ maker.Elastic: 获取镜像失败: %s, %v", image.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Elastic: 获取所需镜像成功!!!")
|
||||||
|
|
||||||
logger.Info("✅ maker.Elastic: 构建 elastic(es) 依赖成功!!!")
|
logger.Info("✅ maker.Elastic: 构建 elastic(es) 依赖成功!!!")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
"yizhisec.com/hsv2/forge/pkg/resource"
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *maker) EMQX(ctx context.Context) error {
|
func (m *maker) EMQX(ctx context.Context) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
location = filepath.Join(opt.Cfg.Make.Dir, "emqx")
|
location = filepath.Join(m.workdir, "dependency", "emqx")
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.Info("☑️ maker.EMQX: 开始构建 emqx(mqtt) 依赖...")
|
logger.Info("☑️ maker.EMQX: 开始构建 emqx(mqtt) 依赖...")
|
||||||
@@ -32,6 +32,14 @@ func (m *maker) EMQX(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
logger.Debug("✅ maker.EMQX: 写入 emqx.yaml 文件成功, dest = %s", filepath.Join(location, "emqx.yaml"))
|
logger.Debug("✅ maker.EMQX: 写入 emqx.yaml 文件成功, dest = %s", filepath.Join(location, "emqx.yaml"))
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.EMQX: 开始获取所需镜像...")
|
||||||
|
var img = &model.Image{Name: "hub.yizhisec.com/external/emqx:5.1", Fallback: "", Save: "emqx.5.1.tar"}
|
||||||
|
if err = m.Image(ctx, img.Name, WithImageFallback(img.Fallback), WithImageSave(filepath.Join(location, img.Save))); err != nil {
|
||||||
|
logger.Debug("❌ maker.EMQX: 获取镜像失败: %s, %v", img.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.EMQX: 获取所需镜像成功!!!")
|
||||||
|
|
||||||
logger.Info("✅ maker.EMQX: 构建 emqx(mqtt) 依赖成功!!!")
|
logger.Info("✅ maker.EMQX: 构建 emqx(mqtt) 依赖成功!!!")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
"yizhisec.com/hsv2/forge/pkg/resource"
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *maker) Flannel(ctx context.Context, mode string) error {
|
func (m *maker) Flannel(ctx context.Context, mode string) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
location = filepath.Join(opt.Cfg.Make.Dir, "dependency", "flannel")
|
location = filepath.Join(m.workdir, "dependency", "flannel")
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.Info("☑️ 开始构建 flannel 资源...")
|
logger.Info("☑️ 开始构建 flannel 资源...")
|
||||||
@@ -34,6 +34,27 @@ func (m *maker) Flannel(ctx context.Context, mode string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var images = []*model.Image{
|
||||||
|
{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"},
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("MakeFlannel: 开始获取镜像...")
|
||||||
|
for _, image := range images {
|
||||||
|
opts := []ImageOpt{
|
||||||
|
WithImageFallback(image.Fallback),
|
||||||
|
WithImageSave(filepath.Join(location, image.Save)),
|
||||||
|
WithImageForcePull(image.Force),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.Image(ctx, image.Name, opts...); err != nil {
|
||||||
|
logger.Error("❌ MakeFlannel: 获取镜像失败: %s, 可以手动获取后重试", image.Name)
|
||||||
|
logger.Debug("❌ MakeFlannel: 获取镜像失败: %s, %v", image.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debug("MakeFlannel: 获取镜像成功!!!")
|
||||||
|
|
||||||
logger.Info("✅ 构建 flannel 成功!!!")
|
logger.Info("✅ 构建 flannel 成功!!!")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
"yizhisec.com/hsv2/forge/pkg/archiver"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *maker) HSNet(ctx context.Context) error {
|
func (m *maker) HSNet(ctx context.Context) error {
|
||||||
const (
|
const (
|
||||||
service = `[Unit]
|
_service = `[Unit]
|
||||||
Description=hs-net Container Service
|
Description=hs-net Container Service
|
||||||
Documentation=https://docs.containerd.io
|
Documentation=https://docs.containerd.io
|
||||||
After=network.target containerd.service
|
After=network.target containerd.service
|
||||||
@@ -19,6 +20,7 @@ After=network.target containerd.service
|
|||||||
[Service]
|
[Service]
|
||||||
# 启动前清理旧容器
|
# 启动前清理旧容器
|
||||||
# ExecStartPre=-/usr/local/bin/k0s ctr -n hs-net task kill hs-net
|
# ExecStartPre=-/usr/local/bin/k0s ctr -n hs-net task kill hs-net
|
||||||
|
ExecStartPre=-/usr/local/bin/k0s ctr namespace create hs-net
|
||||||
ExecStartPre=-/usr/local/bin/k0s ctr -n hs-net container rm hs-net
|
ExecStartPre=-/usr/local/bin/k0s ctr -n hs-net container rm hs-net
|
||||||
|
|
||||||
# 拉取最新镜像(按需启用/注释)
|
# 拉取最新镜像(按需启用/注释)
|
||||||
@@ -28,9 +30,7 @@ ExecStartPre=-/usr/local/bin/k0s ctr -n hs-net container rm hs-net
|
|||||||
ExecStart=/usr/local/bin/k0s ctr -n hs-net run \
|
ExecStart=/usr/local/bin/k0s ctr -n hs-net run \
|
||||||
--net-host \
|
--net-host \
|
||||||
--privileged \
|
--privileged \
|
||||||
--cgroup host \
|
|
||||||
--env LD_LIBRARY_PATH=/yizhisec/hs_net \
|
--env LD_LIBRARY_PATH=/yizhisec/hs_net \
|
||||||
--env RUSTFLAGS="-C target-cpu=nehalem" \
|
|
||||||
--env RUST_BACKTRACE=1 \
|
--env RUST_BACKTRACE=1 \
|
||||||
--mount type=bind,src=/etc/localtime,dst=/etc/localtime,options=rbind:ro \
|
--mount type=bind,src=/etc/localtime,dst=/etc/localtime,options=rbind:ro \
|
||||||
--mount type=bind,src=/etc/hosts,dst=/etc/hosts,options=rbind:ro \
|
--mount type=bind,src=/etc/hosts,dst=/etc/hosts,options=rbind:ro \
|
||||||
@@ -43,11 +43,11 @@ ExecStart=/usr/local/bin/k0s ctr -n hs-net run \
|
|||||||
--mount type=bind,src=/yizhisec/hs_net/conf,dst=/etc/hs_net,options=rbind:rw \
|
--mount type=bind,src=/yizhisec/hs_net/conf,dst=/etc/hs_net,options=rbind:rw \
|
||||||
hub.yizhisec.com/hybridscope/hsnet:release_2.1.0-std hs-net
|
hub.yizhisec.com/hybridscope/hsnet:release_2.1.0-std hs-net
|
||||||
|
|
||||||
|
# --cgroup host \
|
||||||
|
# --env RUSTFLAGS="-C target-cpu=nehalem" \
|
||||||
# 重启策略
|
# 重启策略
|
||||||
Restart=on-failure
|
Restart=always
|
||||||
RestartSec=5s
|
RestartSec=5s
|
||||||
StartLimitInterval=60s
|
|
||||||
StartLimitBurst=5
|
|
||||||
|
|
||||||
# 资源限制(按需调整)
|
# 资源限制(按需调整)
|
||||||
MemoryLimit=2G
|
MemoryLimit=2G
|
||||||
@@ -64,19 +64,291 @@ ExecStopPost=/usr/local/bin/k0s ctr -n hs-net container rm hs-net
|
|||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target`
|
WantedBy=multi-user.target`
|
||||||
|
_conf_out = `log:
|
||||||
|
level: info
|
||||||
|
controller:
|
||||||
|
protocol: https
|
||||||
|
registerHost: hs-gateway-register-controller
|
||||||
|
host: hs-gateway-controller
|
||||||
|
port: 443
|
||||||
|
tokenFilePath: /etc/yizhisec/token
|
||||||
|
registerRetry: 30
|
||||||
|
wg:
|
||||||
|
private_key: qPfOaNKrV11kzaGQiNQNyiu6wMQGUpIM+/xqboVAnng=
|
||||||
|
private_network: 246.0.0.1/8
|
||||||
|
listen_port: 23209
|
||||||
|
mtu: 1300
|
||||||
|
obf_key: 0
|
||||||
|
keep_alive: 61
|
||||||
|
tun_name: wg_tun
|
||||||
|
yosGuard:
|
||||||
|
host: __ip__
|
||||||
|
port: 7788
|
||||||
|
mqtt:
|
||||||
|
protocol: tls
|
||||||
|
host: mqtt.yizhisec.com
|
||||||
|
port: '443'
|
||||||
|
cert: /yizhisec/hs_net/conf/ssl/mqtt.client.crt
|
||||||
|
key: /yizhisec/hs_net/conf/ssl/mqtt.client.key
|
||||||
|
keep_alive: 60
|
||||||
|
paseto_key: TtKVnSzEHO3jRv/GWg3f5k3H1OVfMnPZ1Ke9E6MSCXk=
|
||||||
|
resource_server: hs-gateway-controller
|
||||||
|
dns_cache:
|
||||||
|
Address: 127.0.0.1:9028
|
||||||
|
gatewayVersionFile: /etc/yizhisec/gateway_version.json
|
||||||
|
lastVersion: null
|
||||||
|
workDir: /yizhisec/hs_net/workspace
|
||||||
|
eth_names: []
|
||||||
|
tag: ''
|
||||||
|
cluster_mock: ''
|
||||||
|
openobserve_uri: ''
|
||||||
|
tcp_mode_disable: false
|
||||||
|
`
|
||||||
|
_conf_in = `{
|
||||||
|
"LogLevel": "info",
|
||||||
|
"LogFile": "/yizhisec/hs_net/workspace/log/wireguard",
|
||||||
|
"DnsVirtNetwork": null,
|
||||||
|
"DnsVirtNetworkV6": null,
|
||||||
|
"Foreground": false,
|
||||||
|
"WithPprof": false,
|
||||||
|
"DnsCache": {
|
||||||
|
"Address": "127.0.0.1:9028"
|
||||||
|
},
|
||||||
|
"log": {
|
||||||
|
"level": "info"
|
||||||
|
},
|
||||||
|
"yosGuard": {
|
||||||
|
"host": "__ip__",
|
||||||
|
"port": 7788
|
||||||
|
},
|
||||||
|
"controller": {
|
||||||
|
"protocol": "https",
|
||||||
|
"host": "hs-gateway-controller",
|
||||||
|
"registerHost": "hs-gateway-register-controller",
|
||||||
|
"port": 443,
|
||||||
|
"registerRetry": 30,
|
||||||
|
"tokenFilePath": "/etc/yizhisec/token"
|
||||||
|
},
|
||||||
|
"wg": {
|
||||||
|
"private_key": "qPfOaNKrV11kzaGQiNQNyiu6wMQGUpIM+/xqboVAnng=",
|
||||||
|
"private_network": "246.0.0.1/8",
|
||||||
|
"listen_port": 23209,
|
||||||
|
"mtu": 1380,
|
||||||
|
"obf_key": 0,
|
||||||
|
"keep_alive": 60,
|
||||||
|
"tun_name": "wg_tun"
|
||||||
|
},
|
||||||
|
"mqtt": {
|
||||||
|
"protocol": "tls",
|
||||||
|
"host": "mqtt.yizhisec.com",
|
||||||
|
"port": 443,
|
||||||
|
"cert": "/yizhisec/hs_net/conf/ssl/mqtt.client.crt",
|
||||||
|
"key": "/yizhisec/hs_net/conf/ssl/mqtt.client.key",
|
||||||
|
"keep_alive": 60
|
||||||
|
},
|
||||||
|
"paseto_key": "TtKVnSzEHO3jRv/GWg3f5k3H1OVfMnPZ1Ke9E6MSCXk=",
|
||||||
|
"resource_server": "hs-gateway-controller",
|
||||||
|
"gatewayVersionFile": "/etc/yizhisec/gateway_version.json",
|
||||||
|
"lastVersion": null,
|
||||||
|
"workDir": "/yizhisec/hs_net/workspace",
|
||||||
|
"dns_cache": {
|
||||||
|
"Address": "127.0.0.1:9028"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
_url = "https://artifactory.yizhisec.com/artifactory/yizhisec-release/hs_net/release/2.1.0-std/package.tar.gz"
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
location = filepath.Join(opt.Cfg.Make.Dir, "dependency", "hs-net")
|
workdir = filepath.Join(m.workdir, "dependency", "hs_net")
|
||||||
)
|
)
|
||||||
|
|
||||||
if err = os.MkdirAll(location, 0755); err != nil {
|
logger.Info("☑️ MakeHSNet: 开始构建 hs-net, workdir = %s", workdir)
|
||||||
logger.Error("MakeHSNet: 创建目录失败s")
|
|
||||||
logger.Debug("MakeHSNet: 创建目录失败: %s", err.Error())
|
if err = os.MkdirAll(workdir, 0755); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 创建目录失败: %s", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Fatal("MakeHSNet: 构建 hs-net 失败!!!(怎么完善,怎么完善,怎么完善???)")
|
if err = archiver.DownloadAndExtract(ctx, _url, workdir); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 下载和解压失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// mv workdir/package/server workdir/
|
||||||
|
// mv workdir/package/server_aes workdir/
|
||||||
|
if err = os.Rename(filepath.Join(workdir, "package", "server"), filepath.Join(workdir, "server")); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 重命名文件失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = os.Rename(filepath.Join(workdir, "package", "server_aes"), filepath.Join(workdir, "server_aes")); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 重命名文件失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write down conf_out to server.conf
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "server.conf"), []byte(_conf_out), 0644); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 写入配置文件失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write down conf_in to conf/server.conf
|
||||||
|
if err = os.MkdirAll(filepath.Join(workdir, "conf", "ssl"), 0755); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 创建目录失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "conf", "server.conf"), []byte(_conf_in), 0644); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 写入配置文件失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write resource.SSLMQTTClientCrt
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "conf", "ssl", "mqtt.client.crt"), resource.SSLMQTTClientCrt, 0644); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 写入配置文件失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "conf", "ssl", "mqtt.client.key"), resource.SSLMQTTClientKey, 0644); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 写入配置文件失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// mkdir workspace
|
||||||
|
if err = os.MkdirAll(filepath.Join(workdir, "workspace"), 0755); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 创建目录失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// new empty file lastVersion.txt
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "lastVersion.txt"), []byte{}, 0644); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 创建空文件失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
imgName := "hub.yizhisec.com/hybridscope/hsnet:release_2.1.0-std"
|
||||||
|
imgPath := filepath.Join(workdir, "hs-net.tar")
|
||||||
|
logger.Debug("☑️ MakeHSNet: 构建镜像 %s 到 %s", imgName, imgPath)
|
||||||
|
if err = m.Image(ctx, imgName, WithImageSave(imgPath), WithImageForcePull(true)); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 构建镜像失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ MakeHSNet: 构建镜像 %s 到 %s 成功", imgName, imgPath)
|
||||||
|
|
||||||
|
// write hs-net.service
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "hs-net.service"), []byte(_service), 0644); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 写入服务文件失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// upsert.sh script
|
||||||
|
const _upsert = `#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Starting hs-net deployment..."
|
||||||
|
|
||||||
|
# 1. Copy token file
|
||||||
|
echo "Copying token file..."
|
||||||
|
mkdir -p /etc/yizhisec
|
||||||
|
cp ../../configmap/token /etc/yizhisec/token
|
||||||
|
echo "Token file copied successfully"
|
||||||
|
|
||||||
|
# 2. Get local IP address
|
||||||
|
echo "Detecting local IP address..."
|
||||||
|
LocalIP=$(ip route get 1.1.1.1 | grep -oP 'src \K\S+')
|
||||||
|
if [ -z "$LocalIP" ]; then
|
||||||
|
echo "Error: Failed to detect local IP address"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Local IP detected: $LocalIP"
|
||||||
|
|
||||||
|
# 3. Update /etc/hosts with required entries
|
||||||
|
echo "Updating /etc/hosts..."
|
||||||
|
for host in "hs-gateway-register-controller" "hs-gateway-controller" "mqtt.yizhisec.com"; do
|
||||||
|
if grep -q "$host" /etc/hosts; then
|
||||||
|
sed -i "/$host/d" /etc/hosts
|
||||||
|
fi
|
||||||
|
echo "$LocalIP $host" >> /etc/hosts
|
||||||
|
echo "Added: $LocalIP $host"
|
||||||
|
done
|
||||||
|
echo "/etc/hosts updated successfully"
|
||||||
|
|
||||||
|
# 4. Replace __ip__ in server.conf
|
||||||
|
echo "Updating server.conf..."
|
||||||
|
sed -i "s/__ip__/$LocalIP/g" server.conf
|
||||||
|
echo "server.conf updated successfully"
|
||||||
|
|
||||||
|
# 5. Replace __ip__ in conf/server.conf
|
||||||
|
echo "Updating conf/server.conf..."
|
||||||
|
sed -i "s/__ip__/$LocalIP/g" conf/server.conf
|
||||||
|
echo "conf/server.conf updated successfully"
|
||||||
|
|
||||||
|
# 6. Create /mnt/huge directory
|
||||||
|
echo "Creating /mnt/huge directory..."
|
||||||
|
mkdir -p /mnt/huge
|
||||||
|
echo "/mnt/huge directory created successfully"
|
||||||
|
|
||||||
|
# 7. Create workspace directories
|
||||||
|
echo "Creating workspace directories..."
|
||||||
|
mkdir -p /yizhisec/hs_net/workspace/log
|
||||||
|
mkdir -p /yizhisec/hs_net/conf
|
||||||
|
echo "Workspace directories created successfully"
|
||||||
|
|
||||||
|
# 8. Copy configuration files
|
||||||
|
echo "Copying configuration files..."
|
||||||
|
cp -r conf/* /yizhisec/hs_net/conf/
|
||||||
|
echo "Configuration files copied successfully"
|
||||||
|
|
||||||
|
# 9. Copy binaries based on CPU AVX support
|
||||||
|
echo "Detecting CPU AVX support..."
|
||||||
|
if grep -q avx /proc/cpuinfo; then
|
||||||
|
echo "AVX support detected, using server_aes"
|
||||||
|
cp server_aes /yizhisec/hs_net/server
|
||||||
|
chmod +x /yizhisec/hs_net/server
|
||||||
|
echo "server_aes copied to /yizhisec/hs_net/server with execute permission"
|
||||||
|
else
|
||||||
|
echo "AVX not supported, using server"
|
||||||
|
cp server /yizhisec/hs_net/server
|
||||||
|
chmod +x /yizhisec/hs_net/server
|
||||||
|
echo "server copied to /yizhisec/hs_net/server with execute permission"
|
||||||
|
fi
|
||||||
|
echo "Binary copied successfully"
|
||||||
|
|
||||||
|
# 10. Copy lastVersion.txt
|
||||||
|
echo "Copying lastVersion.txt..."
|
||||||
|
cp lastVersion.txt /yizhisec/hs_net/
|
||||||
|
echo "lastVersion.txt copied successfully"
|
||||||
|
|
||||||
|
# 11. Load container image
|
||||||
|
echo "Loading hs-net container image..."
|
||||||
|
k0s ctr -n hs-net images import hs-net.tar
|
||||||
|
echo "Container image loaded successfully"
|
||||||
|
|
||||||
|
# 12. Install and enable systemd service
|
||||||
|
echo "Installing hs-net systemd service..."
|
||||||
|
cp hs-net.service /etc/systemd/system/
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable hs-net.service
|
||||||
|
echo "hs-net service installed and enabled"
|
||||||
|
|
||||||
|
# 13. Start the service
|
||||||
|
echo "Starting hs-net service..."
|
||||||
|
systemctl restart hs-net.service
|
||||||
|
echo "hs-net service started successfully"
|
||||||
|
|
||||||
|
echo "hs-net deployment completed successfully!"
|
||||||
|
echo "You can check the service status with: systemctl status hs-net.service"
|
||||||
|
`
|
||||||
|
|
||||||
|
// Write upsert.sh
|
||||||
|
logger.Debug("☑️ MakeHSNet: 写入 upsert.sh 脚本...")
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "upsert.sh"), []byte(_upsert), 0755); err != nil {
|
||||||
|
logger.Debug("❌ MakeHSNet: 写入 upsert.sh 失败: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ MakeHSNet: 写入 upsert.sh 成功")
|
||||||
|
|
||||||
|
logger.Info("✅ MakeHSNet: 构建 hs-net 成功, workdir = %s", workdir)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type imageOpt struct {
|
type imageOpt struct {
|
||||||
@@ -32,9 +32,11 @@ func WithImageSave(filename string) ImageOpt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithImageForcePull() ImageOpt {
|
func WithImageForcePull(force bool) ImageOpt {
|
||||||
return func(o *imageOpt) {
|
return func(o *imageOpt) {
|
||||||
o.ForcePull = true
|
if force {
|
||||||
|
o.ForcePull = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,53 +109,11 @@ SAVE:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *maker) Images(ctx context.Context) error {
|
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"},
|
|
||||||
|
|
||||||
|
var images = []*model.Image{
|
||||||
{Name: "hub.yizhisec.com/external/alpine:3.22.2", Fallback: "", Save: "alpine.tar", Force: true},
|
{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: "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/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/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/client_server:latest", Fallback: "", Save: "app.client.tar", Force: true},
|
||||||
@@ -163,7 +123,7 @@ func (m *maker) Images(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, image := range images {
|
for _, image := range images {
|
||||||
image.Save = filepath.Join(opt.Cfg.Make.Dir, "dependency", "image", image.Save)
|
image.Save = filepath.Join(m.workdir, "dependency", "image", image.Save)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("☑️ 开始获取镜像(s)...")
|
logger.Info("☑️ 开始获取镜像(s)...")
|
||||||
@@ -173,10 +133,7 @@ func (m *maker) Images(ctx context.Context) error {
|
|||||||
opts := []ImageOpt{
|
opts := []ImageOpt{
|
||||||
WithImageFallback(image.Fallback),
|
WithImageFallback(image.Fallback),
|
||||||
WithImageSave(image.Save),
|
WithImageSave(image.Save),
|
||||||
}
|
WithImageForcePull(image.Force),
|
||||||
|
|
||||||
if image.Force {
|
|
||||||
opts = append(opts, WithImageForcePull())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("☑️ 获取镜像: %s", image.Name)
|
logger.Info("☑️ 获取镜像: %s", image.Name)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
func TestImage(t *testing.T) {
|
func TestImage(t *testing.T) {
|
||||||
logger.SetLogLevel(logger.LogLevelDebug)
|
logger.SetLogLevel(logger.LogLevelDebug)
|
||||||
m := NewMaker()
|
m := NewMaker("./x-data")
|
||||||
m.Image(t.Context(), "docker.io/nginx:1.29.3-alpine3.22",
|
m.Image(t.Context(), "docker.io/nginx:1.29.3-alpine3.22",
|
||||||
WithImageFallback("swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.29.3-alpine3.22"),
|
WithImageFallback("swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.29.3-alpine3.22"),
|
||||||
WithImageSave("/root/nginx.tar"),
|
WithImageSave("/root/nginx.tar"),
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
|
||||||
"yizhisec.com/hsv2/forge/pkg/resource"
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *maker) LessDNS(ctx context.Context) error {
|
func (m *maker) LessDNS(ctx context.Context) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
location = filepath.Join(opt.Cfg.Make.Dir, "dependency", "less-dns")
|
location = filepath.Join(m.workdir, "dependency", "less-dns")
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.Info("☑️ maker.LessDNS: 开始构建 less-dns...")
|
logger.Info("☑️ maker.LessDNS: 开始构建 less-dns...")
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
|
||||||
"yizhisec.com/hsv2/forge/pkg/downloader"
|
"yizhisec.com/hsv2/forge/pkg/downloader"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *maker) Longhorn(ctx context.Context, replica int) error {
|
func (m *maker) Longhorn(ctx context.Context, replica int) error {
|
||||||
@@ -24,18 +24,18 @@ persistence:
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
chartURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/charts/longhorn-1.10.0.tgz"
|
chartURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/charts/longhorn-1.10.0.tgz"
|
||||||
longhornDir = filepath.Join(opt.Cfg.Make.Dir, "dependency", "longhorn")
|
location = filepath.Join(m.workdir, "dependency", "longhorn")
|
||||||
chartFile = filepath.Join(longhornDir, "longhorn-1.10.0.tgz")
|
chartFile = filepath.Join(location, "longhorn-1.10.0.tgz")
|
||||||
valuesFile = filepath.Join(longhornDir, "values.yaml")
|
valuesFile = filepath.Join(location, "values.yaml")
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.Info("☑️ 开始准备 Longhorn 资源...")
|
logger.Info("☑️ 开始准备 Longhorn 资源...")
|
||||||
logger.Debug("下载地址: %s", chartURL)
|
logger.Debug("下载地址: %s", chartURL)
|
||||||
logger.Debug("目标目录: %s", longhornDir)
|
logger.Debug("目标目录: %s", location)
|
||||||
|
|
||||||
if err = os.MkdirAll(filepath.Join(opt.Cfg.Make.Dir, "dependency", "longhorn"), 0755); err != nil {
|
if err = os.MkdirAll(filepath.Join(m.workdir, "dependency", "longhorn"), 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +58,36 @@ persistence:
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var images = []*model.Image{
|
||||||
|
{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"},
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("MakeLonghorn: 开始获取镜像...")
|
||||||
|
for _, image := range images {
|
||||||
|
opts := []ImageOpt{
|
||||||
|
WithImageFallback(image.Fallback),
|
||||||
|
WithImageSave(filepath.Join(location, image.Save)),
|
||||||
|
WithImageForcePull(image.Force),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.Image(ctx, image.Name, opts...); err != nil {
|
||||||
|
logger.Error("❌ MakeLonghorn: 获取镜像失败: %s, 可以手动获取后重试", image.Name)
|
||||||
|
logger.Debug("❌ MakeLonghorn: 获取镜像失败: %s, %v", image.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debug("MakeLonghorn: 获取镜像成功!!!")
|
||||||
|
|
||||||
logger.Info("✅ 成功创建 longhorn 资源!!!")
|
logger.Info("✅ 成功创建 longhorn 资源!!!")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package maker
|
package maker
|
||||||
|
|
||||||
type maker struct{}
|
type maker struct {
|
||||||
|
workdir string
|
||||||
func NewMaker() *maker {
|
}
|
||||||
return &maker{}
|
|
||||||
|
func NewMaker(workdir string) *maker {
|
||||||
|
return &maker{workdir: workdir}
|
||||||
}
|
}
|
||||||
|
|||||||
62
internal/controller/maker/minio.go
Normal file
62
internal/controller/maker/minio.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
// todo, remake minio-init image
|
||||||
|
func (m *maker) Minio(ctx context.Context, storage string) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
location = filepath.Join(m.workdir, "dependency", "minio")
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Info("☑️ maker.Minio: 开始构建 minio 依赖, workdir = %s", location)
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.Minio: 构建工作目录, workdir = %s", location)
|
||||||
|
if err = os.MkdirAll(location, 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.Minio: 创建工作目录失败, workdir = %s, err = %v", location, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Minio: 创建工作目录成功, workdir = %s", location)
|
||||||
|
|
||||||
|
filename := filepath.Join(location, "minio.yaml")
|
||||||
|
logger.Debug("☑️ maker.Minio: 准备资源文件, filename = %s, storage = %s", filename, storage)
|
||||||
|
bs := []byte(fmt.Sprintf(resource.YAMLMinIO, storage))
|
||||||
|
if err = os.WriteFile(filename, bs, 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.Minio: 写入资源文件失败, filename = %s, err = %v", filename, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Minio: 准备资源文件成功, filename = %s", filename)
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.Minio: 开始获取所需镜像...")
|
||||||
|
var images = []*model.Image{
|
||||||
|
{Name: "hub.yizhisec.com/hybridscope/v3/minio-init:latest", Fallback: "", Save: "dep.minio-init.tar"},
|
||||||
|
{Name: "hub.yizhisec.com/external/minio:RELEASE.2025-03-12T18-04-18Z", Fallback: "", Save: "dep.minio.tar"},
|
||||||
|
}
|
||||||
|
for _, image := range images {
|
||||||
|
opts := []ImageOpt{
|
||||||
|
WithImageFallback(image.Fallback),
|
||||||
|
WithImageSave(filepath.Join(location, image.Save)),
|
||||||
|
WithImageForcePull(image.Force),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.Image(ctx, image.Name, opts...); err != nil {
|
||||||
|
logger.Error("❌ maker.Minio: 获取镜像失败: %s, 可以手动获取后重试", image.Name)
|
||||||
|
logger.Debug("❌ maker.Minio: 获取镜像失败: %s, %v", image.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Minio: 获取所需镜像成功!!!")
|
||||||
|
|
||||||
|
logger.Info("✅ maker.Minio: 构建 minio 依赖成功, workdir = %s", location)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
"yizhisec.com/hsv2/forge/pkg/downloader"
|
"yizhisec.com/hsv2/forge/pkg/downloader"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MysqlOpt func(*mysqlOpt)
|
type MysqlOpt func(*mysqlOpt)
|
||||||
@@ -30,7 +30,7 @@ func WithMySQLReplica(replica int) MysqlOpt {
|
|||||||
func WithMySQLStorage(storage string) MysqlOpt {
|
func WithMySQLStorage(storage string) MysqlOpt {
|
||||||
return func(o *mysqlOpt) {
|
return func(o *mysqlOpt) {
|
||||||
// validate Kubernetes storage size string (e.g., "50Gi", "100Mi")
|
// validate Kubernetes storage size string (e.g., "50Gi", "100Mi")
|
||||||
if matched, _ := regexp.MatchString(`^\d+(\.\d+)?[EPTGMK]i?$`, storage); matched {
|
if opt.StorageSizeReg.MatchString(storage) {
|
||||||
o.Storage = storage
|
o.Storage = storage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,14 +74,14 @@ spec:
|
|||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: %s
|
storage: %s
|
||||||
podSpec:
|
podSpec:
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: "250m"
|
cpu: "250m"
|
||||||
memory: "250Mi"
|
memory: "250Mi"
|
||||||
limits:
|
limits:
|
||||||
cpu: "2"
|
cpu: "2"
|
||||||
memory: "4Gi"
|
memory: "4Gi"
|
||||||
# affinity:
|
# affinity:
|
||||||
# podAntiAffinity:
|
# podAntiAffinity:
|
||||||
# requiredDuringSchedulingIgnoredDuringExecution: # 强制规则
|
# requiredDuringSchedulingIgnoredDuringExecution: # 强制规则
|
||||||
@@ -95,7 +95,6 @@ spec:
|
|||||||
# values: ["mysql-cluster"]
|
# values: ["mysql-cluster"]
|
||||||
# topologyKey: "kubernetes.io/hostname" # 确保不同节点
|
# topologyKey: "kubernetes.io/hostname" # 确保不同节点
|
||||||
---
|
---
|
||||||
|
|
||||||
apiVersion: mysql.presslabs.org/v1alpha1
|
apiVersion: mysql.presslabs.org/v1alpha1
|
||||||
kind: MysqlDatabase
|
kind: MysqlDatabase
|
||||||
metadata:
|
metadata:
|
||||||
@@ -118,9 +117,9 @@ spec:
|
|||||||
|
|
||||||
err error
|
err error
|
||||||
chartURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/charts/mysql-operator-0.6.3.tgz"
|
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")
|
location = filepath.Join(m.workdir, "dependency", "mysql")
|
||||||
chartFile = filepath.Join(mysqlDir, "mysql-operator-0.6.3.tgz")
|
chartFile = filepath.Join(location, "mysql-operator-0.6.3.tgz")
|
||||||
clusterFile = filepath.Join(mysqlDir, "cluster.yaml")
|
clusterFile = filepath.Join(location, "cluster.yaml")
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, fn := range opts {
|
for _, fn := range opts {
|
||||||
@@ -129,13 +128,13 @@ spec:
|
|||||||
|
|
||||||
logger.Info("☑️ 开始构建 MySQL 资源...")
|
logger.Info("☑️ 开始构建 MySQL 资源...")
|
||||||
|
|
||||||
if err = os.MkdirAll(mysqlDir, 0755); err != nil {
|
if err = os.MkdirAll(location, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
o.Password = base64.StdEncoding.EncodeToString([]byte(o.Password))
|
o.Password = base64.StdEncoding.EncodeToString([]byte(o.Password))
|
||||||
|
|
||||||
logger.Debug("正在下载 MySQL operator chart..., url = %s, dir = %s", chartURL, mysqlDir)
|
logger.Debug("正在下载 MySQL operator chart..., url = %s, dir = %s", chartURL, location)
|
||||||
if err = downloader.Download(
|
if err = downloader.Download(
|
||||||
ctx,
|
ctx,
|
||||||
chartURL,
|
chartURL,
|
||||||
@@ -158,6 +157,31 @@ spec:
|
|||||||
|
|
||||||
logger.Debug("✅ 成功创建 database.yaml")
|
logger.Debug("✅ 成功创建 database.yaml")
|
||||||
|
|
||||||
|
logger.Debug("☑️ MakeMysql: 开始获取所需镜像...")
|
||||||
|
|
||||||
|
var images = []*model.Image{
|
||||||
|
{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"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, image := range images {
|
||||||
|
opts := []ImageOpt{
|
||||||
|
WithImageFallback(image.Fallback),
|
||||||
|
WithImageSave(filepath.Join(location, image.Save)),
|
||||||
|
WithImageForcePull(image.Force),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.Image(ctx, image.Name, opts...); err != nil {
|
||||||
|
logger.Error("❌ MakeMysql: 获取镜像失败: %s, 可以手动获取后重试", image.Name)
|
||||||
|
logger.Debug("❌ MakeMysql: 获取镜像失败: %s, %v", image.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debug("✅ MakeMysql: 获取镜像成功!!!")
|
||||||
|
|
||||||
logger.Info("✅ MySQL 资源构建成功!!!")
|
logger.Info("✅ MySQL 资源构建成功!!!")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
147
internal/controller/maker/proxy.go
Normal file
147
internal/controller/maker/proxy.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/downloader"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *maker) Proxy(ctx context.Context) error {
|
||||||
|
const (
|
||||||
|
binURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv2/bin/caddy"
|
||||||
|
systemdSvc = `[Unit]
|
||||||
|
Description=YiZhiSec Caddy Reverse Proxy
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
ExecStart=/usr/local/bin/caddy run --config /etc/caddy/caddy.json
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
Nice=-20
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target`
|
||||||
|
)
|
||||||
|
|
||||||
|
location := filepath.Join(m.workdir, "dependency", "proxy")
|
||||||
|
|
||||||
|
logger.Info("☑️ maker.Proxy: 开始构建 caddy 反向代理...")
|
||||||
|
logger.Debug("☑️ maker.Proxy: 创建目录 %s", location)
|
||||||
|
if err := os.MkdirAll(location, 0755); err != nil {
|
||||||
|
logger.Debug("❌ maker.Proxy: 创建目录失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Proxy: 创建目录 %s 成功", location)
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.Proxy: 下载 caddy 二进制..., url = %s, dest = %s", binURL, filepath.Join(location, "caddy"))
|
||||||
|
if err := downloader.Download(
|
||||||
|
ctx,
|
||||||
|
binURL,
|
||||||
|
filepath.Join(location, "caddy"),
|
||||||
|
downloader.WithInsecureSkipVerify(),
|
||||||
|
downloader.WithFileMode(0755),
|
||||||
|
); err != nil {
|
||||||
|
logger.Debug("❌ maker.Proxy: 下载 caddy 失败, url = %s, err = %v", binURL, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Proxy: 下载 caddy 成功, url = %s", binURL)
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.Proxy: 写入 caddy.json 文件..., dest = %s", filepath.Join(location, "caddy.json"))
|
||||||
|
caddyConfig := model.CaddyConfig{
|
||||||
|
"apps": &model.CaddyApp{
|
||||||
|
Layer4: &model.CaddyLayer4{
|
||||||
|
Servers: map[string]*model.CaddyServer{
|
||||||
|
"proxy_8443": {
|
||||||
|
Listen: []string{":8443"},
|
||||||
|
Routes: []*model.CaddyRoute{
|
||||||
|
{
|
||||||
|
Handle: []*model.CaddyHandle{
|
||||||
|
{
|
||||||
|
Handler: "proxy",
|
||||||
|
Upstreams: []*model.CaddyUpstream{
|
||||||
|
{Dial: []string{"__ip_1__:32443"}},
|
||||||
|
{Dial: []string{"__ip_2__:32443"}},
|
||||||
|
},
|
||||||
|
HealthChecks: &model.CaddyHealthCheck{
|
||||||
|
Active: &model.CaddyActive{
|
||||||
|
Interval: "10s",
|
||||||
|
Timeout: "2s",
|
||||||
|
Port: 32443,
|
||||||
|
},
|
||||||
|
Passive: &model.CaddyPassive{
|
||||||
|
FailDuration: "30s",
|
||||||
|
MaxFails: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LoadBalancing: &model.CaddyLoadBalancing{
|
||||||
|
Selection: &model.CaddySelection{
|
||||||
|
Policy: "round_robin",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"proxy_443": {
|
||||||
|
Listen: []string{":443"},
|
||||||
|
Routes: []*model.CaddyRoute{
|
||||||
|
{
|
||||||
|
Handle: []*model.CaddyHandle{
|
||||||
|
{
|
||||||
|
Handler: "proxy",
|
||||||
|
Upstreams: []*model.CaddyUpstream{
|
||||||
|
{Dial: []string{"__ip_1__:31443"}},
|
||||||
|
{Dial: []string{"__ip_2__:31443"}},
|
||||||
|
},
|
||||||
|
HealthChecks: &model.CaddyHealthCheck{
|
||||||
|
Active: &model.CaddyActive{
|
||||||
|
Interval: "10s",
|
||||||
|
Timeout: "2s",
|
||||||
|
Port: 31443,
|
||||||
|
},
|
||||||
|
Passive: &model.CaddyPassive{
|
||||||
|
FailDuration: "30s",
|
||||||
|
MaxFails: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LoadBalancing: &model.CaddyLoadBalancing{
|
||||||
|
Selection: &model.CaddySelection{
|
||||||
|
Policy: "round_robin",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
bs, _ := json.MarshalIndent(caddyConfig, "", " ")
|
||||||
|
if err := os.WriteFile(filepath.Join(location, "caddy.json"), []byte(bs), 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.Proxy: 写入 Caddyfile 失败, dest = %s, err = %v", filepath.Join(location, "caddy.json"), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Proxy: 写入 Caddyfile 文件成功, dest = %s", filepath.Join(location, "caddy.json"))
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.Proxy: 写入 caddy.service 文件..., dest = %s", filepath.Join(location, "caddy.service"))
|
||||||
|
if err := os.WriteFile(filepath.Join(location, "caddy.service"), []byte(systemdSvc), 0644); err != nil {
|
||||||
|
logger.Debug("❌ maker.Proxy: 写入 caddy.service 失败, dest = %s, err = %v", filepath.Join(location, "caddy.service"), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Proxy: 写入 caddy.service 文件成功, dest = %s", filepath.Join(location, "caddy.service"))
|
||||||
|
|
||||||
|
logger.Info("✅ maker.Proxy: 构建 caddy 反向代理成功!!!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -5,11 +5,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
"yizhisec.com/hsv2/forge/internal/opt"
|
||||||
"yizhisec.com/hsv2/forge/pkg/downloader"
|
"yizhisec.com/hsv2/forge/pkg/downloader"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RedisOpt func(*redisOpt)
|
type RedisOpt func(*redisOpt)
|
||||||
@@ -38,7 +38,7 @@ func WithRedisPassword(password string) RedisOpt {
|
|||||||
|
|
||||||
func WithRedisStorage(storage string) RedisOpt {
|
func WithRedisStorage(storage string) RedisOpt {
|
||||||
return func(o *redisOpt) {
|
return func(o *redisOpt) {
|
||||||
if matched, _ := regexp.MatchString(`^\d+(\.\d+)?[EPTGMK]i?$`, storage); matched {
|
if opt.StorageSizeReg.MatchString(storage) {
|
||||||
o.Storage = storage
|
o.Storage = storage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,18 +91,18 @@ metrics:
|
|||||||
fn(o)
|
fn(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
redisDir := filepath.Join(opt.Cfg.Make.Dir, "dependency", "redis")
|
location := filepath.Join(m.workdir, "dependency", "redis")
|
||||||
chartFile := filepath.Join(redisDir, chartFilename)
|
chartFile := filepath.Join(location, chartFilename)
|
||||||
valuesFile := filepath.Join(redisDir, "values.yaml")
|
valuesFile := filepath.Join(location, "values.yaml")
|
||||||
|
|
||||||
logger.Info("☑️ maker.Redis: 开始构建 Redis 资源...")
|
logger.Info("☑️ maker.Redis: 开始构建 Redis 资源...")
|
||||||
logger.Debug("☑️ maker.Redis: 开始构建 Redis 资源..., opt = %#v", o)
|
logger.Debug("☑️ maker.Redis: 开始构建 Redis 资源..., opt = %#v", o)
|
||||||
logger.Debug("☑️ maker.Redis: 创建目录 %s", redisDir)
|
logger.Debug("☑️ maker.Redis: 创建目录 %s", location)
|
||||||
if err := os.MkdirAll(redisDir, 0755); err != nil {
|
if err := os.MkdirAll(location, 0755); err != nil {
|
||||||
logger.Debug("❌ maker.Redis: 创建目录失败: %v", err)
|
logger.Debug("❌ maker.Redis: 创建目录失败: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Debug("✅ maker.Redis: 创建目录 %s 成功", redisDir)
|
logger.Debug("✅ maker.Redis: 创建目录 %s 成功", location)
|
||||||
|
|
||||||
logger.Debug("☑️ maker.Redis: 下载 Redis chart..., url = %s, dest = %s", chartURL, chartFile)
|
logger.Debug("☑️ maker.Redis: 下载 Redis chart..., url = %s, dest = %s", chartURL, chartFile)
|
||||||
if err := downloader.Download(
|
if err := downloader.Download(
|
||||||
@@ -124,6 +124,14 @@ metrics:
|
|||||||
}
|
}
|
||||||
logger.Debug("✅ maker.Redis: 写入 values.yaml 文件成功, dest = %s", valuesFile)
|
logger.Debug("✅ maker.Redis: 写入 values.yaml 文件成功, dest = %s", valuesFile)
|
||||||
|
|
||||||
|
logger.Debug("☑️ maker.Redis: 开始获取镜像...")
|
||||||
|
img := &model.Image{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"}
|
||||||
|
if err := m.Image(ctx, img.Name, WithImageFallback(img.Fallback), WithImageSave(filepath.Join(location, img.Save))); err != nil {
|
||||||
|
logger.Debug("❌ maker.Redis: 获取镜像失败: %s, %v", img.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ maker.Redis: 获取镜像成功!!!")
|
||||||
|
|
||||||
logger.Info("✅ maker.Redis: 构建 Redis 资源成功!!!")
|
logger.Info("✅ maker.Redis: 构建 Redis 资源成功!!!")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
73
internal/controller/maker/registry.go
Normal file
73
internal/controller/maker/registry.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package maker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *maker) Registry(ctx context.Context, storage string) error {
|
||||||
|
const (
|
||||||
|
_registryToml = `
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".registry]
|
||||||
|
config_path = ""
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."10.96.123.45:80"]
|
||||||
|
endpoint = ["http://10.96.123.45:80"]
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".registry.configs]
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".registry.configs."10.96.123.45:80".tls]
|
||||||
|
insecure_skip_verify = true
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".registry.configs."10.96.123.45:80".auth]`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
location = filepath.Join(m.workdir, "dependency", "registry")
|
||||||
|
imgName = "docker.io/library/registry:2.8.3"
|
||||||
|
uiImgName = "docker.io/quiq/registry-ui:0.11.0"
|
||||||
|
imgFallback = "docker-mirror.yizhisec.com/library/registry:2.8.3"
|
||||||
|
uiImgFallback = "docker-mirror.yizhisec.com/quiq/registry-ui:0.11.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Info("☑️ 开始创建依赖: registry...")
|
||||||
|
|
||||||
|
logger.Debug("☑️ 创建 dir: %s ...", location)
|
||||||
|
if err = os.MkdirAll(location, 0755); err != nil {
|
||||||
|
logger.Debug("❌ 创建 dir %s 失败: %v", location, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
yamlFile := filepath.Join(location, "registry.yaml")
|
||||||
|
content := fmt.Sprintf(resource.YAMLRegistry, storage)
|
||||||
|
logger.Debug("写入 yaml 文件: %s ...", yamlFile)
|
||||||
|
if os.WriteFile(yamlFile, []byte(content), 0644); err != nil {
|
||||||
|
logger.Debug("❌ 写入 yaml 文件 %s 失败: %v", yamlFile, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("开始准备镜像...")
|
||||||
|
imgFile := filepath.Join(location, "registry.tar")
|
||||||
|
if err = m.Image(ctx, imgName, WithImageFallback(imgFallback), WithImageSave(imgFile)); err != nil {
|
||||||
|
logger.Debug("❌ 准备镜像 %s 失败: %v", imgName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
imgFile = filepath.Join(location, "registry-ui.tar")
|
||||||
|
if err = m.Image(ctx, uiImgName, WithImageFallback(uiImgFallback), WithImageSave(imgFile)); err != nil {
|
||||||
|
logger.Debug("❌ 准备镜像 %s 失败: %v", uiImgName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("写入 registry.toml 文件: %s ...", filepath.Join(location, "registry.toml"))
|
||||||
|
if os.WriteFile(filepath.Join(location, "registry.toml"), []byte(_registryToml), 0644); err != nil {
|
||||||
|
logger.Debug("❌ 写入 registry.toml 文件 %s 失败: %v", filepath.Join(location, "registry.toml"), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("✅ 创建依赖成功: registry!!!")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
212
internal/controller/maker/seafile.go
Normal file
212
internal/controller/maker/seafile.go
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
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/model"
|
||||||
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SeafileOpt func(*seafileOpt)
|
||||||
|
type seafileOpt struct {
|
||||||
|
DBHost string
|
||||||
|
DBPassword string
|
||||||
|
AdminEmail string
|
||||||
|
AdminPassword string
|
||||||
|
ServerHostname string
|
||||||
|
Storage string
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSeafileStorage(storage string) SeafileOpt {
|
||||||
|
return func(o *seafileOpt) {
|
||||||
|
if opt.StorageSizeReg.MatchString(storage) {
|
||||||
|
o.Storage = storage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSeafileDBHost(host string) SeafileOpt {
|
||||||
|
return func(o *seafileOpt) {
|
||||||
|
if o.DBHost == "" {
|
||||||
|
o.DBHost = host
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSeafileDBPassword(password string) SeafileOpt {
|
||||||
|
return func(o *seafileOpt) {
|
||||||
|
if o.DBPassword == "" {
|
||||||
|
o.DBPassword = password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSeafileAdminEmail(email string) SeafileOpt {
|
||||||
|
return func(o *seafileOpt) {
|
||||||
|
if opt.EmailReg.MatchString(email) {
|
||||||
|
o.AdminEmail = email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSeafileAdminPassword(password string) SeafileOpt {
|
||||||
|
return func(o *seafileOpt) {
|
||||||
|
if o.AdminPassword == "" {
|
||||||
|
o.AdminPassword = password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSeafileHostname(hostname string) SeafileOpt {
|
||||||
|
return func(o *seafileOpt) {
|
||||||
|
if o.ServerHostname == "" {
|
||||||
|
o.ServerHostname = hostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *maker) Seafile(ctx context.Context, opts ...SeafileOpt) error {
|
||||||
|
const (
|
||||||
|
_config = `
|
||||||
|
ControllerServer:
|
||||||
|
UserManagement: user-service.hsv2:9013
|
||||||
|
Database:
|
||||||
|
Mysql:
|
||||||
|
Address: %s:3306
|
||||||
|
DBName: backup_server
|
||||||
|
Password: %s
|
||||||
|
SeafileDBName: seafile_db
|
||||||
|
UserName: root
|
||||||
|
Log:
|
||||||
|
Dir: ./log
|
||||||
|
Level: 1
|
||||||
|
Name: hs_backup_seafile
|
||||||
|
SeafileServer:
|
||||||
|
Admin: %s
|
||||||
|
AdminPassword: %s
|
||||||
|
BackupDir: /seafile/backup_data
|
||||||
|
Host: seafile-service
|
||||||
|
Port: 80
|
||||||
|
StorageDir: /seafile/storage
|
||||||
|
Sentry:
|
||||||
|
DSN: https://fd7149f063c211eda2b50242ac15001c@sentry.yizhisec.com:13443/7
|
||||||
|
TracesSampleRate: 1
|
||||||
|
Web:
|
||||||
|
Host: 0.0.0.0
|
||||||
|
Mode: release
|
||||||
|
Port: 9027
|
||||||
|
WorkDir: /yizhisec/hs_backup_seafile/workspace
|
||||||
|
YosGuard:
|
||||||
|
Host: 172.17.0.1
|
||||||
|
Port: 7788`
|
||||||
|
_upsert = `#!/bin/bash
|
||||||
|
|
||||||
|
kubectl create configmap config-backup-seafile --namespace seafile --from-file=config.yml=./config.yml --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
kubectl create configmap nginx-seafile --namespace hsv2 --from-file=seafile.conf=./nginx.conf --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
kubectl apply -f deployment.yaml
|
||||||
|
kubectl rollout restart deployment backup-seafile-deployment -n seafile`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
o = &seafileOpt{
|
||||||
|
DBHost: "mysql-cluster-mysql-master.db-mysql",
|
||||||
|
DBPassword: "L0hMysql.",
|
||||||
|
AdminEmail: "admin@yizhisec.com",
|
||||||
|
AdminPassword: "asecret",
|
||||||
|
ServerHostname: "cloud.hybridscope.com",
|
||||||
|
Storage: "50Gi",
|
||||||
|
}
|
||||||
|
workdir = filepath.Join(m.workdir, "dependency", "seafile")
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, fn := range opts {
|
||||||
|
fn(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("☑️ maker.Seafile: 开始构建 seafile 依赖, dir = %s", workdir)
|
||||||
|
|
||||||
|
// 1. 准备工作目录
|
||||||
|
logger.Debug("☑️ make.Seafile: 准备工作目录: %s", workdir)
|
||||||
|
if err = os.MkdirAll(workdir, 0755); err != nil {
|
||||||
|
logger.Error("❌ make.Seafile: 准备工作目录: %s 失败, err = %v", workdir, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ make.Seafile: 准备工作目录: %s 成功", workdir)
|
||||||
|
|
||||||
|
// 2. seafile yaml
|
||||||
|
logger.Debug("☑️ make.Seafile: 准备 seafile yaml")
|
||||||
|
bs := []byte(fmt.Sprintf(resource.YAMLSeafile, o.DBHost, o.DBPassword, o.AdminEmail, o.AdminPassword, o.ServerHostname, o.Storage))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "seafile.yaml"), bs, 0644); err != nil {
|
||||||
|
logger.Error("❌ make.Seafile: 准备 seafile yaml: %s 失败, err = %v", filepath.Join(workdir, "seafile.yaml"), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ make.Seafile: 准备 seafile yaml 成功")
|
||||||
|
|
||||||
|
// 3. backup-seafile deployment
|
||||||
|
logger.Debug("☑️ make.Seafile: 准备 backup-seafile deployment")
|
||||||
|
bs = []byte(resource.YAMLBackupSeafile)
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "deployment.yaml"), bs, 0644); err != nil {
|
||||||
|
logger.Error("❌ make.Seafile: 准备 backup-seafile deployment: %s 失败, err = %v", filepath.Join(workdir, "deployment.yaml"), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ make.Seafile: 准备 backup-seafile deployment 成功")
|
||||||
|
|
||||||
|
// 4. config.yml
|
||||||
|
logger.Debug("☑️ make.Seafile: 准备 config.yml")
|
||||||
|
bs = []byte(fmt.Sprintf(_config, o.DBHost, o.DBPassword, o.AdminEmail, o.AdminPassword))
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "config.yml"), bs, 0644); err != nil {
|
||||||
|
logger.Error("❌ make.Seafile: 准备 config.yml: %s 失败, err = %v", filepath.Join(workdir, "config.yml"), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ make.Seafile: 准备 config.yml 成功")
|
||||||
|
|
||||||
|
// 5. seafile.conf
|
||||||
|
logger.Debug("☑️ make.Seafile: 准备 seafile.conf")
|
||||||
|
bs = resource.NGINXSeafile
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "seafile.conf"), bs, 0644); err != nil {
|
||||||
|
logger.Error("❌ make.Seafile: 准备 seafile.conf: %s 失败, err = %v", filepath.Join(workdir, "seafile.conf"), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ make.Seafile: 准备 seafile.conf 成功")
|
||||||
|
|
||||||
|
// 6. upsert.sh
|
||||||
|
logger.Debug("☑️ make.Seafile: 准备 upsert.sh")
|
||||||
|
bs = []byte(_upsert)
|
||||||
|
if err = os.WriteFile(filepath.Join(workdir, "upsert.sh"), bs, 0755); err != nil {
|
||||||
|
logger.Error("❌ make.Seafile: 准备 upsert.sh: %s 失败, err = %v", filepath.Join(workdir, "upsert.sh"), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("✅ make.Seafile: 准备 upsert.sh 成功")
|
||||||
|
|
||||||
|
// 7. prepare images
|
||||||
|
logger.Debug("☑️ make.Seafile: 准备 images")
|
||||||
|
imgDir := filepath.Join(m.workdir, "dependency", "image")
|
||||||
|
if err = os.MkdirAll(imgDir, 0755); err != nil {
|
||||||
|
logger.Error("❌ make.Seafile: 准备 images 目录: %s 失败, err = %v", imgDir, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var images = []*model.Image{
|
||||||
|
{Name: "hub.yizhisec.com/hybridscope/hs_backup_seafile:latest", Fallback: "", Save: "seafile.backup_seafile.tar", Force: true},
|
||||||
|
{Name: "hub.yizhisec.com/product/hybridscope/memcached:latest", Fallback: "", Save: "seafile.memcached.tar"},
|
||||||
|
{Name: "hub.yizhisec.com/product/hybridscope/seafile-mc:latest", Fallback: "", Save: "seafile.seafile_mc.tar"},
|
||||||
|
}
|
||||||
|
for _, img := range images {
|
||||||
|
img.Save = filepath.Join(imgDir, img.Save)
|
||||||
|
if err = m.Image(ctx, img.Name, WithImageSave(img.Save), WithImageForcePull(img.Force)); err != nil {
|
||||||
|
logger.Error("❌ make.Seafile: 准备 image: %s 失败, err = %v", img.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debug("✅ make.Seafile: 准备 images 成功")
|
||||||
|
|
||||||
|
logger.Info("✅ maker.Seafile: 构建 seafile 依赖成功!!!")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
"yizhisec.com/hsv2/forge/internal/opt"
|
|
||||||
"yizhisec.com/hsv2/forge/pkg/downloader"
|
"yizhisec.com/hsv2/forge/pkg/downloader"
|
||||||
"yizhisec.com/hsv2/forge/pkg/resource"
|
"yizhisec.com/hsv2/forge/pkg/resource"
|
||||||
)
|
)
|
||||||
@@ -17,32 +16,21 @@ type yosguardOpt struct{}
|
|||||||
|
|
||||||
func (m *maker) Yosguard(ctx context.Context, opts ...YosguardOpt) error {
|
func (m *maker) Yosguard(ctx context.Context, opts ...YosguardOpt) error {
|
||||||
const (
|
const (
|
||||||
configTemplate = `
|
_config = `
|
||||||
Web:
|
AsController: true
|
||||||
# default listen in docker0
|
AsGateway: false
|
||||||
Host: 172.17.0.1
|
|
||||||
Port: 7788
|
|
||||||
|
|
||||||
UUIDFilePath: /etc/yosguard/uuid
|
|
||||||
|
|
||||||
# 心跳间隔: 单位秒,默认为5
|
|
||||||
HeartbeatDuration: 5
|
|
||||||
|
|
||||||
# 控制器 yosguard 地址
|
|
||||||
ControllerServer:
|
ControllerServer:
|
||||||
Host: dasheng.zhsftech.debug
|
Host: dasheng.zhsftech.debug
|
||||||
Port: 443
|
Port: 443
|
||||||
|
|
||||||
# True: 作为控制器运行; False: 不作为控制器运行
|
|
||||||
AsController: true
|
|
||||||
|
|
||||||
# True: 作为网关运行; False: 不作为网关运行
|
|
||||||
AsGateway: false
|
|
||||||
|
|
||||||
Database:
|
Database:
|
||||||
SQLite:
|
SQLite:
|
||||||
DBPath: "/etc/yosguard/db/yosguard.db"
|
DBPath: /etc/yosguard/db/yosguard.db
|
||||||
SQLPath: "/etc/yosguard/db/create.sql"`
|
HeartbeatDuration: 5
|
||||||
|
UUIDFilePath: /etc/yosguard/uuid
|
||||||
|
Web:
|
||||||
|
Host: __ip__
|
||||||
|
Port: 7788
|
||||||
|
`
|
||||||
|
|
||||||
systemdService = `
|
systemdService = `
|
||||||
[Unit]
|
[Unit]
|
||||||
@@ -64,7 +52,7 @@ WantedBy=multi-user.target`
|
|||||||
binURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv2/bin/yosguard"
|
binURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv2/bin/yosguard"
|
||||||
)
|
)
|
||||||
|
|
||||||
location := filepath.Join(opt.Cfg.Make.Dir, "dependency", "yosguard")
|
location := filepath.Join(m.workdir, "dependency", "yosguard")
|
||||||
|
|
||||||
logger.Info("☑️ maker.Yosguard: 开始构建 yosguard...")
|
logger.Info("☑️ maker.Yosguard: 开始构建 yosguard...")
|
||||||
logger.Debug("☑️ maker.Yosguard: 创建目录 %s", location)
|
logger.Debug("☑️ maker.Yosguard: 创建目录 %s", location)
|
||||||
@@ -87,12 +75,12 @@ WantedBy=multi-user.target`
|
|||||||
}
|
}
|
||||||
logger.Debug("✅ maker.Yosguard: 下载 yosguard 成功, url = %s", binURL)
|
logger.Debug("✅ maker.Yosguard: 下载 yosguard 成功, url = %s", binURL)
|
||||||
|
|
||||||
logger.Debug("☑️ maker.Yosguard: 写入 config_template.yml 文件..., dest = %s", filepath.Join(location, "config_template.yml"))
|
logger.Debug("☑️ maker.Yosguard: 写入 config.yml 文件..., dest = %s", filepath.Join(location, "config.yml"))
|
||||||
if err := os.WriteFile(filepath.Join(location, "config_template.yml"), []byte(configTemplate), 0644); err != nil {
|
if err := os.WriteFile(filepath.Join(location, "config.yml"), []byte(_config), 0644); err != nil {
|
||||||
logger.Debug("❌ maker.Yosguard: 写入 config_template.yml 失败, dest = %s, err = %v", filepath.Join(location, "config_template.yml"), err)
|
logger.Debug("❌ maker.Yosguard: 写入 config.yml 失败, dest = %s, err = %v", filepath.Join(location, "config.yml"), err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Debug("✅ maker.Yosguard: 写入 config_template.yml 文件成功, dest = %s", filepath.Join(location, "config_template.yml"))
|
logger.Debug("✅ maker.Yosguard: 写入 config.yml 文件成功, dest = %s", filepath.Join(location, "config.yml"))
|
||||||
|
|
||||||
logger.Debug("☑️ maker.Yosguard: 写入 create.sql 文件..., dest = %s", filepath.Join(location, "create.sql"))
|
logger.Debug("☑️ maker.Yosguard: 写入 create.sql 文件..., dest = %s", filepath.Join(location, "create.sql"))
|
||||||
if err := os.WriteFile(filepath.Join(location, "create.sql"), resource.SQLYosguard, 0644); err != nil {
|
if err := os.WriteFile(filepath.Join(location, "create.sql"), resource.SQLYosguard, 0644); err != nil {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package opt
|
package opt
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Debug bool
|
Debug bool
|
||||||
Make struct {
|
Make struct {
|
||||||
@@ -11,3 +13,12 @@ type config struct {
|
|||||||
var (
|
var (
|
||||||
Cfg = &config{}
|
Cfg = &config{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultWorkdir = "/root/hsv2-installation"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
StorageSizeReg = regexp.MustCompile(`^\d+(\.\d+)?[EPTGMK]i?$`)
|
||||||
|
EmailReg = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
|
||||||
|
)
|
||||||
|
|||||||
5
main.go
5
main.go
@@ -5,10 +5,15 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"yizhisec.com/hsv2/forge/internal/cmd"
|
"yizhisec.com/hsv2/forge/internal/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
time.Local = time.FixedZone("CST", 8*60*60)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|||||||
648
pkg/imager/pull.go
Normal file
648
pkg/imager/pull.go
Normal file
@@ -0,0 +1,648 @@
|
|||||||
|
package imager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PullOption is a functional option for configuring image pull
|
||||||
|
type PullOption func(*pullOption)
|
||||||
|
|
||||||
|
type pullOption struct {
|
||||||
|
Proxy string // http or socks5 proxy
|
||||||
|
Rename string // pull image and rename it
|
||||||
|
PlainHTTP bool // use http instead of https
|
||||||
|
SkipTLSVerify bool // skip TLS certificate verification
|
||||||
|
Username string // registry username for authentication
|
||||||
|
Password string // registry password for authentication
|
||||||
|
RetryTimes int // retry times for sync/proxy registries, default is 3
|
||||||
|
RetryDelay time.Duration // delay between retries, default is 2 seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithProxy sets the proxy for pulling images
|
||||||
|
func WithProxy(proxy string) PullOption {
|
||||||
|
return func(o *pullOption) {
|
||||||
|
o.Proxy = proxy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRename sets a new name for the pulled image
|
||||||
|
func WithRename(name string) PullOption {
|
||||||
|
return func(o *pullOption) {
|
||||||
|
o.Rename = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPlainHTTP enables plain HTTP (no TLS)
|
||||||
|
func WithPlainHTTP() PullOption {
|
||||||
|
return func(o *pullOption) {
|
||||||
|
o.PlainHTTP = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSkipTLSVerify skips TLS certificate verification
|
||||||
|
func WithSkipTLSVerify() PullOption {
|
||||||
|
return func(o *pullOption) {
|
||||||
|
o.SkipTLSVerify = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAuth sets authentication credentials
|
||||||
|
func WithAuth(username, password string) PullOption {
|
||||||
|
return func(o *pullOption) {
|
||||||
|
o.Username = username
|
||||||
|
o.Password = password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRetry sets the retry times for pulling images
|
||||||
|
func WithRetry(times int) PullOption {
|
||||||
|
return func(o *pullOption) {
|
||||||
|
if times < 0 {
|
||||||
|
times = 0
|
||||||
|
}
|
||||||
|
o.RetryTimes = times
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRetryDelay sets the delay between retries
|
||||||
|
func WithRetryDelay(delay time.Duration) PullOption {
|
||||||
|
return func(o *pullOption) {
|
||||||
|
o.RetryDelay = delay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// manifestV2 represents Docker manifest v2 schema
|
||||||
|
type manifestV2 struct {
|
||||||
|
SchemaVersion int `json:"schemaVersion"`
|
||||||
|
MediaType string `json:"mediaType"`
|
||||||
|
Config struct {
|
||||||
|
MediaType string `json:"mediaType"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Digest string `json:"digest"`
|
||||||
|
} `json:"config"`
|
||||||
|
Layers []struct {
|
||||||
|
MediaType string `json:"mediaType"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Digest string `json:"digest"`
|
||||||
|
} `json:"layers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// imageReference parses image reference into registry, repository, and tag
|
||||||
|
type imageReference struct {
|
||||||
|
Registry string
|
||||||
|
Repository string
|
||||||
|
Tag string
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseImageReference parses an image name into its components
|
||||||
|
func parseImageReference(name string) (*imageReference, error) {
|
||||||
|
ref := &imageReference{
|
||||||
|
Tag: "latest",
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, split by / to separate registry from repository
|
||||||
|
// This handles cases like localhost:5000/myimage:tag
|
||||||
|
slashParts := strings.SplitN(name, "/", 2)
|
||||||
|
|
||||||
|
var registryPart, repoPart string
|
||||||
|
|
||||||
|
if len(slashParts) == 1 {
|
||||||
|
// No slash, it's just image:tag (e.g., alpine:3.19)
|
||||||
|
repoPart = slashParts[0]
|
||||||
|
ref.Registry = "registry-1.docker.io"
|
||||||
|
} else {
|
||||||
|
// Has slash, check if first part is a registry
|
||||||
|
// Registry contains . or : (for host:port)
|
||||||
|
if strings.Contains(slashParts[0], ".") || strings.Contains(slashParts[0], ":") {
|
||||||
|
// First part is a registry
|
||||||
|
registryPart = slashParts[0]
|
||||||
|
repoPart = slashParts[1]
|
||||||
|
ref.Registry = registryPart
|
||||||
|
} else {
|
||||||
|
// First part is namespace (e.g., library/alpine)
|
||||||
|
repoPart = name
|
||||||
|
ref.Registry = "registry-1.docker.io"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now parse the repository and tag from repoPart
|
||||||
|
// Split on last : to get tag (in case repository name contains /)
|
||||||
|
lastColon := strings.LastIndex(repoPart, ":")
|
||||||
|
if lastColon > 0 {
|
||||||
|
ref.Repository = repoPart[:lastColon]
|
||||||
|
ref.Tag = repoPart[lastColon+1:]
|
||||||
|
} else {
|
||||||
|
ref.Repository = repoPart
|
||||||
|
}
|
||||||
|
|
||||||
|
// For docker.io, add library/ prefix if no namespace
|
||||||
|
if ref.Registry == "registry-1.docker.io" && !strings.Contains(ref.Repository, "/") {
|
||||||
|
ref.Repository = "library/" + ref.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PullImage pulls an OCI image using HTTP requests and saves it as a tar archive
|
||||||
|
func PullImage(ctx context.Context, name string, store io.Writer, opts ...PullOption) error {
|
||||||
|
options := &pullOption{
|
||||||
|
RetryTimes: 3, // default retry times
|
||||||
|
RetryDelay: 2 * time.Second, // default retry delay
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Pulling image: %s with options: %+v", name, options)
|
||||||
|
|
||||||
|
// Parse image reference
|
||||||
|
ref, err := parseImageReference(name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse image reference: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Parsed image reference: registry=%s, repository=%s, tag=%s", ref.Registry, ref.Repository, ref.Tag)
|
||||||
|
|
||||||
|
// Create HTTP client
|
||||||
|
client := createHTTPClient(options)
|
||||||
|
|
||||||
|
// Retry logic for sync/proxy registries
|
||||||
|
var lastErr error
|
||||||
|
for attempt := 0; attempt <= options.RetryTimes; attempt++ {
|
||||||
|
if attempt > 0 {
|
||||||
|
logger.Debug("Retry attempt %d/%d for image: %s", attempt, options.RetryTimes, name)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-time.After(options.RetryDelay):
|
||||||
|
// Continue after delay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get auth token if needed
|
||||||
|
token, err := getAuthToken(ctx, client, ref, options)
|
||||||
|
if err != nil {
|
||||||
|
lastErr = fmt.Errorf("failed to get auth token: %w", err)
|
||||||
|
logger.Debug("Attempt %d failed: %v", attempt+1, lastErr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get manifest
|
||||||
|
manifest, err := getManifest(ctx, client, ref, token, options)
|
||||||
|
if err != nil {
|
||||||
|
lastErr = fmt.Errorf("failed to get manifest: %w", err)
|
||||||
|
logger.Debug("Attempt %d failed: %v", attempt+1, lastErr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Got manifest with %d layers", len(manifest.Layers))
|
||||||
|
|
||||||
|
// Download and create tar archive
|
||||||
|
if err := createImageTar(ctx, client, ref, manifest, token, store, name, options); err != nil {
|
||||||
|
lastErr = fmt.Errorf("failed to create image tar: %w", err)
|
||||||
|
logger.Debug("Attempt %d failed: %v", attempt+1, lastErr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success!
|
||||||
|
logger.Info("Successfully pulled image: %s", name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// All retries exhausted
|
||||||
|
if options.RetryTimes > 0 {
|
||||||
|
return fmt.Errorf("failed to pull image after %d retries: %w", options.RetryTimes+1, lastErr)
|
||||||
|
}
|
||||||
|
return lastErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// createHTTPClient creates an HTTP client with the given options
|
||||||
|
func createHTTPClient(options *pullOption) *http.Client {
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
// Configure TLS
|
||||||
|
if options.SkipTLSVerify {
|
||||||
|
transport := &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
}
|
||||||
|
client.Transport = transport
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure proxy
|
||||||
|
if options.Proxy != "" {
|
||||||
|
proxyURL, err := url.Parse(options.Proxy)
|
||||||
|
if err == nil {
|
||||||
|
if client.Transport == nil {
|
||||||
|
client.Transport = &http.Transport{}
|
||||||
|
}
|
||||||
|
if transport, ok := client.Transport.(*http.Transport); ok {
|
||||||
|
transport.Proxy = http.ProxyURL(proxyURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAuthToken gets authentication token from registry
|
||||||
|
func getAuthToken(ctx context.Context, client *http.Client, ref *imageReference, options *pullOption) (string, error) {
|
||||||
|
// Try to access registry API v2 to get auth challenge
|
||||||
|
scheme := "https"
|
||||||
|
if options.PlainHTTP {
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
apiURL := fmt.Sprintf("%s://%s/v2/", scheme, ref.Registry)
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", apiURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add basic auth if provided
|
||||||
|
if options.Username != "" && options.Password != "" {
|
||||||
|
req.SetBasicAuth(options.Username, options.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// If 200 OK, no auth needed
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for WWW-Authenticate header
|
||||||
|
authHeader := resp.Header.Get("WWW-Authenticate")
|
||||||
|
if authHeader == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse auth challenge
|
||||||
|
token, err := fetchToken(ctx, client, authHeader, ref, options)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchToken fetches authentication token from auth server
|
||||||
|
func fetchToken(ctx context.Context, client *http.Client, authHeader string, ref *imageReference, options *pullOption) (string, error) {
|
||||||
|
// Parse WWW-Authenticate header
|
||||||
|
// Format: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/alpine:pull"
|
||||||
|
if !strings.HasPrefix(authHeader, "Bearer ") {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
params := make(map[string]string)
|
||||||
|
parts := strings.Split(authHeader[7:], ",")
|
||||||
|
for _, part := range parts {
|
||||||
|
part = strings.TrimSpace(part)
|
||||||
|
idx := strings.Index(part, "=")
|
||||||
|
if idx > 0 {
|
||||||
|
key := part[:idx]
|
||||||
|
value := strings.Trim(part[idx+1:], "\"")
|
||||||
|
params[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
realm, ok := params["realm"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("no realm in auth header")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build token URL
|
||||||
|
tokenURL := realm
|
||||||
|
if service, ok := params["service"]; ok {
|
||||||
|
tokenURL += "?service=" + url.QueryEscape(service)
|
||||||
|
}
|
||||||
|
scope := fmt.Sprintf("repository:%s:pull", ref.Repository)
|
||||||
|
if params["scope"] != "" {
|
||||||
|
scope = params["scope"]
|
||||||
|
}
|
||||||
|
tokenURL += "&scope=" + url.QueryEscape(scope)
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", tokenURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add basic auth if provided
|
||||||
|
if options.Username != "" && options.Password != "" {
|
||||||
|
req.SetBasicAuth(options.Username, options.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return "", fmt.Errorf("failed to get token: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenResp struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenResp.Token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getManifest fetches the image manifest
|
||||||
|
func getManifest(ctx context.Context, client *http.Client, ref *imageReference, token string, options *pullOption) (*manifestV2, error) {
|
||||||
|
scheme := "https"
|
||||||
|
if options.PlainHTTP {
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
manifestURL := fmt.Sprintf("%s://%s/v2/%s/manifests/%s", scheme, ref.Registry, ref.Repository, ref.Tag)
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", manifestURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set accept headers for manifest v2 (add both types)
|
||||||
|
req.Header.Add("Accept", "application/vnd.docker.distribution.manifest.v2+json")
|
||||||
|
req.Header.Add("Accept", "application/vnd.oci.image.manifest.v1+json")
|
||||||
|
req.Header.Add("Accept", "application/vnd.docker.distribution.manifest.list.v2+json")
|
||||||
|
|
||||||
|
if token != "" {
|
||||||
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Fetching manifest from: %s", manifestURL)
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
logger.Debug("Manifest request failed: %s, body: %s", resp.Status, string(body))
|
||||||
|
return nil, fmt.Errorf("failed to get manifest: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType := resp.Header.Get("Content-Type")
|
||||||
|
logger.Debug("Manifest Content-Type: %s", contentType)
|
||||||
|
|
||||||
|
// Read response body
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a manifest list (multi-arch)
|
||||||
|
if strings.Contains(contentType, "manifest.list") || strings.Contains(contentType, "image.index") {
|
||||||
|
// Parse manifest list and select amd64/linux
|
||||||
|
var manifestList struct {
|
||||||
|
SchemaVersion int `json:"schemaVersion"`
|
||||||
|
Manifests []struct {
|
||||||
|
Digest string `json:"digest"`
|
||||||
|
Platform struct {
|
||||||
|
Architecture string `json:"architecture"`
|
||||||
|
OS string `json:"os"`
|
||||||
|
} `json:"platform"`
|
||||||
|
} `json:"manifests"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(body, &manifestList); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse manifest list: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Found manifest list with %d manifests", len(manifestList.Manifests))
|
||||||
|
|
||||||
|
// Find amd64/linux manifest
|
||||||
|
var targetDigest string
|
||||||
|
for _, m := range manifestList.Manifests {
|
||||||
|
logger.Debug("Checking manifest: arch=%s, os=%s, digest=%s",
|
||||||
|
m.Platform.Architecture, m.Platform.OS, m.Digest)
|
||||||
|
if m.Platform.Architecture == "amd64" && m.Platform.OS == "linux" {
|
||||||
|
targetDigest = m.Digest
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if targetDigest == "" && len(manifestList.Manifests) > 0 {
|
||||||
|
// Fallback to first manifest with known platform
|
||||||
|
for _, m := range manifestList.Manifests {
|
||||||
|
if m.Platform.Architecture != "unknown" && m.Platform.OS != "unknown" {
|
||||||
|
targetDigest = m.Digest
|
||||||
|
logger.Debug("Using fallback manifest: arch=%s, os=%s",
|
||||||
|
m.Platform.Architecture, m.Platform.OS)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if targetDigest == "" {
|
||||||
|
return nil, fmt.Errorf("no suitable manifest found in manifest list")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Selected manifest digest: %s", targetDigest)
|
||||||
|
// Fetch the actual manifest by digest
|
||||||
|
return getManifestByDigest(ctx, client, ref, targetDigest, token, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
var manifest manifestV2
|
||||||
|
if err := json.Unmarshal(body, &manifest); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse manifest: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Parsed manifest: schemaVersion=%d, config.digest=%s, layers=%d",
|
||||||
|
manifest.SchemaVersion, manifest.Config.Digest, len(manifest.Layers))
|
||||||
|
|
||||||
|
return &manifest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getManifestByDigest fetches a manifest by its digest
|
||||||
|
func getManifestByDigest(ctx context.Context, client *http.Client, ref *imageReference, digest, token string, options *pullOption) (*manifestV2, error) {
|
||||||
|
scheme := "https"
|
||||||
|
if options.PlainHTTP {
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
manifestURL := fmt.Sprintf("%s://%s/v2/%s/manifests/%s", scheme, ref.Registry, ref.Repository, digest)
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", manifestURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("Accept", "application/vnd.docker.distribution.manifest.v2+json")
|
||||||
|
req.Header.Add("Accept", "application/vnd.oci.image.manifest.v1+json")
|
||||||
|
|
||||||
|
if token != "" {
|
||||||
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("failed to get manifest by digest: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var manifest manifestV2
|
||||||
|
if err := json.Unmarshal(body, &manifest); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse manifest: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &manifest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createImageTar downloads layers and creates a Docker-compatible tar archive
|
||||||
|
func createImageTar(ctx context.Context, client *http.Client, ref *imageReference, manifest *manifestV2, token string, store io.Writer, imageName string, options *pullOption) error {
|
||||||
|
// Create tar writer
|
||||||
|
tw := tar.NewWriter(store)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
scheme := "https"
|
||||||
|
if options.PlainHTTP {
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download config blob
|
||||||
|
logger.Debug("Downloading config blob: %s", manifest.Config.Digest)
|
||||||
|
configBlob, err := downloadBlob(ctx, client, scheme, ref.Registry, ref.Repository, manifest.Config.Digest, token)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to download config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write config as json file
|
||||||
|
configFileName := strings.TrimPrefix(manifest.Config.Digest, "sha256:") + ".json"
|
||||||
|
if err := writeTarEntry(tw, configFileName, configBlob); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download and write each layer
|
||||||
|
var layerFiles []string
|
||||||
|
for i, layer := range manifest.Layers {
|
||||||
|
logger.Debug("Downloading layer %d/%d: %s", i+1, len(manifest.Layers), layer.Digest)
|
||||||
|
layerBlob, err := downloadBlob(ctx, client, scheme, ref.Registry, ref.Repository, layer.Digest, token)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to download layer %s: %w", layer.Digest, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
layerFileName := strings.TrimPrefix(layer.Digest, "sha256:") + "/layer.tar"
|
||||||
|
layerFiles = append(layerFiles, layerFileName)
|
||||||
|
|
||||||
|
if err := writeTarEntry(tw, layerFileName, layerBlob); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create manifest.json for Docker compatibility
|
||||||
|
if options.Rename != "" {
|
||||||
|
imageName = options.Rename
|
||||||
|
}
|
||||||
|
|
||||||
|
manifestJSON := []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"Config": configFileName,
|
||||||
|
"RepoTags": []string{imageName},
|
||||||
|
"Layers": layerFiles,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
manifestData, err := json.Marshal(manifestJSON)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeTarEntry(tw, "manifest.json", manifestData); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create repositories file (legacy)
|
||||||
|
repositories := make(map[string]map[string]string)
|
||||||
|
repositories[imageName] = map[string]string{ref.Tag: strings.TrimPrefix(manifest.Config.Digest, "sha256:")[:12]}
|
||||||
|
reposData, err := json.Marshal(repositories)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeTarEntry(tw, "repositories", reposData); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// downloadBlob downloads a blob from registry
|
||||||
|
func downloadBlob(ctx context.Context, client *http.Client, scheme, registry, repository, digest, token string) ([]byte, error) {
|
||||||
|
blobURL := fmt.Sprintf("%s://%s/v2/%s/blobs/%s", scheme, registry, repository, digest)
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", blobURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if token != "" {
|
||||||
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("failed to download blob: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if content is gzipped
|
||||||
|
var reader io.Reader = resp.Body
|
||||||
|
if resp.Header.Get("Content-Type") == "application/vnd.docker.image.rootfs.diff.tar.gzip" ||
|
||||||
|
strings.Contains(resp.Header.Get("Content-Encoding"), "gzip") {
|
||||||
|
gzReader, err := gzip.NewReader(resp.Body)
|
||||||
|
if err == nil {
|
||||||
|
defer gzReader.Close()
|
||||||
|
reader = gzReader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return io.ReadAll(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeTarEntry writes a file entry to tar archive
|
||||||
|
func writeTarEntry(tw *tar.Writer, name string, data []byte) error {
|
||||||
|
hdr := &tar.Header{
|
||||||
|
Name: name,
|
||||||
|
Mode: 0644,
|
||||||
|
Size: int64(len(data)),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := tw.Write(data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
429
pkg/imager/pull_test.go
Normal file
429
pkg/imager/pull_test.go
Normal file
@@ -0,0 +1,429 @@
|
|||||||
|
package imager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestPullImage_PublicImage tests pulling a public image from Docker Hub
|
||||||
|
func TestPullImage_PublicImage(t *testing.T) {
|
||||||
|
logger.SetLogLevel(logger.LogLevelDebug)
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Create temp directory for test output
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputFile := filepath.Join(tmpDir, "alpine.tar")
|
||||||
|
outputFile = "./redis.alpine.tar"
|
||||||
|
|
||||||
|
// Create output file
|
||||||
|
f, err := os.Create(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create output file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Pull alpine image (small and commonly available)
|
||||||
|
imageName := "docker-mirror.yizhisec.com/library/redis:alpine"
|
||||||
|
err = PullImage(ctx, imageName, f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to pull image %s: %v", imageName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify file was created and has content
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
t.Fatalf("failed to close file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to stat output file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Size() == 0 {
|
||||||
|
t.Error("output file is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Successfully pulled %s, size: %d bytes", imageName, info.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPullImage_WithRegistry tests pulling from a specific registry
|
||||||
|
func TestPullImage_WithRegistry(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputFile := filepath.Join(tmpDir, "nginx.tar")
|
||||||
|
|
||||||
|
f, err := os.Create(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create output file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Pull from docker.io with explicit registry
|
||||||
|
imageName := "docker.io/library/nginx:alpine"
|
||||||
|
err = PullImage(ctx, imageName, f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to pull image %s: %v", imageName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
t.Fatalf("failed to close file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to stat output file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Size() == 0 {
|
||||||
|
t.Error("output file is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Successfully pulled %s, size: %d bytes", imageName, info.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPullImage_WithRename tests pulling and renaming an image
|
||||||
|
func TestPullImage_WithRename(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputFile := filepath.Join(tmpDir, "renamed.tar")
|
||||||
|
|
||||||
|
f, err := os.Create(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create output file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
imageName := "alpine:3.19"
|
||||||
|
newName := "my-custom-alpine:latest"
|
||||||
|
|
||||||
|
err = PullImage(ctx, imageName, f, WithRename(newName))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to pull image %s: %v", imageName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
t.Fatalf("failed to close file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to stat output file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Size() == 0 {
|
||||||
|
t.Error("output file is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Successfully pulled %s and renamed to %s, size: %d bytes", imageName, newName, info.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPullImage_WithAuth tests pulling with authentication (skip if no credentials)
|
||||||
|
func TestPullImage_WithAuth(t *testing.T) {
|
||||||
|
// This test requires actual credentials, so it's skipped by default
|
||||||
|
t.Skip("Skipping authentication test - requires valid credentials")
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputFile := filepath.Join(tmpDir, "private.tar")
|
||||||
|
|
||||||
|
f, err := os.Create(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create output file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Replace with your private registry details
|
||||||
|
imageName := "your-registry.com/your-repo/your-image:tag"
|
||||||
|
username := "your-username"
|
||||||
|
password := "your-password"
|
||||||
|
|
||||||
|
err = PullImage(ctx, imageName, f, WithAuth(username, password))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to pull private image %s: %v", imageName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
t.Fatalf("failed to close file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to stat output file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Size() == 0 {
|
||||||
|
t.Error("output file is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Successfully pulled private image %s, size: %d bytes", imageName, info.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPullImage_WithRetry tests retry functionality
|
||||||
|
func TestPullImage_WithRetry(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputFile := filepath.Join(tmpDir, "retry.tar")
|
||||||
|
|
||||||
|
f, err := os.Create(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create output file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Pull with custom retry settings
|
||||||
|
imageName := "alpine:3.19"
|
||||||
|
err = PullImage(ctx, imageName, f,
|
||||||
|
WithRetry(5), // 5 retries
|
||||||
|
WithRetryDelay(1*time.Second), // 1 second delay
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to pull image %s: %v", imageName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
t.Fatalf("failed to close file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to stat output file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Size() == 0 {
|
||||||
|
t.Error("output file is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Successfully pulled %s with retry, size: %d bytes", imageName, info.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPullImage_WithZeroRetry tests with retry disabled
|
||||||
|
func TestPullImage_WithZeroRetry(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputFile := filepath.Join(tmpDir, "no-retry.tar")
|
||||||
|
|
||||||
|
f, err := os.Create(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create output file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Pull with retry disabled
|
||||||
|
imageName := "alpine:3.19"
|
||||||
|
err = PullImage(ctx, imageName, f, WithRetry(0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to pull image %s: %v", imageName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
t.Fatalf("failed to close file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to stat output file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Size() == 0 {
|
||||||
|
t.Error("output file is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Successfully pulled %s without retry, size: %d bytes", imageName, info.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPullImage_WithSkipTLSVerify tests pulling with TLS verification disabled
|
||||||
|
func TestPullImage_WithSkipTLSVerify(t *testing.T) {
|
||||||
|
// This test is for registries with self-signed certificates
|
||||||
|
t.Skip("Skipping TLS skip test - requires a registry with self-signed cert")
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputFile := filepath.Join(tmpDir, "insecure.tar")
|
||||||
|
|
||||||
|
f, err := os.Create(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create output file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
imageName := "your-insecure-registry.local/image:tag"
|
||||||
|
err = PullImage(ctx, imageName, f, WithSkipTLSVerify())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to pull image %s: %v", imageName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
t.Fatalf("failed to close file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to stat output file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Size() == 0 {
|
||||||
|
t.Error("output file is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Successfully pulled %s with TLS verification skipped, size: %d bytes", imageName, info.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestParseImageReference tests the image reference parsing logic
|
||||||
|
func TestParseImageReference(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
imageName string
|
||||||
|
wantRegistry string
|
||||||
|
wantRepository string
|
||||||
|
wantTag string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple image with tag",
|
||||||
|
imageName: "alpine:3.19",
|
||||||
|
wantRegistry: "registry-1.docker.io",
|
||||||
|
wantRepository: "library/alpine",
|
||||||
|
wantTag: "3.19",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "simple image without tag",
|
||||||
|
imageName: "alpine",
|
||||||
|
wantRegistry: "registry-1.docker.io",
|
||||||
|
wantRepository: "library/alpine",
|
||||||
|
wantTag: "latest",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "image with namespace",
|
||||||
|
imageName: "library/nginx:alpine",
|
||||||
|
wantRegistry: "registry-1.docker.io",
|
||||||
|
wantRepository: "library/nginx",
|
||||||
|
wantTag: "alpine",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom registry",
|
||||||
|
imageName: "hub.yizhisec.com/external/alpine:3.22.2",
|
||||||
|
wantRegistry: "hub.yizhisec.com",
|
||||||
|
wantRepository: "external/alpine",
|
||||||
|
wantTag: "3.22.2",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "docker.io explicit",
|
||||||
|
imageName: "docker.io/library/redis:8.2.2",
|
||||||
|
wantRegistry: "docker.io",
|
||||||
|
wantRepository: "library/redis",
|
||||||
|
wantTag: "8.2.2",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "registry with port",
|
||||||
|
imageName: "localhost:5000/myimage:v1.0",
|
||||||
|
wantRegistry: "localhost:5000",
|
||||||
|
wantRepository: "myimage",
|
||||||
|
wantTag: "v1.0",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "quay.io registry",
|
||||||
|
imageName: "quay.io/k0sproject/pause:3.10.1",
|
||||||
|
wantRegistry: "quay.io",
|
||||||
|
wantRepository: "k0sproject/pause",
|
||||||
|
wantTag: "3.10.1",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
ref, err := parseImageReference(tt.imageName)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("parseImageReference() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ref.Registry != tt.wantRegistry {
|
||||||
|
t.Errorf("parseImageReference() registry = %v, want %v", ref.Registry, tt.wantRegistry)
|
||||||
|
}
|
||||||
|
if ref.Repository != tt.wantRepository {
|
||||||
|
t.Errorf("parseImageReference() repository = %v, want %v", ref.Repository, tt.wantRepository)
|
||||||
|
}
|
||||||
|
if ref.Tag != tt.wantTag {
|
||||||
|
t.Errorf("parseImageReference() tag = %v, want %v", ref.Tag, tt.wantTag)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPullImage_ContextCancellation tests that context cancellation works
|
||||||
|
func TestPullImage_ContextCancellation(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputFile := filepath.Join(tmpDir, "cancelled.tar")
|
||||||
|
|
||||||
|
f, err := os.Create(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create output file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Cancel context immediately
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
imageName := "alpine:3.19"
|
||||||
|
err = PullImage(ctx, imageName, f)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error due to cancelled context, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Context cancellation correctly handled: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BenchmarkPullImage benchmarks image pulling performance
|
||||||
|
func BenchmarkPullImage(b *testing.B) {
|
||||||
|
ctx := context.Background()
|
||||||
|
tmpDir := b.TempDir()
|
||||||
|
|
||||||
|
imageName := "alpine:3.19"
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
outputFile := filepath.Join(tmpDir, "alpine_bench.tar")
|
||||||
|
f, err := os.Create(outputFile)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("failed to create output file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = PullImage(ctx, imageName, f)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("failed to pull image: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Close()
|
||||||
|
os.Remove(outputFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
55
pkg/model/caddy.go
Normal file
55
pkg/model/caddy.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type CaddyUpstream struct {
|
||||||
|
Dial []string `json:"dial"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyActive struct {
|
||||||
|
Interval string `json:"interval"`
|
||||||
|
Timeout string `json:"timeout"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyPassive struct {
|
||||||
|
MaxFails int `json:"max_fails"`
|
||||||
|
FailDuration string `json:"fail_duration"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyHealthCheck struct {
|
||||||
|
Active *CaddyActive `json:"active"`
|
||||||
|
Passive *CaddyPassive `json:"passive"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddySelection struct {
|
||||||
|
Policy string `json:"policy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyLoadBalancing struct {
|
||||||
|
Selection *CaddySelection `json:"selection"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyHandle struct {
|
||||||
|
Handler string `json:"handler"`
|
||||||
|
Upstreams []*CaddyUpstream `json:"upstreams"`
|
||||||
|
HealthChecks *CaddyHealthCheck `json:"health_checks"`
|
||||||
|
LoadBalancing *CaddyLoadBalancing `json:"load_balancing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyRoute struct {
|
||||||
|
Handle []*CaddyHandle `json:"handle"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyServer struct {
|
||||||
|
Listen []string `json:"listen"`
|
||||||
|
Routes []*CaddyRoute `json:"routes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyLayer4 struct {
|
||||||
|
Servers map[string]*CaddyServer `json:"servers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyApp struct {
|
||||||
|
Layer4 *CaddyLayer4 `json:"layer4"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyConfig map[string]*CaddyApp
|
||||||
8
pkg/model/image.go
Normal file
8
pkg/model/image.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
Name string
|
||||||
|
Fallback string
|
||||||
|
Save string
|
||||||
|
Force bool
|
||||||
|
}
|
||||||
58
pkg/model/vendor.go
Normal file
58
pkg/model/vendor.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type Vendor struct {
|
||||||
|
Name string
|
||||||
|
OEMUrl string
|
||||||
|
OEMDir string
|
||||||
|
AppFrontUserImageName string
|
||||||
|
AppFrontAdminImageName string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
vendorMap = map[string]*Vendor{
|
||||||
|
"standard": &Vendor{
|
||||||
|
Name: "Standard",
|
||||||
|
OEMUrl: "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem.tar.gz",
|
||||||
|
OEMDir: "oem",
|
||||||
|
AppFrontUserImageName: "hub.yizhisec.com/hybridscope/v2/front-user:latest",
|
||||||
|
AppFrontAdminImageName: "hub.yizhisec.com/build/hybirdscope/front/admin:latest",
|
||||||
|
},
|
||||||
|
"elink": &Vendor{
|
||||||
|
Name: "elink",
|
||||||
|
OEMUrl: "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem_csgElink.tar.gz",
|
||||||
|
OEMDir: "oem_csgElink",
|
||||||
|
AppFrontUserImageName: "hub.yizhisec.com/hybridscope/v2/front-user-elink:latest",
|
||||||
|
AppFrontAdminImageName: "hub.yizhisec.com/build/hybirdscope/front/admin:latest",
|
||||||
|
},
|
||||||
|
"noah": &Vendor{
|
||||||
|
Name: "noah",
|
||||||
|
OEMUrl: "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem_noah.tar.gz",
|
||||||
|
OEMDir: "oem_noah",
|
||||||
|
AppFrontUserImageName: "hub.yizhisec.com/hybridscope/v2/front-user:latest",
|
||||||
|
AppFrontAdminImageName: "hub.yizhisec.com/build/hybirdscope/front/admin:latest",
|
||||||
|
},
|
||||||
|
"heishuimeng": &Vendor{
|
||||||
|
Name: "heishuimeng",
|
||||||
|
OEMUrl: "https://artifactory.yizhisec.com/artifactory/yizhisec-release/oem/release/2.1.0-std/oem_heishuimeng.tar.gz",
|
||||||
|
OEMDir: "oem_heishuimeng",
|
||||||
|
AppFrontUserImageName: "hub.yizhisec.com/hybridscope/v2/front-user:latest",
|
||||||
|
AppFrontAdminImageName: "hub.yizhisec.com/build/hybirdscope/front/admin:latest",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetVendor(name string) *Vendor {
|
||||||
|
if vendor, ok := vendorMap[name]; ok {
|
||||||
|
return vendor
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVendorNames() []string {
|
||||||
|
names := make([]string, 0, len(vendorMap))
|
||||||
|
for name := range vendorMap {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
73
pkg/resource/nginx/caddy.json
Normal file
73
pkg/resource/nginx/caddy.json
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"layer4": {
|
||||||
|
"servers": {
|
||||||
|
"proxy_8443_tcp_backends": {
|
||||||
|
"listen": [":8443"],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "proxy",
|
||||||
|
"upstreams": [
|
||||||
|
{"dial": ["10.118.2.11:32443"]},
|
||||||
|
{"dial": ["10.118.2.12:32443"]}
|
||||||
|
],
|
||||||
|
"health_checks": {
|
||||||
|
"active": {
|
||||||
|
"interval": "5s",
|
||||||
|
"timeout": "2s",
|
||||||
|
"port": 32443
|
||||||
|
},
|
||||||
|
"passive": {
|
||||||
|
"max_fails": 1,
|
||||||
|
"fail_duration": "30s"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"load_balancing": {
|
||||||
|
"selection": {
|
||||||
|
"policy": "round_robin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"proxy_443_tcp_backends": {
|
||||||
|
"listen": [":443"],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "proxy",
|
||||||
|
"upstreams": [
|
||||||
|
{"dial": ["10.118.2.11:31443"]},
|
||||||
|
{"dial": ["10.118.2.12:31443"]}
|
||||||
|
],
|
||||||
|
"health_checks": {
|
||||||
|
"active": {
|
||||||
|
"interval": "5s",
|
||||||
|
"timeout": "2s",
|
||||||
|
"port": 31443
|
||||||
|
},
|
||||||
|
"passive": {
|
||||||
|
"max_fails": 1,
|
||||||
|
"fail_duration": "30s"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"load_balancing": {
|
||||||
|
"selection": {
|
||||||
|
"policy": "round_robin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
254
pkg/resource/nginx/client.conf
Normal file
254
pkg/resource/nginx/client.conf
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
upstream hs-client-server {
|
||||||
|
least_conn;
|
||||||
|
server client-service:9129 max_fails=3 fail_timeout=10s;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream hs-client-without-auth-server {
|
||||||
|
least_conn;
|
||||||
|
server client-service:9024 max_fails=3 fail_timeout=10s;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream hs-client-message-server {
|
||||||
|
least_conn;
|
||||||
|
server client-service:9025 max_fails=3 fail_timeout=10s;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl
|
||||||
|
proxy_protocol;
|
||||||
|
server_name hs-client-api-server hs.client.api.server;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/client.server.crt;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/client.server.key;
|
||||||
|
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_cache shared:MozSSL:10m;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
client_max_body_size 50M;
|
||||||
|
|
||||||
|
location /api/v2_2 {
|
||||||
|
proxy_pass http://u-api-service;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/pkg/archive {
|
||||||
|
proxy_pass http://u-api-service/api/v2_2/client/download/check;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/version {
|
||||||
|
proxy_pass http://u-api-service/api/v2_2/client/version;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://hs-client-server;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/ {
|
||||||
|
proxy_pass http://hs-client-without-auth-server;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/dl/ {
|
||||||
|
proxy_pass http://hs-client-without-auth-server;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v2/admin/ {
|
||||||
|
proxy_pass http://hs-client-message-server;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# location /app-store {
|
||||||
|
# auth_request /app-store-auth;
|
||||||
|
# rewrite ^/app-store(.*)$ $1 break;
|
||||||
|
# proxy_pass http://hs-resource-server:19980;
|
||||||
|
# proxy_http_version 1.1;
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
# proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
# proxy_read_timeout 300s;
|
||||||
|
# }
|
||||||
|
|
||||||
|
location /app-store-auth {
|
||||||
|
internal;
|
||||||
|
proxy_pass http://hs-client-server/auth$request_uri;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Content-Length "";
|
||||||
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
|
proxy_set_header X-Original-Method $request_method;
|
||||||
|
proxy_set_header X-Original-IP $remote_addr;
|
||||||
|
proxy_set_header Query-Data $http_query_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
# location /wm/api {
|
||||||
|
# proxy_pass http://hs-watermark-server;
|
||||||
|
# proxy_http_version 1.1;
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
# proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
# proxy_read_timeout 300s;
|
||||||
|
# }
|
||||||
|
|
||||||
|
location /static/config/ {
|
||||||
|
alias /static/config/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /static/resource/ {
|
||||||
|
alias /static/resource/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /user/avatar/ {
|
||||||
|
alias /static/avatar/;
|
||||||
|
add_header Cache-Control public;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl proxy_protocol;
|
||||||
|
server_name hs-client-update-server hs.client.update.server;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/client.server.crt;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/client.server.key;
|
||||||
|
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_cache shared:MozSSL:10m;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
client_max_body_size 50M;
|
||||||
|
|
||||||
|
location /api/v2_2 {
|
||||||
|
proxy_pass http://u-api-service;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/pkg/archive {
|
||||||
|
proxy_pass http://u-api-service/api/v2_2/client/download/check;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/pkg/archive/version {
|
||||||
|
proxy_pass http://u-api-service/api/v2_2/client/version;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/version {
|
||||||
|
proxy_pass http://u-api-service/api/v2_2/client/version;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /static/config/rc.json {
|
||||||
|
proxy_pass http://u-api-service/api/v2_2/client/rc/json?os=win;
|
||||||
|
}
|
||||||
|
|
||||||
|
# location = /api/v1/version {
|
||||||
|
# proxy_pass http://hs-client-without-auth-server;
|
||||||
|
# proxy_http_version 1.1;
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
# proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
# proxy_read_timeout 300s;
|
||||||
|
# }
|
||||||
|
|
||||||
|
location /api/v1/pkg {
|
||||||
|
proxy_pass http://hs-client-without-auth-server;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/dl/ {
|
||||||
|
proxy_pass http://hs-client-without-auth-server;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /user/avatar/ {
|
||||||
|
alias /static/avatar/;
|
||||||
|
expires 7d;
|
||||||
|
add_header Cache-Control public;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /static/config/ {
|
||||||
|
alias /static/config/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /static/resource/ {
|
||||||
|
alias /static/resource/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 9118 ssl
|
||||||
|
proxy_protocol;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/client.server.crt;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/client.server.key;
|
||||||
|
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_cache shared:MozSSL:10m;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
client_max_body_size 50M;
|
||||||
|
location = /api/v1/version {
|
||||||
|
proxy_pass http://hs-client-without-auth-server;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/pkg {
|
||||||
|
proxy_pass http://hs-client-without-auth-server;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/dl/ {
|
||||||
|
proxy_pass http://hs-client-without-auth-server;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
}
|
||||||
28
pkg/resource/nginx/client_pkg.conf
Normal file
28
pkg/resource/nginx/client_pkg.conf
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
user root;
|
||||||
|
worker_processes auto;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
log_format custom '$time_iso8601 - $remote_addr - $http_host - $status - $request_time - $request_method - $request_uri';
|
||||||
|
access_log /var/log/nginx/access.log custom;
|
||||||
|
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
|
||||||
|
location %s {
|
||||||
|
alias /data;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
213
pkg/resource/nginx/common.conf
Normal file
213
pkg/resource/nginx/common.conf
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
ssl_certificate /etc/nginx/ssl/web.server.crt;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/web.server.key;
|
||||||
|
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
ssl_dhparam /etc/nginx/ssl/ffdhe2048.txt;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
client_header_buffer_size 1k;
|
||||||
|
|
||||||
|
client_max_body_size 50M;
|
||||||
|
|
||||||
|
location = /token_auth {
|
||||||
|
internal;
|
||||||
|
proxy_pass http://hs-api/api/tokenauth;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_pass_request_body off;
|
||||||
|
proxy_set_header Content-Length "";
|
||||||
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /client/dl/android {
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
alias /static/client/android;
|
||||||
|
if ($arg_attname ~ "^(.+)") {
|
||||||
|
add_header Content-Disposition "attachment;filename*=utf-8''$arg_attname";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
location /client/dl/ {
|
||||||
|
# remove download client auth verify
|
||||||
|
# auth_request /token_auth;
|
||||||
|
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
alias /static/client/;
|
||||||
|
if ($arg_attname ~ "^(.+)") {
|
||||||
|
add_header Content-Disposition "attachment;filename*=utf-8''$arg_attname";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
location /user/avatar/ {
|
||||||
|
auth_request /token_auth;
|
||||||
|
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
alias /static/avatar/;
|
||||||
|
expires 7d;
|
||||||
|
add_header Cache-Control public;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /file/share/ {
|
||||||
|
auth_request /token_auth;
|
||||||
|
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
alias /static/share_file/;
|
||||||
|
if ($arg_attname ~ "^(.+)") {
|
||||||
|
add_header Content-Disposition "attachment;filename*=utf-8''$arg_attname";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
location /file/public/ {
|
||||||
|
auth_request /token_auth;
|
||||||
|
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
alias /static/public_folder/;
|
||||||
|
if ($arg_attname ~ "^(.+)") {
|
||||||
|
add_header Content-Disposition "attachment;filename*=utf-8''$arg_attname";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
location /file/clipboard/ {
|
||||||
|
auth_request /token_auth;
|
||||||
|
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
alias /static/clipboard_file/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /file/uploaded/ {
|
||||||
|
auth_request /token_auth;
|
||||||
|
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
alias /static/uploaded_files/;
|
||||||
|
if ($arg_attname ~ "^(.+)") {
|
||||||
|
add_header Content-Disposition "attachment;filename*=utf-8''$arg_attname";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
location /resource/update_log.csv {
|
||||||
|
auth_request /token_auth;
|
||||||
|
|
||||||
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
alias /static/resource/update_log.csv;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /resource/update_timestamp.txt {
|
||||||
|
auth_request /token_auth;
|
||||||
|
|
||||||
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
alias /static/resource/update_timestamp.txt;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /resource/ {
|
||||||
|
default_type application/octet-stream;
|
||||||
|
alias /static/resource/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://hs-api;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# location /network-disk {
|
||||||
|
# set $arg_token ''; # 声明 $arg_token 变量
|
||||||
|
# if ($args ~* "token=(.*?)(&|$)") {
|
||||||
|
# set $arg_token $1;
|
||||||
|
# }
|
||||||
|
# auth_request /token_auth;
|
||||||
|
# set $auth $http_authorization;
|
||||||
|
# if ($http_authorization = "") {
|
||||||
|
# set $auth "token $arg_authorization";
|
||||||
|
# }
|
||||||
|
# rewrite ^/network-disk(.*)$ $1 break;
|
||||||
|
# proxy_pass http://hs-resource-server:19980;
|
||||||
|
# proxy_http_version 1.1;
|
||||||
|
# proxy_set_header Authorization $auth;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# location /app-store {
|
||||||
|
# set $arg_token ''; # 声明 $arg_token 变量
|
||||||
|
# if ($args ~* "token=(.*?)(&|$)") {
|
||||||
|
# set $arg_token $1;
|
||||||
|
# }
|
||||||
|
# auth_request /app-store-auth;
|
||||||
|
# set $auth $http_authorization;
|
||||||
|
# if ($http_authorization = "") {
|
||||||
|
# set $auth "token $arg_authorization";
|
||||||
|
# }
|
||||||
|
# rewrite ^/app-store(.*)$ $1 break;
|
||||||
|
# proxy_pass http://hs-resource-server:19980;
|
||||||
|
# proxy_http_version 1.1;
|
||||||
|
# proxy_set_header Authorization $auth;
|
||||||
|
# }
|
||||||
|
|
||||||
|
location /app-store-auth {
|
||||||
|
internal;
|
||||||
|
set $hs_token $http_hs_token;
|
||||||
|
if ($hs_token = "") {
|
||||||
|
set $hs_token $arg_token;
|
||||||
|
}
|
||||||
|
proxy_set_header Hs-Token $hs_token;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Content-Length "";
|
||||||
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
|
proxy_set_header X-Original-Method $request_method;
|
||||||
|
proxy_set_header X-Original-IP $remote_addr;
|
||||||
|
proxy_set_header Query-Data $http_query_data;
|
||||||
|
|
||||||
|
proxy_pass http://hs-api/api$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 502 /502.json;
|
||||||
|
error_page 503 /503.json;
|
||||||
|
location /503.json {
|
||||||
|
return 503 '{"code": -2, "msg": "服务器未响应", "err": "hs-nginx err"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 504 /504.json;
|
||||||
|
location /504.json {
|
||||||
|
return 504 '{"code": -3, "msg": "服务器未响应", "err": "hs-nginx err"}';
|
||||||
|
}
|
||||||
|
error_page 497 301 =307 https://$http_host$request_uri;
|
||||||
|
error_page 401 @my_401;
|
||||||
|
error_page 403 @my_403;
|
||||||
|
error_page 404 @my_404;
|
||||||
|
error_page 502 @my_502;
|
||||||
|
|
||||||
|
location @my_401 {
|
||||||
|
default_type text/html;
|
||||||
|
return 401 '<!doctypehtml><html lang=en><meta charset=UTF-8><meta content="width=device-width,initial-scale=1"name=viewport><title>401</title><style>body{display:flex;flex-direction:column;align-items:center;justify-content:center}</style><h1>401 Unauthorized</h1>';
|
||||||
|
}
|
||||||
|
|
||||||
|
location @my_403 {
|
||||||
|
default_type text/html;
|
||||||
|
return 403 '<!doctypehtml><html lang=en><meta charset=UTF-8><meta content="width=device-width,initial-scale=1"name=viewport><title>403</title><style>body{display:flex;flex-direction:column;align-items:center;justify-content:center}</style><h1>403 Forbidden</h1>';
|
||||||
|
}
|
||||||
|
|
||||||
|
location @my_404 {
|
||||||
|
default_type text/html;
|
||||||
|
return 404 '<!doctypehtml><html lang=en><meta charset=UTF-8><meta content="width=device-width,initial-scale=1"name=viewport><title>404</title><style>body{display:flex;flex-direction:column;align-items:center;justify-content:center}</style><h1>404 Not_Found</h1>';
|
||||||
|
}
|
||||||
|
|
||||||
|
location @my_502 {
|
||||||
|
default_type text/html;
|
||||||
|
return 502 '<!doctypehtml><html lang=en><meta charset=UTF-8><meta content="width=device-width,initial-scale=1"name=viewport><title>502</title><style>body{display:flex;flex-direction:column;align-items:center;justify-content:center}</style><h1>502 Bad_Gateway</h1>';
|
||||||
|
}
|
||||||
75
pkg/resource/nginx/gateway.conf
Normal file
75
pkg/resource/nginx/gateway.conf
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
upstream hs-gateway-controller {
|
||||||
|
least_conn;
|
||||||
|
server gateway-service:9012 max_fails=3 fail_timeout=10s;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl proxy_protocol;
|
||||||
|
server_name hs-gateway-controller;
|
||||||
|
|
||||||
|
ssl_certificate /yizhisec/ssl/server.crt;
|
||||||
|
ssl_certificate_key /yizhisec/ssl/server.key;
|
||||||
|
ssl_client_certificate /yizhisec/ssl/ca.crt;
|
||||||
|
ssl_verify_client on;
|
||||||
|
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
|
||||||
|
ssl_dhparam /etc/nginx/ssl/ffdhe2048.txt;
|
||||||
|
|
||||||
|
# intermediate configuration
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
client_max_body_size 50M;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://hs-gateway-controller;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl proxy_protocol;
|
||||||
|
server_name hs-gateway-register-controller;
|
||||||
|
|
||||||
|
ssl_certificate /yizhisec/ssl/server.crt;
|
||||||
|
ssl_certificate_key /yizhisec/ssl/server.key;
|
||||||
|
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_cache shared:MozSSL:10m;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
ssl_dhparam /etc/nginx/ssl/ffdhe2048.txt;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
client_max_body_size 50M;
|
||||||
|
|
||||||
|
location = /api/v1/gateway/setting {
|
||||||
|
if ($request_method != POST ) {
|
||||||
|
return 502 '{"code": -1, "msg": "invalid request"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_pass http://hs-gateway-controller;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
pkg/resource/nginx/nginx.conf
Normal file
63
pkg/resource/nginx/nginx.conf
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
user root;
|
||||||
|
worker_processes auto;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream {
|
||||||
|
error_log /var/log/nginx/error.log error;
|
||||||
|
|
||||||
|
map $ssl_preread_server_name $backend {
|
||||||
|
mqtt.yizhisec.com 127.0.0.1:27443;
|
||||||
|
mqtt-yizhisec-com 127.0.0.1:27443;
|
||||||
|
default web;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream web {
|
||||||
|
server 127.0.0.1:443;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 27443 ssl proxy_protocol;
|
||||||
|
|
||||||
|
# ssl_session_timeout 10m;
|
||||||
|
ssl_certificate /etc/nginx/ssl/mqtt.server.crt;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/mqtt.server.key;
|
||||||
|
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
|
|
||||||
|
proxy_pass emqx-service.db-emqx:1883;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 23443;
|
||||||
|
proxy_pass $backend;
|
||||||
|
ssl_preread on;
|
||||||
|
proxy_protocol on;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
log_format custom '$time_iso8601 - $remote_addr - $http_host - $status - $request_time - $request_method - $request_uri';
|
||||||
|
access_log /var/log/nginx/access.log custom;
|
||||||
|
|
||||||
|
include /etc/nginx/sites-enabled/*.conf;
|
||||||
|
include mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
sendfile_max_chunk 512k;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_http_version 1.0;
|
||||||
|
gzip_min_length 1000;
|
||||||
|
gzip_comp_level 6;
|
||||||
|
gzip_disable msie6;
|
||||||
|
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/javascript text/xml application/xml application/rss+xml application/atom+xml;
|
||||||
|
|
||||||
|
keepalive_timeout 65;
|
||||||
|
}
|
||||||
81
pkg/resource/nginx/seafile.conf
Normal file
81
pkg/resource/nginx/seafile.conf
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
server {
|
||||||
|
listen 443 ssl proxy_protocol;
|
||||||
|
server_name seafile.yizhisec.com cloud.hybridscope.com seafile-yizhise-com cloud-hybridscope-com;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/client.server.crt;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/client.server.key;
|
||||||
|
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
ssl_trusted_certificate /etc/nginx/ssl/client.ca.crt;
|
||||||
|
ssl_client_certificate /etc/nginx/ssl/client.ca.crt;
|
||||||
|
ssl_verify_client on;
|
||||||
|
|
||||||
|
client_max_body_size 500M;
|
||||||
|
|
||||||
|
# location = /auth-sharing {
|
||||||
|
# internal;
|
||||||
|
# proxy_pass http://client-service:9129/api/auth-sharing;
|
||||||
|
# proxy_http_version 1.1;
|
||||||
|
# proxy_pass_request_body off;
|
||||||
|
# proxy_set_header Content-Length "";
|
||||||
|
# proxy_set_header X-Original-URI $request_uri;
|
||||||
|
# }
|
||||||
|
|
||||||
|
location /f/ {
|
||||||
|
rewrite ^(.+[^/])$ $1/ last; # 补上末尾的 /,避免重定向两次
|
||||||
|
# auth_request /auth-sharing;
|
||||||
|
# proxy_pass http://hs-openresty:13381;
|
||||||
|
proxy_pass http://seafile-service.seafile;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v1/ {
|
||||||
|
proxy_pass http://backup-seafile-service.seafile:9027;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api2/ {
|
||||||
|
# proxy_pass http://hs-resource-server:19980;
|
||||||
|
proxy_pass http://seafile-service.seafile;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v2.1/ {
|
||||||
|
# proxy_pass http://hs-resource-server:19980;
|
||||||
|
proxy_pass http://seafile-service.seafile;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /seafhttp/ {
|
||||||
|
# proxy_pass http://hs-resource-server:19980;
|
||||||
|
proxy_pass http://seafile-service.seafile;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
pkg/resource/nginx/user.conf
Normal file
17
pkg/resource/nginx/user.conf
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name hs-user-management-controller;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
client_max_body_size 50M;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://user-service:9013;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
}
|
||||||
157
pkg/resource/nginx/web.conf
Normal file
157
pkg/resource/nginx/web.conf
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
# upstream hs-backup-server {
|
||||||
|
# least_conn;
|
||||||
|
# server hs-backup-server:9349 max_fails=3 fail_timeout=10s;
|
||||||
|
# }
|
||||||
|
|
||||||
|
upstream hs-api {
|
||||||
|
server api-service:9002;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 9002;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://hs-api;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl default_server;
|
||||||
|
|
||||||
|
location /api/admin/ {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /oem {
|
||||||
|
proxy_pass http://oem-service;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/my/sys/client/installer {
|
||||||
|
proxy_pass http://u-api-service/api/v2_2/client/download/list;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/system/version {
|
||||||
|
proxy_pass http://u-api-service/api/v2_2/system/version;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v2_2/client {
|
||||||
|
proxy_pass http://u-api-service;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v2_2/system {
|
||||||
|
proxy_pass http://u-api-service;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://front-user-service;
|
||||||
|
}
|
||||||
|
|
||||||
|
include /etc/nginx/common/common.conf;
|
||||||
|
|
||||||
|
error_page 497 301 =307 https://$http_host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8443 ssl;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN"; # 或 "DENY"
|
||||||
|
add_header Content-Security-Policy "img-src * data:; frame-ancestors 'none';" always;
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies "none";
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
add_header X-Download-Options "noopen" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
|
location /api/system/version {
|
||||||
|
proxy_pass http://u-api-service/api/v2_2/system/version;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /oem {
|
||||||
|
proxy_pass http://oem-service;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# location /wm/ {
|
||||||
|
# alias /data/wm/;
|
||||||
|
# expires 30d;
|
||||||
|
# add_header Cache-Control public;
|
||||||
|
# }
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://front-admin-service;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/v2_1/user {
|
||||||
|
proxy_pass http://user-service:9013;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
include /etc/nginx/common/common.conf;
|
||||||
|
|
||||||
|
location /ws {
|
||||||
|
proxy_pass http://hs-api/ws;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# location /backup {
|
||||||
|
# proxy_pass http://hs-backup-server;
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
# proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
# proxy_read_timeout 300s;
|
||||||
|
# }
|
||||||
|
|
||||||
|
location /api/local/user/import/template {
|
||||||
|
auth_request /token_auth;
|
||||||
|
alias /static/resource/local_user_import_template.xlsx;
|
||||||
|
}
|
||||||
|
|
||||||
|
# location /wm/api {
|
||||||
|
# proxy_pass http://hs-watermark-server;
|
||||||
|
# proxy_http_version 1.1;
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
# proxy_set_header X-Real-IP $proxy_protocol_addr;
|
||||||
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
# proxy_read_timeout 300s;
|
||||||
|
# }
|
||||||
|
|
||||||
|
location @my_401 {
|
||||||
|
default_type text/html;
|
||||||
|
return 401 '<!doctypehtml><html lang=en><meta charset=UTF-8><meta content="width=device-width,initial-scale=1"name=viewport><title>401</title><style>body{display:flex;flex-direction:column;align-items:center;justify-content:center}</style><h1>401 Unauthorized</h1>';
|
||||||
|
}
|
||||||
|
|
||||||
|
location @my_403 {
|
||||||
|
default_type text/html;
|
||||||
|
return 403 '<!doctypehtml><html lang=en><meta charset=UTF-8><meta content="width=device-width,initial-scale=1"name=viewport><title>403</title><style>body{display:flex;flex-direction:column;align-items:center;justify-content:center}</style><h1>403 Forbidden</h1>';
|
||||||
|
}
|
||||||
|
|
||||||
|
location @my_404 {
|
||||||
|
default_type text/html;
|
||||||
|
return 404 '<!doctypehtml><html lang=en><meta charset=UTF-8><meta content="width=device-width,initial-scale=1"name=viewport><title>404</title><style>body{display:flex;flex-direction:column;align-items:center;justify-content:center}</style><h1>404 Not_Found</h1>';
|
||||||
|
}
|
||||||
|
|
||||||
|
location @my_502 {
|
||||||
|
default_type text/html;
|
||||||
|
return 502 '<!doctypehtml><html lang=en><meta charset=UTF-8><meta content="width=device-width,initial-scale=1"name=viewport><title>502</title><style>body{display:flex;flex-direction:column;align-items:center;justify-content:center}</style><h1>502 Bad_Gateway</h1>';
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 497 301 =307 https://$http_host$request_uri;
|
||||||
|
error_page 401 @my_401;
|
||||||
|
error_page 403 @my_403;
|
||||||
|
error_page 404 @my_404;
|
||||||
|
error_page 502 @my_502;
|
||||||
|
}
|
||||||
@@ -5,24 +5,132 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
//go:embed flannel.yaml
|
//go:embed yaml/registry.yaml
|
||||||
|
YAMLRegistry string
|
||||||
|
|
||||||
|
//go:embed yaml/flannel.yaml
|
||||||
YAMLFlannel string
|
YAMLFlannel string
|
||||||
|
|
||||||
//go:embed es.yaml
|
//go:embed yaml/es.yaml
|
||||||
YAMLES string
|
YAMLES string
|
||||||
|
|
||||||
//go:embed kibana.yaml
|
//go:embed yaml/kibana.yaml
|
||||||
YAMLKibana []byte
|
YAMLKibana []byte
|
||||||
|
|
||||||
//go:embed es.init.sh
|
//go:embed sh/es.init.sh
|
||||||
BashESInit []byte
|
BashESInit []byte
|
||||||
|
|
||||||
//go:embed emqx.yaml
|
//go:embed yaml/emqx.yaml
|
||||||
YAMLEMQX []byte
|
YAMLEMQX []byte
|
||||||
|
|
||||||
//go:embed yosguard.create.sql
|
//go:embed yaml/minio.yaml
|
||||||
|
YAMLMinIO string
|
||||||
|
|
||||||
|
//go:embed sql/yosguard.create.sql
|
||||||
SQLYosguard []byte
|
SQLYosguard []byte
|
||||||
|
|
||||||
//go:embed less-dns.yaml
|
//go:embed yaml/less-dns.yaml
|
||||||
YAMLLessDNS []byte
|
YAMLLessDNS []byte
|
||||||
|
|
||||||
|
//go:embed yaml/seafile.yaml
|
||||||
|
YAMLSeafile string
|
||||||
|
|
||||||
|
//go:embed yaml/backup-seafile.yaml
|
||||||
|
YAMLBackupSeafile string
|
||||||
|
|
||||||
|
//go:embed yaml/app.user.yaml
|
||||||
|
YAMLAppUser string
|
||||||
|
|
||||||
|
//go:embed yaml/app.gateway.yaml
|
||||||
|
YAMLAppGateway string
|
||||||
|
|
||||||
|
//go:embed yaml/app.client.yaml
|
||||||
|
YAMLAppClient string
|
||||||
|
|
||||||
|
//go:embed yaml/app.mie.api.yaml
|
||||||
|
YAMLAppMieAPI string
|
||||||
|
|
||||||
|
//go:embed yaml/app.mie.worker.yaml
|
||||||
|
YAMLAppMieWorker []byte
|
||||||
|
|
||||||
|
//go:embed yaml/app.mie.cron.yaml
|
||||||
|
YAMLAppMieCron []byte
|
||||||
|
|
||||||
|
//go:embed yaml/app.mie.sweeper.yaml
|
||||||
|
YAMLAppMieSweeper []byte
|
||||||
|
|
||||||
|
//go:embed yaml/app.oem.yaml
|
||||||
|
YAMLAppOEM string
|
||||||
|
|
||||||
|
//go:embed yaml/app.front.user.yaml
|
||||||
|
YAMLAppFrontUser string
|
||||||
|
|
||||||
|
//go:embed yaml/app.front.admin.yaml
|
||||||
|
YAMLAppFrontAdmin string
|
||||||
|
|
||||||
|
//go:embed yaml/app.nginx.yaml
|
||||||
|
YAMLAppNGINX string
|
||||||
|
|
||||||
|
//go:embed yaml/client.pkg.yaml
|
||||||
|
YAMLClientPKG string
|
||||||
|
|
||||||
|
//go:embed ssl/ca.crt
|
||||||
|
SSLCaCrt string
|
||||||
|
|
||||||
|
//go:embed ssl/client.server.crt
|
||||||
|
SSLClientServerCrt string
|
||||||
|
|
||||||
|
//go:embed ssl/client.server.key
|
||||||
|
SSLClientServerKey string
|
||||||
|
|
||||||
|
//go:embed ssl/ffdhe2048.txt
|
||||||
|
SSLFFDHE2048 string
|
||||||
|
|
||||||
|
//go:embed ssl/mqtt.server.crt
|
||||||
|
SSLMQTTServerCrt string
|
||||||
|
|
||||||
|
//go:embed ssl/mqtt.server.key
|
||||||
|
SSLMQTTServerKey string
|
||||||
|
|
||||||
|
//go:embed ssl/mqtt.client.crt
|
||||||
|
SSLMQTTClientCrt []byte
|
||||||
|
|
||||||
|
//go:embed ssl/mqtt.client.key
|
||||||
|
SSLMQTTClientKey []byte
|
||||||
|
|
||||||
|
//go:embed ssl/server.crt
|
||||||
|
SSLServerCrt string
|
||||||
|
|
||||||
|
//go:embed ssl/server.key
|
||||||
|
SSLServerKey string
|
||||||
|
|
||||||
|
//go:embed ssl/web.server.crt
|
||||||
|
SSLWebServerCrt string
|
||||||
|
|
||||||
|
//go:embed ssl/web.server.key
|
||||||
|
SSLWebServerKey string
|
||||||
|
|
||||||
|
//go:embed nginx/seafile.conf
|
||||||
|
NGINXSeafile []byte
|
||||||
|
|
||||||
|
//go:embed nginx/common.conf
|
||||||
|
NGINXCommon []byte
|
||||||
|
|
||||||
|
//go:embed nginx/gateway.conf
|
||||||
|
NGINXGateway []byte
|
||||||
|
|
||||||
|
//go:embed nginx/web.conf
|
||||||
|
NGINXWeb []byte
|
||||||
|
|
||||||
|
//go:embed nginx/client.conf
|
||||||
|
NGINXClient []byte
|
||||||
|
|
||||||
|
//go:embed nginx/nginx.conf
|
||||||
|
NGINXMain []byte
|
||||||
|
|
||||||
|
//go:embed nginx/user.conf
|
||||||
|
NGINXUser []byte
|
||||||
|
|
||||||
|
//go:embed nginx/client_pkg.conf
|
||||||
|
NGINXClientPKG string
|
||||||
)
|
)
|
||||||
|
|||||||
13
pkg/resource/ssl/ca.crt
Normal file
13
pkg/resource/ssl/ca.crt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB7zCCAZWgAwIBAgIUZvlcdld7K4q8gQ1iS7DCv8dAuAcwCgYIKoZIzj0EAwIw
|
||||||
|
TTELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vh
|
||||||
|
bmd6aG91MRYwFAYDVQQKDA1ZaVpoaSBSb290IENBMB4XDTIyMTIwMjEwMTMxNVoX
|
||||||
|
DTMyMTEyOTEwMTMxNVowTTELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9u
|
||||||
|
ZzESMBAGA1UEBwwJR3Vhbmd6aG91MRYwFAYDVQQKDA1ZaVpoaSBSb290IENBMFkw
|
||||||
|
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAu+EOUpD8tO1KA6MXkvjfo3iD5dEEezY
|
||||||
|
kRL+sM9uCB2jKDcMiq2QNa/GE1NRbgQ04fpwVcvJkeMKrlEQWdqCEKNTMFEwHQYD
|
||||||
|
VR0OBBYEFCJhDR/vXpS4Mlo1y5sk/XWloNR6MB8GA1UdIwQYMBaAFCJhDR/vXpS4
|
||||||
|
Mlo1y5sk/XWloNR6MA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIg
|
||||||
|
IPCDJQOAvuR1LcTc/1G0nmcZLJA8mk7PSpzc7dp7kO4CIQC41hyfKwEYkfvxthLR
|
||||||
|
f4vSt3qR8cz4cBaWaSJ9sZRHoQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
10
pkg/resource/ssl/client.server.crt
Normal file
10
pkg/resource/ssl/client.server.crt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBejCCASACAQEwCgYIKoZIzj0EAwIwTTELMAkGA1UEBhMCQ04xEjAQBgNVBAgM
|
||||||
|
CUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MRYwFAYDVQQKDA1ZaVpoaSBS
|
||||||
|
b290IENBMB4XDTIyMDcyNjA3MDUxOFoXDTMyMDcyMzA3MDUxOFowRTELMAkGA1UE
|
||||||
|
BhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MQ4w
|
||||||
|
DAYDVQQKDAVZaVpoaTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD01GbM70jdF
|
||||||
|
hKz1Mc8ZdZ0PbseeZFO6X5hRR6MpOXl0KKIhqmEFb6vIUk7putv2NPp+1ifLXx2+
|
||||||
|
4Gg6X7VP53QwCgYIKoZIzj0EAwIDSAAwRQIhAKCf/+9sG5Y2muvjAS92kRd3Cxwa
|
||||||
|
1JkEGsiSnc3KtuD9AiAPAc1yuZaQuv8oTct1xJZpPE3vgVbKhU/mP+O3dDIr2Q==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
8
pkg/resource/ssl/client.server.key
Normal file
8
pkg/resource/ssl/client.server.key
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
-----BEGIN EC PARAMETERS-----
|
||||||
|
BggqhkjOPQMBBw==
|
||||||
|
-----END EC PARAMETERS-----
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEICfD/l/g3ERF2gwJwQhC2bmIzeUWlyzizYpwlw9y19/1oAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEPTUZszvSN0WErPUxzxl1nQ9ux55kU7pfmFFHoyk5eXQooiGqYQVv
|
||||||
|
q8hSTum62/Y0+n7WJ8tfHb7gaDpftU/ndA==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
8
pkg/resource/ssl/ffdhe2048.txt
Normal file
8
pkg/resource/ssl/ffdhe2048.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
-----BEGIN DH PARAMETERS-----
|
||||||
|
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
|
||||||
|
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
|
||||||
|
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
|
||||||
|
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
|
||||||
|
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
|
||||||
|
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
|
||||||
|
-----END DH PARAMETERS-----
|
||||||
12
pkg/resource/ssl/mqtt.client.crt
Normal file
12
pkg/resource/ssl/mqtt.client.crt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBvDCCAWOgAwIBAgIBATAKBggqhkjOPQQDAjBNMQswCQYDVQQGEwJDTjESMBAG
|
||||||
|
A1UECAwJR3Vhbmdkb25nMRIwEAYDVQQHDAlHdWFuZ3pob3UxFjAUBgNVBAoMDVlp
|
||||||
|
WmhpIFJvb3QgQ0EwHhcNMjMxMjEwMTU0MzU0WhcNMzMxMjA3MTU0MzU0WjBhMQsw
|
||||||
|
CQYDVQQGEwJDTjESMBAGA1UECAwJR3Vhbmdkb25nMRIwEAYDVQQHDAlHdWFuZ3po
|
||||||
|
b3UxDjAMBgNVBAoMBVlpWmhpMRowGAYDVQQDDBFtcXR0Lnlpemhpc2VjLmNvbTBZ
|
||||||
|
MBMGByqGSM49AgEGCCqGSM49AwEHA0IABGOtQocjlPkUHD5opIt/V4tIQw0QSjJL
|
||||||
|
G9q+OkUEWil40ZNc9au3zbl78lZfZqiT92+s4qWSl0LNoLQEJ06WXxOjIDAeMBwG
|
||||||
|
A1UdEQQVMBOCEW1xdHQueWl6aGlzZWMuY29tMAoGCCqGSM49BAMCA0cAMEQCICOs
|
||||||
|
mhP29LIAuJJtYYsMwi21oGZlhI5pXVXu/R0VbLpDAiBvYkEq3A9UA5jRYwq2YXo4
|
||||||
|
fEbcPuEWU0LFZ6RN4dTebA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
8
pkg/resource/ssl/mqtt.client.key
Normal file
8
pkg/resource/ssl/mqtt.client.key
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
-----BEGIN EC PARAMETERS-----
|
||||||
|
BggqhkjOPQMBBw==
|
||||||
|
-----END EC PARAMETERS-----
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEICWabo6fxyjFq2CgDjLCvecNWLoNPWVxL5oM3ugG08NxoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEY61ChyOU+RQcPmiki39Xi0hDDRBKMksb2r46RQRaKXjRk1z1q7fN
|
||||||
|
uXvyVl9mqJP3b6zipZKXQs2gtAQnTpZfEw==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
12
pkg/resource/ssl/mqtt.server.crt
Normal file
12
pkg/resource/ssl/mqtt.server.crt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBvTCCAWOgAwIBAgIBATAKBggqhkjOPQQDAjBNMQswCQYDVQQGEwJDTjESMBAG
|
||||||
|
A1UECAwJR3Vhbmdkb25nMRIwEAYDVQQHDAlHdWFuZ3pob3UxFjAUBgNVBAoMDVlp
|
||||||
|
WmhpIFJvb3QgQ0EwHhcNMjMxMjEwMTUyNDM3WhcNMzMxMjA3MTUyNDM3WjBhMQsw
|
||||||
|
CQYDVQQGEwJDTjESMBAGA1UECAwJR3Vhbmdkb25nMRIwEAYDVQQHDAlHdWFuZ3po
|
||||||
|
b3UxDjAMBgNVBAoMBVlpWmhpMRowGAYDVQQDDBFtcXR0Lnlpemhpc2VjLmNvbTBZ
|
||||||
|
MBMGByqGSM49AgEGCCqGSM49AwEHA0IABPKwi96F+XaxPzOhkDkTCvcT/150GYJo
|
||||||
|
ExTvEFf0xfnmutDkkQw8RoQOe8AgExsxwXy75QgE5d3i7Igh4EJN2MSjIDAeMBwG
|
||||||
|
A1UdEQQVMBOCEW1xdHQueWl6aGlzZWMuY29tMAoGCCqGSM49BAMCA0gAMEUCICmm
|
||||||
|
3xfwGmdY8TOUFYJsTu1QyWnhLIl1zRPSEgKprPNEAiEAnaBn8Oq1qdx6K2PKAaT/
|
||||||
|
8Cad6JPsoBTxqW/QLYmp89o=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
8
pkg/resource/ssl/mqtt.server.key
Normal file
8
pkg/resource/ssl/mqtt.server.key
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
-----BEGIN EC PARAMETERS-----
|
||||||
|
BggqhkjOPQMBBw==
|
||||||
|
-----END EC PARAMETERS-----
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIPKnMTtmsu90SKIWpeW9OaxyKntsHDvGoP/JSIM/zMKHoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAE8rCL3oX5drE/M6GQORMK9xP/XnQZgmgTFO8QV/TF+ea60OSRDDxG
|
||||||
|
hA57wCATGzHBfLvlCATl3eLsiCHgQk3YxA==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
10
pkg/resource/ssl/server.crt
Normal file
10
pkg/resource/ssl/server.crt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBejCCASACAQEwCgYIKoZIzj0EAwIwTTELMAkGA1UEBhMCQ04xEjAQBgNVBAgM
|
||||||
|
CUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MRYwFAYDVQQKDA1ZaVpoaSBS
|
||||||
|
b290IENBMB4XDTIyMTIwMjEwMTMxNloXDTMyMTEyOTEwMTMxNlowRTELMAkGA1UE
|
||||||
|
BhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MQ4w
|
||||||
|
DAYDVQQKDAVZaVpoaTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNPLXfr++g44
|
||||||
|
7TROHOLF8BIoYM9UTzGCOTA4gDoAgYXkVs077fKLFAJKJH72mpMOw0laZUElmcCw
|
||||||
|
sBKKWLshyHQwCgYIKoZIzj0EAwIDSAAwRQIhALH9PCuZtfHAMZuDEanJOC7hf3BC
|
||||||
|
wPq2CXKG7lzHASLzAiAT6C/rlyN9IYYNiy0RXFsgDtsQQJy9RH6cPyvk/xh6eA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
8
pkg/resource/ssl/server.key
Normal file
8
pkg/resource/ssl/server.key
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
-----BEGIN EC PARAMETERS-----
|
||||||
|
BggqhkjOPQMBBw==
|
||||||
|
-----END EC PARAMETERS-----
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIDKTGdd21zcq4j2rbvTX4G7anjzBJdOgkvSu7uvj0oBZoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAE08td+v76DjjtNE4c4sXwEihgz1RPMYI5MDiAOgCBheRWzTvt8osU
|
||||||
|
Akokfvaakw7DSVplQSWZwLCwEopYuyHIdA==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
10
pkg/resource/ssl/web.server.crt
Normal file
10
pkg/resource/ssl/web.server.crt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBeTCCASACAQEwCgYIKoZIzj0EAwIwTTELMAkGA1UEBhMCQ04xEjAQBgNVBAgM
|
||||||
|
CUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MRYwFAYDVQQKDA1ZaVpoaSBS
|
||||||
|
b290IENBMB4XDTIyMDgyMTA4MjEzMloXDTMyMDgxODA4MjEzMlowRTELMAkGA1UE
|
||||||
|
BhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzESMBAGA1UEBwwJR3Vhbmd6aG91MQ4w
|
||||||
|
DAYDVQQKDAVZaVpoaTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOI4Fy+rT8ca
|
||||||
|
AuW390kWqhfqtv1a9+KISsESg/tuUiNYile3Tl7ndMzZmBJDlIOGXt8KcFc8t7kU
|
||||||
|
Lx/nUF3g4rcwCgYIKoZIzj0EAwIDRwAwRAIgFc6wgYlcdUoFtfZDEeW8a2xloUA3
|
||||||
|
HaPnkqCPZlKzwlACIARWSaWA64UTC+et/n3LZY9ZGWRatzxhhALToM33pewH
|
||||||
|
-----END CERTIFICATE-----
|
||||||
8
pkg/resource/ssl/web.server.key
Normal file
8
pkg/resource/ssl/web.server.key
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
-----BEGIN EC PARAMETERS-----
|
||||||
|
BggqhkjOPQMBBw==
|
||||||
|
-----END EC PARAMETERS-----
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIEu0E+YkAH+Qg7yuOpqh2w56JOgjzSuxqZl7uFQkpLAVoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAE4jgXL6tPxxoC5bf3SRaqF+q2/Vr34ohKwRKD+25SI1iKV7dOXud0
|
||||||
|
zNmYEkOUg4Ze3wpwVzy3uRQvH+dQXeDitw==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
71
pkg/resource/yaml/app.client.yaml
Normal file
71
pkg/resource/yaml/app.client.yaml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: client-deployment
|
||||||
|
namespace: hsv2
|
||||||
|
spec:
|
||||||
|
replicas: %d
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: client
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: client
|
||||||
|
spec:
|
||||||
|
topologySpreadConstraints:
|
||||||
|
- maxSkew: 1
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
whenUnsatisfiable: ScheduleAnyway
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: client
|
||||||
|
containers:
|
||||||
|
- name: client
|
||||||
|
image: hub.yizhisec.com/hybridscope/client_server:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
volumeMounts:
|
||||||
|
- name: ssl-pub-crt
|
||||||
|
mountPath: /etc/yizhisec/license/pub_key
|
||||||
|
subPath: pub_key
|
||||||
|
readOnly: true
|
||||||
|
- name: config-volume
|
||||||
|
mountPath: /etc/client_server/config.yml
|
||||||
|
subPath: config.yml
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: ssl-pub-crt
|
||||||
|
configMap:
|
||||||
|
name: ssl-pub-crt
|
||||||
|
items:
|
||||||
|
- key: pub_key
|
||||||
|
path: pub_key
|
||||||
|
- name: config-volume
|
||||||
|
configMap:
|
||||||
|
name: config-client
|
||||||
|
items:
|
||||||
|
- key: config.yml
|
||||||
|
path: config.yml
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: client-service
|
||||||
|
namespace: hsv2
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: client
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
name: web
|
||||||
|
port: 9129
|
||||||
|
targetPort: 9129
|
||||||
|
- protocol: TCP
|
||||||
|
name: web2
|
||||||
|
port: 9024
|
||||||
|
targetPort: 9024
|
||||||
|
- protocol: TCP
|
||||||
|
name: web-message
|
||||||
|
port: 9025
|
||||||
|
targetPort: 9025
|
||||||
|
type: ClusterIP
|
||||||
42
pkg/resource/yaml/app.front.admin.yaml
Normal file
42
pkg/resource/yaml/app.front.admin.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: front-admin-deployment
|
||||||
|
namespace: hsv2
|
||||||
|
spec:
|
||||||
|
replicas: %d
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: front-admin
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: front-admin
|
||||||
|
spec:
|
||||||
|
topologySpreadConstraints:
|
||||||
|
- maxSkew: 1
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
whenUnsatisfiable: ScheduleAnyway
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: front-admin
|
||||||
|
containers:
|
||||||
|
- name: front-admin
|
||||||
|
image: hub.yizhisec.com/build/hybirdscope/front/admin:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: front-admin-service
|
||||||
|
namespace: hsv2
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: front-admin
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
type: ClusterIP
|
||||||
42
pkg/resource/yaml/app.front.user.yaml
Normal file
42
pkg/resource/yaml/app.front.user.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: front-user-deployment
|
||||||
|
namespace: hsv2
|
||||||
|
spec:
|
||||||
|
replicas: %d
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: front-user
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: front-user
|
||||||
|
spec:
|
||||||
|
topologySpreadConstraints:
|
||||||
|
- maxSkew: 1
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
whenUnsatisfiable: ScheduleAnyway
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: front-user
|
||||||
|
containers:
|
||||||
|
- name: front-user
|
||||||
|
image: hub.yizhisec.com/hybridscope/v2/front-user:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: front-user-service
|
||||||
|
namespace: hsv2
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: front-user
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
type: ClusterIP
|
||||||
83
pkg/resource/yaml/app.gateway.yaml
Normal file
83
pkg/resource/yaml/app.gateway.yaml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: gateway-deployment
|
||||||
|
namespace: hsv2
|
||||||
|
spec:
|
||||||
|
replicas: %d
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: gateway
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: gateway
|
||||||
|
spec:
|
||||||
|
topologySpreadConstraints:
|
||||||
|
- maxSkew: 1
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
whenUnsatisfiable: ScheduleAnyway
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: gateway
|
||||||
|
containers:
|
||||||
|
- name: gateway
|
||||||
|
image: hub.yizhisec.com/hybridscope/gateway_controller:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
volumeMounts:
|
||||||
|
- name: config-volume
|
||||||
|
mountPath: /etc/gateway_controller/config.yml
|
||||||
|
subPath: config.yml
|
||||||
|
readOnly: true
|
||||||
|
- name: config-token
|
||||||
|
mountPath: /etc/yizhisec/token
|
||||||
|
subPath: token
|
||||||
|
readOnly: true
|
||||||
|
- name: ssl-client-crt
|
||||||
|
mountPath: /yizhisec/ssl/client.crt
|
||||||
|
subPath: client.crt
|
||||||
|
readOnly: true
|
||||||
|
- name: ssl-client-key
|
||||||
|
mountPath: /yizhisec/ssl/client.key
|
||||||
|
subPath: client.key
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: config-volume
|
||||||
|
configMap:
|
||||||
|
name: config-gateway
|
||||||
|
items:
|
||||||
|
- key: config.yml
|
||||||
|
path: config.yml
|
||||||
|
- name: config-token
|
||||||
|
configMap:
|
||||||
|
name: config-token
|
||||||
|
items:
|
||||||
|
- key: token
|
||||||
|
path: token
|
||||||
|
- name: ssl-client-crt
|
||||||
|
configMap:
|
||||||
|
name: ssl-client-crt
|
||||||
|
items:
|
||||||
|
- key: client.crt
|
||||||
|
path: client.crt
|
||||||
|
- name: ssl-client-key
|
||||||
|
configMap:
|
||||||
|
name: ssl-client-key
|
||||||
|
items:
|
||||||
|
- key: client.key
|
||||||
|
path: client.key
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: gateway-service
|
||||||
|
namespace: hsv2
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: gateway
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
name: gateway-api
|
||||||
|
port: 9012
|
||||||
|
targetPort: 9012
|
||||||
|
type: ClusterIP
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user