From ce1d4d14567408afed9715f5ae9284341cd3fc46 Mon Sep 17 00:00:00 2001 From: spiritlhl <103393591+spiritLHLS@users.noreply.github.com> Date: Tue, 1 Apr 2025 12:20:23 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81raid=E6=A3=80?= =?UTF-8?q?=E6=B5=8B(=E8=99=BD=E7=84=B6=E5=87=A0=E4=B9=8E=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E6=9C=8D=E5=8A=A1=E5=99=A8=E6=9C=89=E6=9F=A5=E5=BE=97?= =?UTF-8?q?=E5=88=B0=E7=9A=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 - network/ipv6/ipv6_mask_common.go | 30 ---- system/raid.go | 241 +++++++++++++++++++++++++++++++ system/system_test.go | 16 ++ 4 files changed, 257 insertions(+), 31 deletions(-) create mode 100644 system/raid.go diff --git a/README.md b/README.md index c8b70f0..249928e 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ Include: https://github.com/oneclickvirt/gostun ## TODO - [ ] 在可检索的物理核心的时候,额外添加对虚拟核心的识别,尽量全部核心数量还有线程数都展示出来 -- [ ] 支持raid识别 - [ ] 适配MACOS系统的相关信息识别 ## Usage diff --git a/network/ipv6/ipv6_mask_common.go b/network/ipv6/ipv6_mask_common.go index 7ebee94..9172fbe 100644 --- a/network/ipv6/ipv6_mask_common.go +++ b/network/ipv6/ipv6_mask_common.go @@ -27,36 +27,6 @@ func getInterface() (string, error) { return "", fmt.Errorf("未找到合适的网络接口") } -// 获取当前的公网 IPv6 地址 -// func getCurrentIPv6() (string, error) { -// // 创建一个新的req客户端,设置超时 -// client := req.C().SetTimeout(5 * time.Second) -// client.SetTimeout(6 * time.Second) -// // 尝试多个 IPv6 检测服务 -// urls := []string{ -// "https://ipv6.ip.sb", -// "https://api6.ipify.org", -// "https://v6.ident.me", -// } -// var lastErr error -// for _, url := range urls { -// resp, err := client.R().Get(url) -// if err != nil { -// lastErr = err -// continue -// } -// body := resp.String() -// ipv6 := strings.TrimSpace(body) -// if net.ParseIP(ipv6) != nil && strings.Contains(ipv6, ":") { -// return ipv6, nil -// } -// } -// if lastErr != nil { -// return "", lastErr -// } -// return "", fmt.Errorf("无法获取公网IPv6地址") -// } - // 判断是否为非全局单播地址前缀 func isNonGlobalPrefix(prefix [16]byte) bool { // 链路本地地址 fe80::/10 diff --git a/system/raid.go b/system/raid.go new file mode 100644 index 0000000..d4ed062 --- /dev/null +++ b/system/raid.go @@ -0,0 +1,241 @@ +package system + +import ( + "bufio" + "fmt" + "os/exec" + "regexp" + "runtime" + "strings" +) + +// RAID信息结构体 +type RAIDInfo struct { + Exists bool + Type string + DiskCount int + Controller string + Details string +} + +func detectRAID() (RAIDInfo, error) { + var info RAIDInfo + var err error + switch runtime.GOOS { + case "windows": + info, err = detectWindowsRAID() + case "linux": + info, err = detectLinuxRAID() + case "darwin": + info, err = detectMacOSRAID() + default: + err = fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) + } + return info, err +} + +func detectWindowsRAID() (RAIDInfo, error) { + info := RAIDInfo{} + // 使用diskpart和wmic获取存储信息 + cmd := exec.Command("powershell", "-Command", "Get-WmiObject -Class Win32_DiskDrive | Select-Object Model, InterfaceType, MediaType | Format-Table -AutoSize") + output, err := cmd.CombinedOutput() + if err != nil { + return info, err + } + // 检查是否有控制器信息 + controllerCmd := exec.Command("powershell", "-Command", "Get-WmiObject -Class Win32_SCSIController | Select-Object Name, DriverName, PNPDeviceID | Format-Table -AutoSize") + controllerOutput, err := controllerCmd.CombinedOutput() + if err == nil { + controllerStr := string(controllerOutput) + if strings.Contains(strings.ToLower(controllerStr), "raid") { + info.Exists = true + info.Controller = extractControllerName(controllerStr) + } + } + // 检查虚拟磁盘 + vDiskCmd := exec.Command("powershell", "-Command", "Get-WmiObject -Class Win32_DiskDrive | Where-Object {$_.MediaType -eq 'Fixed hard disk media'} | ForEach-Object {$disk = $_; Get-WmiObject -Class Win32_DiskPartition | Where-Object {$_.DiskIndex -eq $disk.Index}} | Format-Table -AutoSize") + vDiskOutput, _ := vDiskCmd.CombinedOutput() + // 分析输出确定RAID类型 + outputStr := string(output) + string(vDiskOutput) + if info.Exists || strings.Contains(strings.ToLower(outputStr), "raid") { + info.Exists = true + info.Type = determineWindowsRAIDType(outputStr) + info.DiskCount = estimateDiskCount(outputStr) + info.Details = cleanOutput(outputStr) + } + return info, nil +} + +func detectLinuxRAID() (RAIDInfo, error) { + info := RAIDInfo{} + // 检查软RAID (mdadm) + mdstatCmd := exec.Command("cat", "/proc/mdstat") + mdstatOutput, err := mdstatCmd.CombinedOutput() + if err == nil && len(mdstatOutput) > 0 && !strings.Contains(string(mdstatOutput), "unused devices") { + mdstatStr := string(mdstatOutput) + if strings.Contains(mdstatStr, "md") { + info.Exists = true + info.Type = determineLinuxRAIDType(mdstatStr) + info.DiskCount = countDevicesInMdstat(mdstatStr) + info.Controller = "软件RAID (mdadm)" + info.Details = cleanOutput(mdstatStr) + return info, nil + } + } + // 检查硬件RAID控制器 + lspciCmd := exec.Command("lspci") + lspciOutput, err := lspciCmd.CombinedOutput() + if err == nil { + lspciStr := string(lspciOutput) + if strings.Contains(strings.ToLower(lspciStr), "raid") { + info.Exists = true + info.Controller = extractLinuxControllerName(lspciStr) + info.Type = "硬件RAID" + info.Details = cleanOutput(lspciStr) + // 尝试获取更多详细信息 + if strings.Contains(strings.ToLower(info.Controller), "lsi") || strings.Contains(strings.ToLower(info.Controller), "avago") || strings.Contains(strings.ToLower(info.Controller), "broadcom") { + mptUtilCmd := exec.Command("sh", "-c", "which mpt-status && mpt-status || echo 'mpt-status not installed'") + mptOutput, _ := mptUtilCmd.CombinedOutput() + info.Details += "\n" + cleanOutput(string(mptOutput)) + } else if strings.Contains(strings.ToLower(info.Controller), "adaptec") { + arcConfCmd := exec.Command("sh", "-c", "which arcconf && arcconf getconfig 1 || echo 'arcconf not installed'") + arcOutput, _ := arcConfCmd.CombinedOutput() + info.Details += "\n" + cleanOutput(string(arcOutput)) + } + } + } + return info, nil +} + +func detectMacOSRAID() (RAIDInfo, error) { + info := RAIDInfo{} + + // 使用diskutil获取RAID信息 + cmd := exec.Command("diskutil", "appleRAID", "list") + output, err := cmd.CombinedOutput() + + if err == nil { + outputStr := string(output) + if !strings.Contains(outputStr, "No RAID sets") { + info.Exists = true + info.Type = determineMacRAIDType(outputStr) + info.DiskCount = countMacRAIDDisks(outputStr) + info.Controller = "Apple Software RAID" + info.Details = cleanOutput(outputStr) + } + } + + return info, nil +} + +func determineWindowsRAIDType(output string) string { + lowerOutput := strings.ToLower(output) + + if strings.Contains(lowerOutput, "raid 0") || strings.Contains(lowerOutput, "stripe") { + return "RAID 0 (条带化)" + } else if strings.Contains(lowerOutput, "raid 1") || strings.Contains(lowerOutput, "mirror") { + return "RAID 1 (镜像)" + } else if strings.Contains(lowerOutput, "raid 5") || strings.Contains(lowerOutput, "parity") { + return "RAID 5 (分布式奇偶校验)" + } else if strings.Contains(lowerOutput, "raid 6") { + return "RAID 6 (双奇偶校验)" + } else if strings.Contains(lowerOutput, "raid 10") { + return "RAID 10 (镜像+条带)" + } else { + return "未知RAID类型" + } +} + +func determineLinuxRAIDType(mdstat string) string { + if strings.Contains(mdstat, "raid0") { + return "RAID 0 (条带化)" + } else if strings.Contains(mdstat, "raid1") { + return "RAID 1 (镜像)" + } else if strings.Contains(mdstat, "raid4") { + return "RAID 4 (专用奇偶校验)" + } else if strings.Contains(mdstat, "raid5") { + return "RAID 5 (分布式奇偶校验)" + } else if strings.Contains(mdstat, "raid6") { + return "RAID 6 (双奇偶校验)" + } else if strings.Contains(mdstat, "raid10") { + return "RAID 10 (镜像+条带)" + } else { + return "未知RAID类型" + } +} + +func determineMacRAIDType(output string) string { + lowerOutput := strings.ToLower(output) + + if strings.Contains(lowerOutput, "stripe") { + return "RAID 0 (条带化)" + } else if strings.Contains(lowerOutput, "mirror") { + return "RAID 1 (镜像)" + } else if strings.Contains(lowerOutput, "concat") { + return "JBOD (磁盘连接)" + } else { + return "未知RAID类型" + } +} + +func extractControllerName(output string) string { + scanner := bufio.NewScanner(strings.NewReader(output)) + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(strings.ToLower(line), "raid") { + fields := strings.Fields(line) + if len(fields) > 0 { + return strings.Join(fields, " ") + } + } + } + return "未知RAID控制器" +} + +func extractLinuxControllerName(lspci string) string { + scanner := bufio.NewScanner(strings.NewReader(lspci)) + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(strings.ToLower(line), "raid") { + return line + } + } + return "未知RAID控制器" +} + +func estimateDiskCount(output string) int { + // 简单估计,实际情况可能需要更复杂的解析 + re := regexp.MustCompile(`Disk #\d+`) + matches := re.FindAllString(output, -1) + return len(matches) +} + +func countDevicesInMdstat(mdstat string) int { + scanner := bufio.NewScanner(strings.NewReader(mdstat)) + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, "active") { + re := regexp.MustCompile(`sd[a-z][0-9]*`) + matches := re.FindAllString(line, -1) + return len(matches) + } + } + return 0 +} + +func countMacRAIDDisks(output string) int { + re := regexp.MustCompile(`Disk: [0-9]`) + matches := re.FindAllString(output, -1) + return len(matches) +} + +func cleanOutput(output string) string { + // 删除ANSI颜色代码和控制字符 + re := regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`) + cleanStr := re.ReplaceAllString(output, "") + // 限制输出长度 + if len(cleanStr) > 500 { + return cleanStr[:500] + "..." + } + return cleanStr +} diff --git a/system/system_test.go b/system/system_test.go index 14c61dd..5bb7aef 100644 --- a/system/system_test.go +++ b/system/system_test.go @@ -5,5 +5,21 @@ import ( ) func TestGetSystemInfo(t *testing.T) { + // 检测整体 GetSystemInfo() + // 检测raid - 在服务器上几乎没有查得到的,不加入检测 + // raidInfo, err := detectRAID() + // if err != nil { + // fmt.Printf("检测RAID时发生错误: %v\n", err) + // return + // } + // if raidInfo.Exists { + // fmt.Println("检测到RAID配置:") + // fmt.Printf("RAID类型: %s\n", raidInfo.Type) + // fmt.Printf("磁盘数量: %d\n", raidInfo.DiskCount) + // fmt.Printf("控制器: %s\n", raidInfo.Controller) + // // fmt.Printf("详细信息: %s\n", raidInfo.Details) + // } else { + // fmt.Println("未检测到RAID配置") + // } }