增加操作系统显示,以及磁盘信息显示

This commit is contained in:
Alex Yang
2025-12-06 23:30:58 +08:00
parent 8a5ca62793
commit 667e370f79
23 changed files with 366 additions and 4744 deletions

Binary file not shown.

View File

@@ -1,5 +1,5 @@
{
"server_url": "http://10.35.10.12:8080/api",
"server_url": "http://localhost:8080/api",
"id": "agent-1764858612504948034-3525156",
"name": "yunc",
"token": "84f0657f9075f63e3964aeb7e3a9e59b",

View File

@@ -8,6 +8,7 @@ import (
stdnet "net"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
@@ -62,12 +63,16 @@ type ProcessMetrics struct {
// DiskDetailMetrics 磁盘详细信息
type DiskDetailMetrics struct {
ID string `json:"id"` // 磁盘唯一ID数字序列
Path string `json:"path"` // 设备路径
Status string `json:"status"` // 设备状态
Type string `json:"type"` // 设备类型
SizeGB float64 `json:"size_gb"` // 设备大小(GB)
Model string `json:"model"` // 设备型号
Vendor string `json:"vendor"` // 设备厂商
InterfaceType string `json:"interface_type"` // 接口类型
FileSystem string `json:"file_system"` // 文件系统
DiskUUID string `json:"disk_uuid"` // 磁盘UUID
Description string `json:"description"` // 设备描述
}
@@ -108,6 +113,7 @@ type MemoryInfo struct {
// NetworkHardwareInfo 网卡硬件信息
type NetworkHardwareInfo struct {
ID string `json:"id"` // 网卡唯一ID数字序列
Name string `json:"name"` // 网卡名称
MAC string `json:"mac"` // MAC地址
IPAddresses []string `json:"ip_addresses"` // IP地址列表
@@ -677,7 +683,7 @@ func collectNetworkHardware() ([]NetworkHardwareInfo, error) {
networkCards := make([]NetworkHardwareInfo, 0, len(interfaces))
for _, iface := range interfaces {
for i, iface := range interfaces {
// 获取接口的IP地址
addrs, err := iface.Addrs()
if err != nil {
@@ -703,7 +709,11 @@ func collectNetworkHardware() ([]NetworkHardwareInfo, error) {
// gopsutil的net.IOCounters没有直接提供速度这里简化处理
// 实际应用中可能需要更复杂的逻辑
// 生成数字序列ID
netCardID := fmt.Sprintf("%d", i+1)
networkCard := NetworkHardwareInfo{
ID: netCardID,
Name: iface.Name,
MAC: iface.HardwareAddr.String(),
IPAddresses: ipAddresses,
@@ -865,9 +875,165 @@ func collectProcessMetrics() ([]ProcessMetrics, error) {
return processes, nil
}
// 执行命令并返回输出
func execCommand(cmd string) (string, error) {
cmdParts := strings.Fields(cmd)
if len(cmdParts) == 0 {
return "", fmt.Errorf("empty command")
}
// 使用exec包执行命令
c := exec.Command(cmdParts[0], cmdParts[1:]...)
var out bytes.Buffer
var stderr bytes.Buffer
c.Stdout = &out
c.Stderr = &stderr
err := c.Run()
if err != nil {
return "", fmt.Errorf("command failed: %w, stderr: %s", err, stderr.String())
}
return out.String(), nil
}
// 解析lsblk命令的JSON输出
func parseLsblkOutput(output string) ([]DiskDetailMetrics, error) {
// 定义lsblk输出的结构添加UUID字段
type LsblkDevice struct {
Name string `json:"name"`
Mountpoint string `json:"mountpoint"`
Size string `json:"size"`
Type string `json:"type"`
Vendor string `json:"vendor"`
Model string `json:"model"`
Fstype string `json:"fstype"`
UUID string `json:"uuid"`
}
type LsblkOutput struct {
Blockdevices []LsblkDevice `json:"blockdevices"`
}
// 解析JSON输出
var lsblkOutput LsblkOutput
err := json.Unmarshal([]byte(output), &lsblkOutput)
if err != nil {
return nil, fmt.Errorf("failed to parse lsblk output: %w", err)
}
// 创建磁盘详细信息切片
diskDetails := make([]DiskDetailMetrics, 0)
// 遍历所有块设备为每个设备生成数字序列ID
for i, device := range lsblkOutput.Blockdevices {
// 只处理磁盘和分区
if device.Type != "disk" && device.Type != "part" {
continue
}
// 设备路径(挂载点)
path := device.Mountpoint
// 设备状态
status := "offline"
if path != "" {
status = "online"
} else if device.Type == "disk" {
status = "exist"
}
// 设备类型
diskType := device.Type
// 设备大小(GB)
sizeGB := 0.0
if device.Size != "" {
// 解析大小字符串,例如"100G" -> 100
sizeStr := strings.TrimSuffix(strings.ToUpper(device.Size), "G")
if size, err := strconv.ParseFloat(sizeStr, 64); err == nil {
sizeGB = size
} else {
// 尝试解析其他单位如MB
sizeStrMB := strings.TrimSuffix(strings.ToUpper(device.Size), "M")
if size, err := strconv.ParseFloat(sizeStrMB, 64); err == nil {
sizeGB = size / 1024
}
}
}
// 设备型号
model := device.Model
// 设备厂商
vendor := device.Vendor
// 接口类型
interfaceType := "unknown"
// 根据设备名称猜测接口类型
if strings.HasPrefix(device.Name, "nvme") {
interfaceType = "NVME"
} else if strings.HasPrefix(device.Name, "sas") {
interfaceType = "SAS"
} else if strings.HasPrefix(device.Name, "scsi") {
interfaceType = "SCSI"
} else if strings.HasPrefix(device.Name, "sd") {
interfaceType = "SATA"
} else if strings.HasPrefix(device.Name, "vd") || strings.HasPrefix(device.Name, "xvda") {
interfaceType = "Virtual"
}
// 文件系统
fileSystem := device.Fstype
// 磁盘UUID
diskUUID := device.UUID
// 设备描述
description := fmt.Sprintf("/dev/%s (%s)", device.Name, fileSystem)
// 生成数字序列ID
diskID := fmt.Sprintf("%d", i+1)
// 创建磁盘详细信息
diskDetail := DiskDetailMetrics{
ID: diskID,
Path: path,
Status: status,
Type: diskType,
SizeGB: sizeGB,
Model: model,
Vendor: vendor,
InterfaceType: interfaceType,
FileSystem: fileSystem,
DiskUUID: diskUUID,
Description: description,
}
diskDetails = append(diskDetails, diskDetail)
}
return diskDetails, nil
}
// 采集磁盘详细信息
func collectDiskDetails() ([]DiskDetailMetrics, error) {
// 获取所有挂载点信息
// 执行lsblk命令获取磁盘信息添加UUID字段
cmd := "lsblk -o NAME,MOUNTPOINT,SIZE,TYPE,VENDOR,MODEL,FSTYPE,UUID --json"
output, err := execCommand(cmd)
if err != nil {
// 如果lsblk命令执行失败使用disk库获取分区信息作为备选
log.Printf("Failed to execute lsblk: %v, using fallback method", err)
return collectDiskDetailsFallback()
}
// 解析lsblk输出
return parseLsblkOutput(output)
}
// 采集磁盘详细信息的备选方法
func collectDiskDetailsFallback() ([]DiskDetailMetrics, error) {
// 使用disk库获取分区信息作为备选
partitions, err := disk.Partitions(false)
if err != nil {
return nil, fmt.Errorf("failed to get disk partitions: %w", err)
@@ -883,25 +1049,31 @@ func collectDiskDetails() ([]DiskDetailMetrics, error) {
continue // 忽略无法访问的分区
}
// 设备路径
path := partition.Device
// 设备路径(挂载点)
path := partition.Mountpoint
// 设备状态
status := "online"
if path == "" {
status = "exist"
}
// 设备类型
diskType := "unknown"
if partition.Fstype != "" {
diskType = partition.Fstype
}
diskType := "disk"
// 设备大小(GB)
sizeGB := float64(usage.Total) / (1024 * 1024 * 1024)
// 设备型号 - 简化实现,实际需要更复杂的逻辑
// 设备型号
model := partition.Device
// 接口类型 - 简化实现
// 设备厂商
vendor := ""
// 文件系统
fileSystem := partition.Fstype
// 接口类型
interfaceType := "unknown"
if len(partition.Device) > 0 {
if partition.Device[:3] == "sda" || partition.Device[:3] == "sdb" {
@@ -912,6 +1084,10 @@ func collectDiskDetails() ([]DiskDetailMetrics, error) {
interfaceType = "MMC"
} else if partition.Device[:3] == "vda" || partition.Device[:3] == "vdb" {
interfaceType = "Virtual"
} else if partition.Device[:4] == "sas" {
interfaceType = "SAS"
} else if partition.Device[:4] == "scsi" {
interfaceType = "SCSI"
}
}
@@ -925,7 +1101,9 @@ func collectDiskDetails() ([]DiskDetailMetrics, error) {
Type: diskType,
SizeGB: sizeGB,
Model: model,
Vendor: vendor,
InterfaceType: interfaceType,
FileSystem: fileSystem,
Description: description,
}
@@ -1277,18 +1455,24 @@ func sendMetrics(metricsList []*Metrics) error {
// 设置设备认证令牌
req.Header.Set("X-Device-Token", config.Token)
log.Printf("Sending %d metrics to server: %s", len(metricsList), config.ServerURL)
// 发送请求
resp, err := client.Do(req)
if err != nil {
log.Printf("Failed to send metrics: %v", err)
return err
}
defer resp.Body.Close()
// 检查响应状态码
if resp.StatusCode != http.StatusOK {
log.Printf("Server returned status code %d", resp.StatusCode)
return fmt.Errorf("server returned status code %d", resp.StatusCode)
}
log.Printf("Successfully sent %d metrics to server", len(metricsList))
return nil
}

Binary file not shown.