Files
Olares/cli/pkg/utils/lvm/tools.go
eball 36b4e792f6 daemon: add non-interactive flags to disk extend commands (#2148)
daemon: add nointeractive flags to disk extend commands
2025-12-04 00:19:12 +08:00

273 lines
6.0 KiB
Go

package lvm
import (
"errors"
"log"
"os"
"os/exec"
"slices"
)
func FindCurrentLVM() ([]*VgItem, error) {
VG := CommandVGS()
result, errmsg, err := VG.Run()
if err != nil {
log.Printf("failed to run vgs command: %s \n%s\n", err, errmsg)
return nil, err
}
if len(result.Report) == 0 || len(result.Report[0].Vg) == 0 {
err = errors.New("no volume groups found")
return nil, err
}
var vgs []*VgItem
for _, vg := range result.Report[0].Vg {
if vg.PvCount == "0" || vg.LvCount == "0" {
continue
}
vgs = append(vgs, &vg)
}
if len(vgs) == 0 {
err = errors.New("no valid volume groups found")
return nil, err
}
return vgs, nil
}
func FindUnmountedDevices() (map[string]*BlkPart, error) {
lblkCmd := CommandLBLK()
result, errmsg, err := lblkCmd.Run()
if err != nil {
log.Printf("failed to run lsblk command: %s \n%s\n", err, errmsg)
return nil, err
}
var unmountedDevices map[string]*BlkPart = make(map[string]*BlkPart)
var unmountedPart func(part BlkPart) bool
unmountedPart = func(part BlkPart) bool {
if len(part.Mountpoints) > 0 {
return false
}
if len(part.Mountpoints) == 0 && len(part.Children) == 0 {
return true
}
for _, child := range part.Children {
if !unmountedPart(child) {
return false
}
}
return true
}
for _, dev := range result.Blockdevices {
if dev.Type != "disk" {
continue
}
if unmountedPart(dev) {
unmountedDevices["/dev/"+dev.Name] = &dev
}
}
return unmountedDevices, nil
}
func FindLvByVgName(vgName string) ([]*LvItem, error) {
LV := CommandLVS()
result, errmsg, err := LV.Run("-o", "+lv_dm_path,lv_path")
if err != nil {
log.Printf("failed to run lvs command: %s \n%s\n", err, errmsg)
return nil, err
}
if len(result.Report) == 0 || len(result.Report[0].Lv) == 0 {
return nil, nil
}
var lvs []*LvItem
for _, lv := range result.Report[0].Lv {
if lv.VgName == vgName {
mountpoints, err := FindMountpointsByLvDmPath(lv.LvDmPath)
if err == nil {
lv.Mountpoints = mountpoints
}
lvs = append(lvs, &lv)
}
}
return lvs, nil
}
func FindMountpointsByLvDmPath(lvDmPath string) ([]string, error) {
FINDMNT := CommandFindMnt()
result, errmsg, err := FINDMNT.Run(lvDmPath)
if err != nil && errmsg != "" {
log.Printf("failed to run findmnt command: %s \n%s\n", err, errmsg)
return nil, err
}
if result == nil || len(result.Filesystems) == 0 {
return nil, nil
}
var mountpoints []string
for _, fs := range result.Filesystems {
mountpoints = append(mountpoints, fs.Target)
}
return mountpoints, nil
}
/*
wipefs -a /dev/nvme0n1
sgdisk --zap-all /dev/nvme0n1
*/
func DeleteDevicePartitions(devicePath string) error {
c, err := exec.Command("wipefs", "-a", devicePath).CombinedOutput()
if err != nil {
log.Printf("failed to wipe device %s: %s\n", devicePath, c)
return err
}
// c, err = exec.Command("sgdisk", "--zap-all", devicePath).CombinedOutput()
// if err != nil {
// log.Printf("failed to zap device %s: %s\n", devicePath, c)
// return err
// }
return nil
}
/*
sudo parted /dev/sdX mklabel gpt
sudo parted -a optimal /dev/sdX mkpart primary 1MiB 100%
*/
func MakePartOnDevice(devicePath string) error {
c, err := exec.Command("parted", "-s", devicePath, "mklabel", "gpt").CombinedOutput()
if err != nil {
log.Printf("failed to make partition table on device %s: %s\n", devicePath, c)
return err
}
c, err = exec.Command("parted", "-a", "optimal", devicePath, "mkpart", "primary", "1MiB", "100%").CombinedOutput()
if err != nil {
log.Printf("failed to make partition on device %s: %s\n", devicePath, c)
return err
}
return nil
}
/*
sudo pvcreate /dev/sdX1
sudo vgextend target_vg /dev/sdX1
*/
func AddNewPV(devicePath string, vg string) error {
partition := devicePath + "p1"
c, err := exec.Command("pvcreate", "-f", partition).CombinedOutput()
if err != nil {
log.Printf("failed to create physical volume on device %s: %s\n", partition, c)
return err
}
c, err = exec.Command("vgextend", vg, partition).CombinedOutput()
if err != nil {
log.Printf("failed to extend volume group %s with device %s: %s\n", vg, partition, c)
return err
}
return nil
}
/*
lvextend -l +100%FREE "/dev/$VG_NAME/$LV_ROOT_NAME"
resize2fs "/dev/$VG_NAME/$LV_ROOT_NAME"
*/
func ExtendLv(vg, lv string) error {
c, err := exec.Command("lvextend", "-l", "+100%FREE", "/dev/"+vg+"/"+lv).CombinedOutput()
if err != nil {
log.Printf("failed to extend logical volume %s in volume group %s: %s\n", lv, vg, c)
return err
}
c, err = exec.Command("resize2fs", "/dev/"+vg+"/"+lv).CombinedOutput()
if err != nil {
log.Printf("failed to resize filesystem on logical volume %s in volume group %s: %s\n", lv, vg, c)
return err
}
return nil
}
func DeactivateLv(vg string) error {
c, err := exec.Command("lvchange", "-an", vg).CombinedOutput()
if err != nil {
log.Printf("failed to deactivate logical volume in volume group %s: %s\n", vg, c)
return err
}
return nil
}
func RemoveLv(lvpath string) error {
_, err := os.Stat(lvpath)
if err != nil {
if os.IsNotExist(err) {
return nil
}
log.Printf("failed to stat logical volume %s: %s\n", lvpath, err)
return err
}
c, err := exec.Command("lvremove", "-f", lvpath).CombinedOutput()
if err != nil {
log.Printf("failed to remove logical volume %s: %s\n", lvpath, c)
return err
}
return nil
}
func RemoveVg(vg string) error {
c, err := exec.Command("vgremove", "-f", vg).CombinedOutput()
if err != nil {
log.Printf("failed to remove volume group %s: %s\n", vg, c)
return err
}
return nil
}
func RemovePv(pv string) error {
c, err := exec.Command("pvremove", "-f", pv).CombinedOutput()
if err != nil {
log.Printf("failed to remove physical volume %s: %s\n", pv, c)
return err
}
return nil
}
func FindVgsOnDevice(devicePaths []string) ([]*VgItem, error) {
VG := CommandVGS()
result, errmsg, err := VG.Run("-o", "+pv_name")
if err != nil {
log.Printf("failed to run vgs command: %s \n%s\n", err, errmsg)
return nil, err
}
var vgs []*VgItem
for _, vg := range result.Report[0].Vg {
if slices.Contains(devicePaths, vg.PvName) {
vgs = append(vgs, &vg)
}
}
return vgs, nil
}