273 lines
6.0 KiB
Go
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
|
|
}
|