Files
basics/system/raid.go

242 lines
7.4 KiB
Go

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
}