🎨 大部分的 make 指令
This commit is contained in:
225
pkg/archiver/archiver.go
Normal file
225
pkg/archiver/archiver.go
Normal file
@@ -0,0 +1,225 @@
|
||||
package archiver
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||
)
|
||||
|
||||
// Options defines options for downloading and extracting archives
|
||||
type Options struct {
|
||||
// InsecureSkipVerify skips TLS certificate verification (equivalent to wget --no-check-certificate)
|
||||
InsecureSkipVerify bool
|
||||
// HTTPClient allows providing a custom HTTP client
|
||||
HTTPClient *http.Client
|
||||
// OnProgress is called during extraction with the current file being extracted
|
||||
OnProgress func(filename string, index int, total int)
|
||||
// IsGzipped explicitly specifies whether the archive is gzip compressed
|
||||
// If nil, auto-detect based on file extension (.tar.gz, .tgz)
|
||||
IsGzipped *bool
|
||||
}
|
||||
|
||||
// Option is a functional option for configuring the archiver
|
||||
type Option func(*Options)
|
||||
|
||||
// WithInsecureSkipVerify skips TLS certificate verification
|
||||
func WithInsecureSkipVerify() Option {
|
||||
return func(o *Options) {
|
||||
o.InsecureSkipVerify = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPClient sets a custom HTTP client
|
||||
func WithHTTPClient(client *http.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.HTTPClient = client
|
||||
}
|
||||
}
|
||||
|
||||
// WithProgress sets a progress callback
|
||||
func WithProgress(callback func(filename string, index int, total int)) Option {
|
||||
return func(o *Options) {
|
||||
o.OnProgress = callback
|
||||
}
|
||||
}
|
||||
|
||||
// WithGzipCompression explicitly sets whether the archive is gzip compressed
|
||||
func WithGzipCompression(isGzipped bool) Option {
|
||||
return func(o *Options) {
|
||||
o.IsGzipped = &isGzipped
|
||||
}
|
||||
}
|
||||
|
||||
// DownloadAndExtract downloads a tar or tar.gz file from URL and extracts it to destDir
|
||||
// Supports both .tar and .tar.gz formats
|
||||
func DownloadAndExtract(ctx context.Context, url, destDir string, opts ...Option) error {
|
||||
options := &Options{
|
||||
InsecureSkipVerify: false,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(options)
|
||||
}
|
||||
|
||||
logger.Debug("开始下载和解压: %s -> %s", url, destDir)
|
||||
|
||||
// Create HTTP client
|
||||
client := options.HTTPClient
|
||||
if client == nil {
|
||||
client = &http.Client{}
|
||||
if options.InsecureSkipVerify {
|
||||
logger.Debug("TLS 证书验证已禁用")
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Download the file
|
||||
logger.Debug("发起 HTTP 请求: %s", url)
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
logger.Debug("创建请求失败: %v", err)
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Debug("下载失败: %v", err)
|
||||
return fmt.Errorf("failed to download: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
logger.Debug("HTTP 状态码异常: %d", resp.StatusCode)
|
||||
return fmt.Errorf("bad status: %s", resp.Status)
|
||||
}
|
||||
|
||||
logger.Debug("下载成功,准备解压")
|
||||
|
||||
// Determine if the file is gzipped
|
||||
var reader io.Reader = resp.Body
|
||||
var isGzipped bool
|
||||
|
||||
if options.IsGzipped != nil {
|
||||
// Explicitly specified by option
|
||||
isGzipped = *options.IsGzipped
|
||||
logger.Debug("压缩格式由选项指定: isGzipped=%v", isGzipped)
|
||||
} else {
|
||||
// Auto-detect based on file extension
|
||||
isGzipped = strings.HasSuffix(url, ".tar.gz") || strings.HasSuffix(url, ".tgz")
|
||||
logger.Debug("根据文件扩展名自动检测压缩格式: isGzipped=%v", isGzipped)
|
||||
}
|
||||
|
||||
if isGzipped {
|
||||
logger.Debug("使用 gzip 解压")
|
||||
gzReader, err := gzip.NewReader(resp.Body)
|
||||
if err != nil {
|
||||
logger.Debug("创建 gzip reader 失败: %v", err)
|
||||
return fmt.Errorf("failed to create gzip reader: %w", err)
|
||||
}
|
||||
defer gzReader.Close()
|
||||
reader = gzReader
|
||||
} else {
|
||||
logger.Debug("tar 格式(未压缩)")
|
||||
}
|
||||
|
||||
// Extract tar archive
|
||||
if err := extractTar(reader, destDir, options); err != nil {
|
||||
return fmt.Errorf("failed to extract tar: %w", err)
|
||||
}
|
||||
|
||||
logger.Debug("解压完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
// extractTar extracts a tar archive to the destination directory
|
||||
func extractTar(r io.Reader, destDir string, options *Options) error {
|
||||
tarReader := tar.NewReader(r)
|
||||
fileCount := 0
|
||||
totalFiles := 0
|
||||
|
||||
// First pass: count total files (optional, for progress reporting)
|
||||
// For now, we'll just extract directly
|
||||
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
logger.Debug("读取 tar 条目失败: %v", err)
|
||||
return fmt.Errorf("failed to read tar header: %w", err)
|
||||
}
|
||||
|
||||
target := filepath.Join(destDir, header.Name)
|
||||
logger.Debug("解压文件: %s", header.Name)
|
||||
|
||||
// Call progress callback if provided
|
||||
if options.OnProgress != nil {
|
||||
options.OnProgress(header.Name, fileCount, totalFiles)
|
||||
}
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
// Create directory
|
||||
if err := os.MkdirAll(target, os.FileMode(header.Mode)); err != nil {
|
||||
logger.Debug("创建目录失败 %s: %v", target, err)
|
||||
return fmt.Errorf("failed to create directory %s: %w", target, err)
|
||||
}
|
||||
|
||||
case tar.TypeReg:
|
||||
// Create regular file
|
||||
// Ensure parent directory exists
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
logger.Debug("创建父目录失败 %s: %v", filepath.Dir(target), err)
|
||||
return fmt.Errorf("failed to create parent directory: %w", err)
|
||||
}
|
||||
|
||||
outFile, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.FileMode(header.Mode))
|
||||
if err != nil {
|
||||
logger.Debug("创建文件失败 %s: %v", target, err)
|
||||
return fmt.Errorf("failed to create file %s: %w", target, err)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||
outFile.Close()
|
||||
logger.Debug("写入文件失败 %s: %v", target, err)
|
||||
return fmt.Errorf("failed to write file %s: %w", target, err)
|
||||
}
|
||||
outFile.Close()
|
||||
fileCount++
|
||||
|
||||
case tar.TypeSymlink:
|
||||
// Create symbolic link
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
logger.Debug("创建符号链接父目录失败 %s: %v", filepath.Dir(target), err)
|
||||
return fmt.Errorf("failed to create parent directory for symlink: %w", err)
|
||||
}
|
||||
|
||||
// Remove existing file/link if exists
|
||||
os.Remove(target)
|
||||
|
||||
if err := os.Symlink(header.Linkname, target); err != nil {
|
||||
logger.Debug("创建符号链接失败 %s -> %s: %v", target, header.Linkname, err)
|
||||
return fmt.Errorf("failed to create symlink %s -> %s: %w", target, header.Linkname, err)
|
||||
}
|
||||
fileCount++
|
||||
|
||||
default:
|
||||
logger.Debug("跳过不支持的文件类型: %s (type: %v)", header.Name, header.Typeflag)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debug("解压完成,共 %d 个文件", fileCount)
|
||||
return nil
|
||||
}
|
||||
47
pkg/archiver/archiver_test.go
Normal file
47
pkg/archiver/archiver_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package archiver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||
)
|
||||
|
||||
func TestDownloadAndExtract(t *testing.T) {
|
||||
logger.SetLogLevel(logger.LogLevelDebug)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Example: download and extract a tar.gz file
|
||||
err := DownloadAndExtract(
|
||||
ctx,
|
||||
"https://example.com/archive.tar.gz",
|
||||
"/tmp/test-extract",
|
||||
WithInsecureSkipVerify(),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Logf("Expected error for test URL: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadAndExtractWithProgress(t *testing.T) {
|
||||
logger.SetLogLevel(logger.LogLevelDebug)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Example: with progress callback
|
||||
err := DownloadAndExtract(
|
||||
ctx,
|
||||
"https://example.com/archive.tar",
|
||||
"/tmp/test-extract",
|
||||
WithInsecureSkipVerify(),
|
||||
WithProgress(func(filename string, index int, total int) {
|
||||
t.Logf("Extracting: %s", filename)
|
||||
}),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Logf("Expected error for test URL: %v", err)
|
||||
}
|
||||
}
|
||||
195
pkg/downloader/downloader.go
Normal file
195
pkg/downloader/downloader.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package downloader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||
)
|
||||
|
||||
// Options defines options for downloading files
|
||||
type Options struct {
|
||||
// InsecureSkipVerify skips TLS certificate verification
|
||||
InsecureSkipVerify bool
|
||||
// HTTPClient allows providing a custom HTTP client
|
||||
HTTPClient *http.Client
|
||||
// OnProgress is called during download with bytes downloaded and total size
|
||||
OnProgress func(downloaded, total int64)
|
||||
// CreateDirs automatically creates parent directories if they don't exist
|
||||
CreateDirs bool
|
||||
// Overwrite allows overwriting existing files
|
||||
Overwrite bool
|
||||
FileMode os.FileMode
|
||||
}
|
||||
|
||||
// Option is a functional option for configuring the downloader
|
||||
type Option func(*Options)
|
||||
|
||||
// WithInsecureSkipVerify skips TLS certificate verification
|
||||
func WithInsecureSkipVerify() Option {
|
||||
return func(o *Options) {
|
||||
o.InsecureSkipVerify = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPClient sets a custom HTTP client
|
||||
func WithHTTPClient(client *http.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.HTTPClient = client
|
||||
}
|
||||
}
|
||||
|
||||
// WithProgress sets a progress callback
|
||||
func WithProgress(callback func(downloaded, total int64)) Option {
|
||||
return func(o *Options) {
|
||||
o.OnProgress = callback
|
||||
}
|
||||
}
|
||||
|
||||
// WithoutCreateDirs disables automatic creation of parent directories
|
||||
func WithoutCreateDirs() Option {
|
||||
return func(o *Options) {
|
||||
o.CreateDirs = false
|
||||
}
|
||||
}
|
||||
|
||||
// WithoutOverwrite prevents overwriting existing files
|
||||
func WithoutOverwrite() Option {
|
||||
return func(o *Options) {
|
||||
o.Overwrite = false
|
||||
}
|
||||
}
|
||||
|
||||
func WithFileMode(mode os.FileMode) Option {
|
||||
return func(o *Options) {
|
||||
o.FileMode = mode
|
||||
}
|
||||
}
|
||||
|
||||
// Download downloads a file from URL to the specified destination
|
||||
func Download(ctx context.Context, url, dest string, opts ...Option) error {
|
||||
options := &Options{
|
||||
InsecureSkipVerify: false,
|
||||
CreateDirs: true,
|
||||
Overwrite: true,
|
||||
FileMode: 0644,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(options)
|
||||
}
|
||||
|
||||
logger.Debug("开始下载文件: %s -> %s", url, dest)
|
||||
|
||||
// Check if file exists and overwrite is disabled
|
||||
if !options.Overwrite {
|
||||
if _, err := os.Stat(dest); err == nil {
|
||||
logger.Debug("文件已存在且不允许覆盖: %s", dest)
|
||||
return fmt.Errorf("file already exists: %s", dest)
|
||||
}
|
||||
}
|
||||
|
||||
// Create parent directories if needed
|
||||
if options.CreateDirs {
|
||||
dir := filepath.Dir(dest)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
logger.Debug("创建目录失败 %s: %v", dir, err)
|
||||
return fmt.Errorf("failed to create directory: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create HTTP client
|
||||
client := options.HTTPClient
|
||||
if client == nil {
|
||||
client = &http.Client{}
|
||||
if options.InsecureSkipVerify {
|
||||
logger.Debug("TLS 证书验证已禁用")
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create HTTP request
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
logger.Debug("创建请求失败: %v", err)
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
// Execute request
|
||||
logger.Debug("发起 HTTP 请求: %s", url)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Debug("下载失败: %v", err)
|
||||
return fmt.Errorf("failed to download: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
logger.Debug("HTTP 状态码异常: %d", resp.StatusCode)
|
||||
return fmt.Errorf("bad status: %s", resp.Status)
|
||||
}
|
||||
|
||||
// Get content length for progress reporting
|
||||
contentLength := resp.ContentLength
|
||||
logger.Debug("文件大小: %d bytes", contentLength)
|
||||
|
||||
outFile, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, options.FileMode)
|
||||
if err != nil {
|
||||
logger.Debug("创建文件失败 %s: %v", dest, err)
|
||||
return fmt.Errorf("failed to create file: %w", err)
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
// Copy content with optional progress reporting
|
||||
var written int64
|
||||
if options.OnProgress != nil && contentLength > 0 {
|
||||
// Use progress reader
|
||||
reader := &progressReader{
|
||||
reader: resp.Body,
|
||||
callback: options.OnProgress,
|
||||
total: contentLength,
|
||||
}
|
||||
written, err = io.Copy(outFile, reader)
|
||||
} else {
|
||||
written, err = io.Copy(outFile, resp.Body)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.Debug("写入文件失败 %s: %v", dest, err)
|
||||
return fmt.Errorf("failed to write file: %w", err)
|
||||
}
|
||||
|
||||
if options.FileMode != 0 {
|
||||
if err := os.Chmod(dest, options.FileMode); err != nil {
|
||||
logger.Debug("设置文件权限失败 %s: %v", dest, err)
|
||||
return fmt.Errorf("failed to set file mode: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debug("文件下载成功: %s (%d bytes)", dest, written)
|
||||
return nil
|
||||
}
|
||||
|
||||
// progressReader wraps an io.Reader to report progress
|
||||
type progressReader struct {
|
||||
reader io.Reader
|
||||
callback func(downloaded, total int64)
|
||||
total int64
|
||||
downloaded int64
|
||||
}
|
||||
|
||||
func (pr *progressReader) Read(p []byte) (int, error) {
|
||||
n, err := pr.reader.Read(p)
|
||||
pr.downloaded += int64(n)
|
||||
if pr.callback != nil {
|
||||
pr.callback(pr.downloaded, pr.total)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
62
pkg/resource/emqx.yaml
Normal file
62
pkg/resource/emqx.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: db-emqx
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: emqx
|
||||
namespace: db-emqx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: emqx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: emqx
|
||||
spec:
|
||||
containers:
|
||||
- name: emqx
|
||||
image: hub.yizhisec.com/external/emqx:5.1
|
||||
ports:
|
||||
- containerPort: 1883
|
||||
name: mqtt
|
||||
- containerPort: 8883
|
||||
name: mqtt-ssl
|
||||
- containerPort: 18083
|
||||
name: dashboard
|
||||
- containerPort: 18084
|
||||
name: websocket
|
||||
env:
|
||||
- name: EMQX_NODE_NAME
|
||||
value: "emqx@single-node"
|
||||
- name: EMQX_DASHBOARD__DEFAULT_PASSWORD
|
||||
value: "YizhiSEC@123"
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: emqx-service
|
||||
namespace: db-emqx
|
||||
spec:
|
||||
selector:
|
||||
app: emqx
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: mqtt
|
||||
port: 1883
|
||||
targetPort: 1883
|
||||
- name: mqtt-ssl
|
||||
port: 8883
|
||||
targetPort: 8883
|
||||
- name: dashboard
|
||||
port: 18083
|
||||
targetPort: 18083
|
||||
- name: websocket
|
||||
port: 18084
|
||||
targetPort: 18084
|
||||
|
||||
1817
pkg/resource/es.init.sh
Normal file
1817
pkg/resource/es.init.sh
Normal file
File diff suppressed because it is too large
Load Diff
121
pkg/resource/es.yaml
Normal file
121
pkg/resource/es.yaml
Normal file
@@ -0,0 +1,121 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: db-es
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
namespace: db-es
|
||||
spec:
|
||||
serviceName: elasticsearch
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: elasticsearch
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: elasticsearch
|
||||
spec:
|
||||
volumes:
|
||||
- name: shared-data
|
||||
emptyDir: {}
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
initContainers:
|
||||
- name: fix-permissions
|
||||
image: hub.yizhisec.com/hybridscope/v2/es-init-helper:alpine-3.22.2
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
args:
|
||||
- |
|
||||
#/bin/sh
|
||||
cp -rf /data/plugins/* /app/shared/
|
||||
chown -R 1000:1000 /usr/share/elasticsearch/data
|
||||
volumeMounts:
|
||||
- name: es-data
|
||||
mountPath: /usr/share/elasticsearch/data
|
||||
- name: shared-data
|
||||
mountPath: /app/shared
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
containers:
|
||||
- name: elasticsearch
|
||||
image: hub.yizhisec.com/external/elasticsearch:7.17.28
|
||||
imagePullPolicy: IfNotPresent
|
||||
env:
|
||||
- name: discovery.type
|
||||
value: single-node
|
||||
- name: ES_JAVA_OPTS
|
||||
value: "-Xms%dg -Xmx%dg"
|
||||
- name: node.name
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
ports:
|
||||
- containerPort: 9200
|
||||
name: http
|
||||
- containerPort: 9300
|
||||
name: transport
|
||||
volumeMounts:
|
||||
- name: es-data
|
||||
mountPath: /usr/share/elasticsearch/data
|
||||
- name: shared-data
|
||||
mountPath: /usr/share/elasticsearch/plugins
|
||||
resources:
|
||||
requests:
|
||||
memory: "%dGi"
|
||||
cpu: "%d"
|
||||
limits:
|
||||
memory: "%dGi"
|
||||
cpu: "%d"
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: es-data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
storageClassName: longhorn
|
||||
resources:
|
||||
requests:
|
||||
storage: %dGi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: es-service
|
||||
namespace: db-es
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: elasticsearch
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 9200
|
||||
targetPort: http
|
||||
- name: transport
|
||||
protocol: TCP
|
||||
port: 9300
|
||||
targetPort: transport
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: es-init-job
|
||||
namespace: db-es
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: es-init
|
||||
image: hub.yizhisec.com/hybridscope/v2/es-init-helper:alpine-3.22.2
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- /bin/sh
|
||||
- /data/create_index.sh
|
||||
restartPolicy: Never
|
||||
backoffLimit: 2
|
||||
214
pkg/resource/flannel.yaml
Normal file
214
pkg/resource/flannel.yaml
Normal file
@@ -0,0 +1,214 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: flannel
|
||||
pod-security.kubernetes.io/enforce: privileged
|
||||
name: kube-flannel
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: flannel
|
||||
name: flannel
|
||||
namespace: kube-flannel
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: flannel
|
||||
name: flannel
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes/status
|
||||
verbs:
|
||||
- patch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: flannel
|
||||
name: flannel
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: flannel
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: flannel
|
||||
namespace: kube-flannel
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
cni-conf.json: |
|
||||
{
|
||||
"name": "cbr0",
|
||||
"cniVersion": "0.3.1",
|
||||
"plugins": [
|
||||
{
|
||||
"type": "flannel",
|
||||
"delegate": {
|
||||
"hairpinMode": true,
|
||||
"isDefaultGateway": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "portmap",
|
||||
"capabilities": {
|
||||
"portMappings": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
net-conf.json: |
|
||||
{
|
||||
"Network": "10.244.0.0/16",
|
||||
"EnableNFTables": false,
|
||||
"Backend": {
|
||||
"Type": "vxlan"
|
||||
}
|
||||
}
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
app: flannel
|
||||
k8s-app: flannel
|
||||
tier: node
|
||||
name: kube-flannel-cfg
|
||||
namespace: kube-flannel
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
labels:
|
||||
app: flannel
|
||||
k8s-app: flannel
|
||||
tier: node
|
||||
name: kube-flannel-ds
|
||||
namespace: kube-flannel
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: flannel
|
||||
k8s-app: flannel
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: flannel
|
||||
k8s-app: flannel
|
||||
tier: node
|
||||
spec:
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/os
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
containers:
|
||||
- args:
|
||||
- --ip-masq
|
||||
- --kube-subnet-mgr
|
||||
command:
|
||||
- /opt/bin/flanneld
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: EVENT_QUEUE_DEPTH
|
||||
value: "5000"
|
||||
- name: CONT_WHEN_CACHE_NOT_READY
|
||||
value: "false"
|
||||
image: ghcr.io/flannel-io/flannel:v0.27.4
|
||||
name: kube-flannel
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
privileged: false
|
||||
volumeMounts:
|
||||
- mountPath: /run/flannel
|
||||
name: run
|
||||
- mountPath: /etc/kube-flannel/
|
||||
name: flannel-cfg
|
||||
- mountPath: /run/xtables.lock
|
||||
name: xtables-lock
|
||||
hostNetwork: true
|
||||
initContainers:
|
||||
- args:
|
||||
- -f
|
||||
- /flannel
|
||||
- /opt/cni/bin/flannel
|
||||
command:
|
||||
- cp
|
||||
image: ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1
|
||||
name: install-cni-plugin
|
||||
volumeMounts:
|
||||
- mountPath: /opt/cni/bin
|
||||
name: cni-plugin
|
||||
- args:
|
||||
- -f
|
||||
- /etc/kube-flannel/cni-conf.json
|
||||
- /etc/cni/net.d/10-flannel.conflist
|
||||
command:
|
||||
- cp
|
||||
image: ghcr.io/flannel-io/flannel:v0.27.4
|
||||
name: install-cni
|
||||
volumeMounts:
|
||||
- mountPath: /etc/cni/net.d
|
||||
name: cni
|
||||
- mountPath: /etc/kube-flannel/
|
||||
name: flannel-cfg
|
||||
priorityClassName: system-node-critical
|
||||
serviceAccountName: flannel
|
||||
tolerations:
|
||||
- effect: NoSchedule
|
||||
operator: Exists
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /run/flannel
|
||||
name: run
|
||||
- hostPath:
|
||||
path: /opt/cni/bin
|
||||
name: cni-plugin
|
||||
- hostPath:
|
||||
path: /etc/cni/net.d
|
||||
name: cni
|
||||
- configMap:
|
||||
name: kube-flannel-cfg
|
||||
name: flannel-cfg
|
||||
- hostPath:
|
||||
path: /run/xtables.lock
|
||||
type: FileOrCreate
|
||||
name: xtables-lock
|
||||
47
pkg/resource/kibana.yaml
Normal file
47
pkg/resource/kibana.yaml
Normal file
@@ -0,0 +1,47 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kibana
|
||||
namespace: db-es
|
||||
spec:
|
||||
replicas: 0
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kibana
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kibana
|
||||
spec:
|
||||
containers:
|
||||
- name: kibana
|
||||
image: hub.yizhisec.com/external/kibana:7.17.28
|
||||
imagePullPolicy: IfNotPresent
|
||||
env:
|
||||
- name: ELASTICSEARCH_HOSTS
|
||||
value: http://es-service:9200
|
||||
- name: SERVER_HOST
|
||||
value: 0.0.0.0
|
||||
ports:
|
||||
- containerPort: 5601
|
||||
name: http
|
||||
resources:
|
||||
limits:
|
||||
memory: 2Gi
|
||||
cpu: 1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kibana-service
|
||||
namespace: db-es
|
||||
spec:
|
||||
type: NodePort
|
||||
selector:
|
||||
app: kibana
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 5601
|
||||
targetPort: 5601
|
||||
nodePort: 31601
|
||||
83
pkg/resource/less-dns.yaml
Normal file
83
pkg/resource/less-dns.yaml
Normal file
@@ -0,0 +1,83 @@
|
||||
# k8s-hs-less-dns.yaml
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: hs-net
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: config-less-dns
|
||||
namespace: hs-net
|
||||
data:
|
||||
config.yml: |
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"vnet4": "100.64.0.1/10",
|
||||
"vnet6": "fc00:eeaa:0000:0000::/48",
|
||||
"redis": {
|
||||
"custom": [
|
||||
{
|
||||
"username": null,
|
||||
"password": "HybridScope0xRed1s.",
|
||||
"host": "redis-master.db-redis",
|
||||
"port": 6379,
|
||||
"tls_insecure": null,
|
||||
"db": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
"mqtt": {
|
||||
"client_id": "dns_mqtt_client",
|
||||
"protocol": "tls",
|
||||
"host": "emqx-service.db-emqx",
|
||||
"port": 1883,
|
||||
"cert": "",
|
||||
"key": "",
|
||||
"keep_alive": 60
|
||||
}
|
||||
}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: less-dns
|
||||
namespace: hs-net
|
||||
labels:
|
||||
app: less-dns
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: less-dns
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: less-dns
|
||||
spec:
|
||||
topologySpreadConstraints:
|
||||
- maxSkew: 1
|
||||
topologyKey: kubernetes.io/hostname
|
||||
whenUnsatisfiable: ScheduleAnyway
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app: less-dns
|
||||
containers:
|
||||
- name: less-dns
|
||||
image: hub.yizhisec.com/hybridscope/less_dns_service:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /etc/less_dns_service
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumes:
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: config-less-dns
|
||||
items:
|
||||
- key: config.yml
|
||||
path: config.yml
|
||||
restartPolicy: Always
|
||||
28
pkg/resource/resource.go
Normal file
28
pkg/resource/resource.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed flannel.yaml
|
||||
YAMLFlannel []byte
|
||||
|
||||
//go:embed es.yaml
|
||||
YAMLES string
|
||||
|
||||
//go:embed kibana.yaml
|
||||
YAMLKibana []byte
|
||||
|
||||
//go:embed es.init.sh
|
||||
BashESInit []byte
|
||||
|
||||
//go:embed emqx.yaml
|
||||
YAMLEMQX []byte
|
||||
|
||||
//go:embed yosguard.create.sql
|
||||
SQLYosguard []byte
|
||||
|
||||
//go:embed less-dns.yaml
|
||||
YAMLLessDNS []byte
|
||||
)
|
||||
36
pkg/resource/yosguard.create.sql
Normal file
36
pkg/resource/yosguard.create.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
CREATE TABLE IF NOT EXISTS `pkg`
|
||||
(
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`path` TEXT,
|
||||
`installed` INTEGER,
|
||||
`create_timestamp` INTEGER,
|
||||
`install_timestamp` INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `patch`
|
||||
(
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`path` TEXT,
|
||||
`verified` INTEGER,
|
||||
`installed` INTEGER,
|
||||
`create_timestamp` INTEGER,
|
||||
`verify_timestamp` INTEGER,
|
||||
`install_timestamp` INTEGER
|
||||
);
|
||||
|
||||
-- 记录注册的机器的信息
|
||||
CREATE TABLE IF NOT EXISTS `machine`
|
||||
(
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`uuid` CHAR(32),
|
||||
`create_timestamp` INTEGER
|
||||
);
|
||||
|
||||
-- 记录下发的指令
|
||||
CREATE TABLE IF NOT EXISTS `action`
|
||||
(
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`uuid` CHAR(32),
|
||||
`action` INTEGER, -- 要下发的指令
|
||||
`create_timestamp` INTEGER -- 下发命令的时间戳,秒为单位
|
||||
);
|
||||
Reference in New Issue
Block a user