func GetDevicePartitions(device string, executor exec.Executor) (partitions []Partition, unusedSpace uint64, err error) {
	var devicePath string
	splitDevicePath := strings.Split(device, "/")
	if len(splitDevicePath) == 1 {
		devicePath = fmt.Sprintf("/dev/%s", device)  
	} else {
		devicePath = device  
	}
	output, err := executor.ExecuteCommandWithOutput("lsblk", devicePath,
		"--bytes", "--pairs", "--output", "NAME,SIZE,TYPE,PKNAME")
	logger.Infof("Output: %+v", output)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to get device %s partitions. %+v", device, err)
	}
	partInfo := strings.Split(output, "\n")
	var deviceSize uint64
	var totalPartitionSize uint64
	for _, info := range partInfo {
		props := parseKeyValuePairString(info)
		name := props["NAME"]
		if name == device {
			logger.Info("Device found - ", name)
			deviceSize, err = strconv.ParseUint(props["SIZE"], 10, 64)
			if err != nil {
				return nil, 0, fmt.Errorf("failed to get device %s size. %+v", device, err)
			}
		} else if props["PKNAME"] == device && props["TYPE"] == PartType {
			p := Partition{Name: name}
			p.Size, err = strconv.ParseUint(props["SIZE"], 10, 64)
			if err != nil {
				return nil, 0, fmt.Errorf("failed to get partition %s size. %+v", name, err)
			}
			totalPartitionSize += p.Size
			info, err := GetUdevInfo(name, executor)
			if err != nil {
				return nil, 0, err
			}
			if v, ok := info["PARTNAME"]; ok {
				p.Label = v
			}
			if v, ok := info["ID_PART_ENTRY_NAME"]; ok {
				p.Label = v
			}
			if v, ok := info["ID_FS_TYPE"]; ok {
				p.Filesystem = v
			}
			partitions = append(partitions, p)
		}
	}
	if deviceSize > 0 {
		unusedSpace = deviceSize - totalPartitionSize
	}
	return partitions, unusedSpace, nil
}
GetDevicePartitions gets partitions on a given device
package sys
import (
	"fmt"
	"github.com/alauda/topolvm-operator/pkg/util/exec"
	osexec "os/exec"
	"path"
	"strconv"
	"strings"
	"github.com/google/uuid"
)
const (
	DiskType = "disk"
	SSDType = "ssd"
	PartType = "part"
	CryptType = "crypt"
	LVMType = "lvm"
	MultiPath = "mpath"
	LinearType = "linear"
	sgdiskCmd  = "sgdisk"
	LoopType = "loop"
)
type Partition struct {
	Name       string
	Size       uint64
	Label      string
	Filesystem string
}
type LocalDisk struct {
	Name string `json:"name"`
	Parent string `json:"parent"`
	HasChildren bool `json:"hasChildren"`
	DevLinks string `json:"devLinks"`
	Size uint64 `json:"size"`
	UUID string `json:"uuid"`
	Serial string `json:"serial"`
	Type string `json:"type"`
	Rotational bool `json:"rotational"`
	Readonly bool `json:"readOnly"`
	Partitions []Partition
	Filesystem string `json:"filesystem"`
	Vendor string `json:"vendor"`
	Model string `json:"model"`
	WWN string `json:"wwn"`
	WWNVendorExtension string `json:"wwnVendorExtension"`
	Empty bool `json:"empty"`
	RealPath string `json:"real-path,omitempty"`
	KernelName string `json:"kernel-name,omitempty"`
	Encrypted bool `json:"encrypted,omitempty"`
}
func ListDevices(executor exec.Executor) ([]string, error) {
	devices, err := executor.ExecuteCommandWithOutput("lsblk", "--all", "--noheadings", "--list", "--output", "KNAME")
	if err != nil {
		return nil, fmt.Errorf("failed to list all devices: %v", err)
	}
	return strings.Split(devices, "\n"), nil
}