From 91d364b18be13ff0f5ad1af897d5b233ec4372ff Mon Sep 17 00:00:00 2001 From: CityFun <31820853+zhengkunwang223@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:22:56 +0800 Subject: [PATCH] feat: improve LVM partition recognition in disk management (#10985) --- agent/app/dto/response/disk.go | 2 +- agent/app/service/disk.go | 24 ++- agent/app/service/disk_utils.go | 157 ++++++++++++++++-- frontend/src/api/interface/host.ts | 2 +- .../views/host/disk-management/disk/index.vue | 10 +- 5 files changed, 170 insertions(+), 25 deletions(-) diff --git a/agent/app/dto/response/disk.go b/agent/app/dto/response/disk.go index 40a1cf666..518dac71e 100644 --- a/agent/app/dto/response/disk.go +++ b/agent/app/dto/response/disk.go @@ -24,7 +24,7 @@ type DiskBasicInfo struct { type CompleteDiskInfo struct { Disks []DiskInfo `json:"disks"` UnpartitionedDisks []DiskBasicInfo `json:"unpartitionedDisks"` - SystemDisk *DiskInfo `json:"systemDisk"` + SystemDisks []DiskInfo `json:"systemDisks"` TotalDisks int `json:"totalDisks"` TotalCapacity int64 `json:"totalCapacity"` } diff --git a/agent/app/service/disk.go b/agent/app/service/disk.go index 20c3bcb56..f838167d6 100644 --- a/agent/app/service/disk.go +++ b/agent/app/service/disk.go @@ -28,14 +28,22 @@ func NewIDiskService() IDiskService { } func (s *DiskService) GetCompleteDiskInfo() (*response.CompleteDiskInfo, error) { - output, err := cmd.RunDefaultWithStdoutBashC("lsblk -P -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE,MODEL,SERIAL,TRAN,ROTA") - if err != nil { - return nil, fmt.Errorf("failed to execute lsblk command: %v", err) - } - - diskInfos, err := parseLsblkOutput(output) - if err != nil { - return nil, fmt.Errorf("failed to parse lsblk output: %v", err) + var diskInfos []response.DiskBasicInfo + output, err := cmd.RunDefaultWithStdoutBashC("lsblk -J -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE,MODEL,SERIAL,TRAN,ROTA") + if err == nil { + diskInfos, err = parseLsblkJsonOutput(output) + if err != nil { + return nil, fmt.Errorf("failed to parse lsblk output: %v", err) + } + } else { + output, err = cmd.RunDefaultWithStdoutBashC("lsblk -P -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE,MODEL,SERIAL,TRAN,ROTA") + if err != nil { + return nil, fmt.Errorf("failed to run lsblk command: %v", err) + } + diskInfos, err = parseLsblkOutput(output) + if err != nil { + return nil, fmt.Errorf("failed to parse lsblk output: %v", err) + } } result := organizeDiskInfo(diskInfos) diff --git a/agent/app/service/disk_utils.go b/agent/app/service/disk_utils.go index de178cc37..b01a23cef 100644 --- a/agent/app/service/disk_utils.go +++ b/agent/app/service/disk_utils.go @@ -2,7 +2,9 @@ package service import ( "bufio" + "encoding/json" "fmt" + "github.com/1Panel-dev/1Panel/agent/utils/re" "os" "os/exec" "strconv" @@ -12,12 +14,134 @@ import ( "github.com/1Panel-dev/1Panel/agent/app/dto/response" "github.com/1Panel-dev/1Panel/agent/buserr" "github.com/1Panel-dev/1Panel/agent/utils/cmd" - "github.com/1Panel-dev/1Panel/agent/utils/re" ) +type LsblkRaw struct { + Blockdevices []LsblkDevice `json:"blockdevices"` +} + +type LsblkDevice struct { + Name string `json:"name"` + Size string `json:"size"` + Type string `json:"type"` + Mountpoint string `json:"mountpoint"` + Fstype string `json:"fstype"` + Model string `json:"model"` + Serial string `json:"serial"` + Tran string `json:"tran"` + Rota bool `json:"rota"` + Children []LsblkDevice `json:"children"` +} + +func parseDevice(dev LsblkDevice) []response.DiskBasicInfo { + var list []response.DiskBasicInfo + + if strings.HasPrefix(dev.Name, "loop") || strings.HasPrefix(dev.Name, "dm-") || dev.Type == "rom" { + return list + } + + if dev.Type == "lvm" { + return list + } + + diskType := "Unknown" + if dev.Type == "disk" || dev.Type == "part" { + if dev.Rota { + diskType = "HDD" + } else { + diskType = "SSD" + } + } + + mountPoint := dev.Mountpoint + filesystem := dev.Fstype + size := dev.Size + + var used, avail, totalSize string + var usePercent int + isMounted := mountPoint != "" + isSystem := false + + if dev.Fstype == "LVM2_member" && len(dev.Children) > 0 { + for _, child := range dev.Children { + if child.Type == "lvm" && child.Mountpoint != "" { + devicePath := "/dev/mapper/" + child.Name + totalSize, used, avail, usePercent, _ := getDiskUsageInfo(devicePath) + + childInfo := response.DiskBasicInfo{ + Device: dev.Name, + Size: totalSize, + Model: dev.Model, + DiskType: diskType, + Filesystem: child.Fstype, + MountPoint: child.Mountpoint, + IsMounted: true, + UsePercent: usePercent, + Used: used, + Avail: avail, + Serial: dev.Serial, + IsRemovable: dev.Tran == "usb", + IsSystem: isSystemDisk(child.Mountpoint), + } + list = append(list, childInfo) + } + } + return list + } else if isMounted { + isSystem = isSystemDisk(mountPoint) + devicePath := "/dev/" + dev.Name + totalSize, used, avail, usePercent, _ = getDiskUsageInfo(devicePath) + if totalSize != "" { + size = totalSize + } + } + + info := response.DiskBasicInfo{ + Device: dev.Name, + Size: size, + Model: dev.Model, + DiskType: diskType, + Filesystem: filesystem, + MountPoint: mountPoint, + IsMounted: isMounted, + UsePercent: usePercent, + Used: used, + Avail: avail, + Serial: dev.Serial, + IsRemovable: dev.Tran == "usb", + IsSystem: isSystem, + } + + list = append(list, info) + + for _, child := range dev.Children { + childList := parseDevice(child) + list = append(list, childList...) + } + + return list +} + +func parseLsblkJsonOutput(output string) ([]response.DiskBasicInfo, error) { + raw := &LsblkRaw{} + if err := json.Unmarshal([]byte(output), raw); err != nil { + return nil, fmt.Errorf("failed to parse lsblk json output: %v", err) + } + var disks []response.DiskBasicInfo + + for _, dev := range raw.Blockdevices { + if strings.HasPrefix(dev.Name, "loop") || + strings.HasPrefix(dev.Name, "dm-") { + continue + } + devList := parseDevice(dev) + disks = append(disks, devList...) + } + return disks, nil +} + func organizeDiskInfo(diskInfos []response.DiskBasicInfo) response.CompleteDiskInfo { var result response.CompleteDiskInfo - var systemDisk *response.DiskInfo diskMap := make(map[string]*response.DiskInfo) partitions := make(map[string][]response.DiskBasicInfo) @@ -55,7 +179,7 @@ func organizeDiskInfo(diskInfos []response.DiskBasicInfo) response.CompleteDiskI totalCapacity += capacity if disk.IsSystem { - systemDisk = disk + result.SystemDisks = append(result.SystemDisks, *disk) } else if len(disk.Partitions) == 0 { result.UnpartitionedDisks = append(result.UnpartitionedDisks, disk.DiskBasicInfo) } else { @@ -63,7 +187,6 @@ func organizeDiskInfo(diskInfos []response.DiskBasicInfo) response.CompleteDiskI } } - result.SystemDisk = systemDisk result.TotalDisks = len(diskMap) result.TotalCapacity = totalCapacity @@ -162,17 +285,25 @@ func parseLsblkOutput(output string) ([]response.DiskBasicInfo, error) { if fsType == "LVM2_member" { for _, lvmInfo := range lvmMap { if lvmInfo.IsMounted { - actualMountPoint = lvmInfo.MountPoint - actualFsType = lvmInfo.Filesystem - actualUsed = lvmInfo.Used - size = lvmInfo.Size - actualAvail = lvmInfo.Avail - actualUsePercent = lvmInfo.UsePercent - isMounted = true - isSystemPartition = lvmInfo.IsSystem - break + lvmDiskInfo := response.DiskBasicInfo{ + Device: name, + Size: lvmInfo.Size, + Model: model, + DiskType: "LVM", + IsRemovable: tran == "usb", + IsSystem: lvmInfo.IsSystem, + Filesystem: lvmInfo.Filesystem, + Used: lvmInfo.Used, + Avail: lvmInfo.Avail, + UsePercent: lvmInfo.UsePercent, + MountPoint: lvmInfo.MountPoint, + IsMounted: true, + Serial: serial, + } + diskInfos = append(diskInfos, lvmDiskInfo) } } + continue } info := response.DiskBasicInfo{ diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index 98d3285e8..934159274 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -241,7 +241,7 @@ export namespace Host { export interface CompleteDiskInfo { disks: DiskInfo[]; unpartitionedDisks: DiskBasicInfo[]; - systemDisk?: DiskInfo; + systemDisks?: DiskInfo[]; totalDisks: number; totalCapacity: number; } diff --git a/frontend/src/views/host/disk-management/disk/index.vue b/frontend/src/views/host/disk-management/disk/index.vue index 52e3d8887..c3a1b7365 100644 --- a/frontend/src/views/host/disk-management/disk/index.vue +++ b/frontend/src/views/host/disk-management/disk/index.vue @@ -2,8 +2,14 @@
-
- +
+