新增 auto-check 工具:网段扫描+SSH登录+压力测试永久循环工作流
- pkg/discovery: TCP端口探测存活主机,ARP表解析MAC作为设备唯一标识 - pkg/sshclient: SSH连接(密码/密钥认证)与远程命令执行 - pkg/stress: stress-ng/stressapptest 压测(cpu/memory/disk/memnative/full)+温度与dmesg监控 - pkg/report: 检测报告生成(文本/JSON) - pkg/workflow: 永久循环工作流(间隔可配),MAC唯一标识设备,增量测试+状态变化打印 - pkg/config: YAML分类配置(scan/ssh/stress/report/workflow) - cmd: cobra入口,仅 --config 指定配置文件
This commit is contained in:
168
auto-check/pkg/stress/runners.go
Normal file
168
auto-check/pkg/stress/runners.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package stress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// truncate 截断过长输出
|
||||
func truncate(s string, maxLen int) string {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) > maxLen {
|
||||
return s[:maxLen] + "\n ... (输出已截断)"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ============================
|
||||
// stress-ng 压测
|
||||
// ============================
|
||||
|
||||
// CPUStress stress-ng CPU 压力测试
|
||||
func CPUStress(client *ssh.Client, ex Executor, cfg Config) Result {
|
||||
start := time.Now()
|
||||
fmt.Printf(" [CPU] stress-ng CPU 压力 (%d线程, %v)...\n", cfg.Threads, cfg.Duration)
|
||||
|
||||
info, err := EnsureTool(client, ex, "stress-ng", "apt install stress-ng / opkg install stress-ng")
|
||||
if err != nil {
|
||||
return Result{Type: TestCPU, Status: "skip", Error: err.Error(), Duration: time.Since(start)}
|
||||
}
|
||||
fmt.Printf(" [CPU] 使用 %s (%s)\n", info.Path, info.Version)
|
||||
|
||||
cmd := fmt.Sprintf("%s --cpu %d --cpu-method all --timeout %v --metrics-brief --temp-path /tmp 2>&1",
|
||||
info.Path, cfg.Threads, cfg.Duration)
|
||||
out, err := exec(client, ex, cmd)
|
||||
duration := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
return Result{Type: TestCPU, Status: "error", Output: truncate(out, 600), Error: err.Error(), Duration: duration}
|
||||
}
|
||||
return Result{Type: TestCPU, Status: "pass", Output: truncate(out, 600), Duration: duration}
|
||||
}
|
||||
|
||||
// MemoryStress stress-ng 内存压力测试
|
||||
func MemoryStress(client *ssh.Client, ex Executor, cfg Config) Result {
|
||||
start := time.Now()
|
||||
fmt.Printf(" [Memory] stress-ng 内存压力 (%d线程, %v)...\n", cfg.Threads, cfg.Duration)
|
||||
|
||||
info, err := EnsureTool(client, ex, "stress-ng", "apt install stress-ng / opkg install stress-ng")
|
||||
if err != nil {
|
||||
return Result{Type: TestMemory, Status: "skip", Error: err.Error(), Duration: time.Since(start)}
|
||||
}
|
||||
|
||||
memWorkers := cfg.Threads
|
||||
if memWorkers > 4 {
|
||||
memWorkers = 4
|
||||
}
|
||||
cmd := fmt.Sprintf("%s --vm %d --vm-bytes 256M --vm-method all --timeout %v --metrics-brief 2>&1",
|
||||
info.Path, memWorkers, cfg.Duration)
|
||||
out, err := exec(client, ex, cmd)
|
||||
duration := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
return Result{Type: TestMemory, Status: "error", Output: truncate(out, 600), Error: err.Error(), Duration: duration}
|
||||
}
|
||||
return Result{Type: TestMemory, Status: "pass", Output: truncate(out, 600), Duration: duration}
|
||||
}
|
||||
|
||||
// DiskIOStress stress-ng 磁盘IO压力测试
|
||||
func DiskIOStress(client *ssh.Client, ex Executor, cfg Config) Result {
|
||||
start := time.Now()
|
||||
fmt.Printf(" [DiskIO] stress-ng 磁盘IO压力 (%v)...\n", cfg.Duration)
|
||||
|
||||
info, err := EnsureTool(client, ex, "stress-ng", "apt install stress-ng / opkg install stress-ng")
|
||||
if err != nil {
|
||||
return Result{Type: TestDiskIO, Status: "skip", Error: err.Error(), Duration: time.Since(start)}
|
||||
}
|
||||
|
||||
testDir := cfg.DiskDir
|
||||
if testDir == "" {
|
||||
testDir = "/tmp/stress-disk-test"
|
||||
}
|
||||
_, _ = exec(client, ex, fmt.Sprintf("mkdir -p %s", testDir))
|
||||
|
||||
cmd := fmt.Sprintf("%s --iomix 2 --iomix-bytes %dM --timeout %v --metrics-brief 2>&1",
|
||||
info.Path, cfg.DiskSizeMB, cfg.Duration)
|
||||
out, err := exec(client, ex, cmd)
|
||||
duration := time.Since(start)
|
||||
|
||||
_, _ = exec(client, ex, fmt.Sprintf("rm -rf %s", testDir))
|
||||
|
||||
if err != nil {
|
||||
return Result{Type: TestDiskIO, Status: "error", Output: truncate(out, 600), Error: err.Error(), Duration: duration}
|
||||
}
|
||||
return Result{Type: TestDiskIO, Status: "pass", Output: truncate(out, 600), Duration: duration}
|
||||
}
|
||||
|
||||
// ============================
|
||||
// stressapptest 内存精压
|
||||
// ============================
|
||||
|
||||
// MemNativeStress stressapptest 内存稳定性精压
|
||||
func MemNativeStress(client *ssh.Client, ex Executor, cfg Config) Result {
|
||||
start := time.Now()
|
||||
fmt.Printf(" [MemNative] stressapptest 内存精压 (%v)...\n", cfg.Duration)
|
||||
|
||||
info, err := EnsureTool(client, ex, "stressapptest", "apt install stressapptest / opkg install stressapptest")
|
||||
if err != nil {
|
||||
return Result{Type: TestMemNative, Status: "skip", Error: err.Error(), Duration: time.Since(start)}
|
||||
}
|
||||
fmt.Printf(" [MemNative] 使用 %s\n", info.Path)
|
||||
|
||||
memSize := cfg.MemSizeMB
|
||||
if memSize <= 0 {
|
||||
out, _ := exec(client, ex, "free -m 2>/dev/null | awk '/Mem:/{print int($7*0.6)}'")
|
||||
out = strings.TrimSpace(out)
|
||||
if out != "" {
|
||||
fmt.Sscanf(out, "%d", &memSize)
|
||||
}
|
||||
if memSize <= 0 {
|
||||
memSize = 512
|
||||
}
|
||||
}
|
||||
|
||||
cmd := fmt.Sprintf("%s -s %d -M %d -f 0 -v 2>&1",
|
||||
info.Path, int(cfg.Duration.Seconds()), memSize)
|
||||
out, err := exec(client, ex, cmd)
|
||||
duration := time.Since(start)
|
||||
|
||||
output := truncate(out, 800)
|
||||
if strings.Contains(strings.ToUpper(output), "PASS") {
|
||||
return Result{Type: TestMemNative, Status: "pass", Output: output, Duration: duration}
|
||||
}
|
||||
if strings.Contains(strings.ToUpper(output), "FAIL") {
|
||||
return Result{Type: TestMemNative, Status: "fail", Output: output, Duration: duration}
|
||||
}
|
||||
if err != nil {
|
||||
return Result{Type: TestMemNative, Status: "error", Output: output, Error: err.Error(), Duration: duration}
|
||||
}
|
||||
return Result{Type: TestMemNative, Status: "pass", Output: output, Duration: duration}
|
||||
}
|
||||
|
||||
// ============================
|
||||
// 综合压测
|
||||
// ============================
|
||||
|
||||
// FullStress 三合一综合压测 (CPU + 内存 + 磁盘IO 同时进行)
|
||||
func FullStress(client *ssh.Client, ex Executor, cfg Config) Result {
|
||||
start := time.Now()
|
||||
fmt.Printf(" [Full] 三合一综合压测 (CPU %d线程 + 内存 + 磁盘IO, %v)...\n", cfg.Threads, cfg.Duration)
|
||||
|
||||
info, err := EnsureTool(client, ex, "stress-ng", "apt install stress-ng / opkg install stress-ng")
|
||||
if err != nil {
|
||||
return Result{Type: TestFull, Status: "skip", Error: err.Error(), Duration: time.Since(start)}
|
||||
}
|
||||
|
||||
cmd := fmt.Sprintf("%s --cpu %d --vm 2 --vm-bytes 128M --iomix 1 --iomix-bytes 256M --timeout %v --metrics-brief 2>&1",
|
||||
info.Path, cfg.Threads, cfg.Duration)
|
||||
out, err := exec(client, ex, cmd)
|
||||
duration := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
return Result{Type: TestFull, Status: "error", Output: truncate(out, 600), Error: err.Error(), Duration: duration}
|
||||
}
|
||||
return Result{Type: TestFull, Status: "pass", Output: truncate(out, 600), Duration: duration}
|
||||
}
|
||||
Reference in New Issue
Block a user