|
@@ -0,0 +1,121 @@
|
|
|
|
+package raid
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "fmt"
|
|
|
|
+ "os"
|
|
|
|
+ "os/exec"
|
|
|
|
+ "strconv"
|
|
|
|
+ "strings"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ mdadm manager
|
|
|
|
+
|
|
|
|
+ This script handles the interaction with mdadm
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+type StorageDeviceMeta struct {
|
|
|
|
+ Name string
|
|
|
|
+ Size int64
|
|
|
|
+ RO bool
|
|
|
|
+ DevType string
|
|
|
|
+ MountPoint string
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// List all the storage device in the system, set minSize to 0 for no filter
|
|
|
|
+func (m *Manager) ListAllStorageDevices(minSize int64) ([]*StorageDeviceMeta, error) {
|
|
|
|
+ cmd := exec.Command("sudo", "lsblk", "-b")
|
|
|
|
+
|
|
|
|
+ output, err := cmd.CombinedOutput()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, fmt.Errorf("lsblk error: %v", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Split the output into lines
|
|
|
|
+ lines := strings.Split(string(output), "\n")
|
|
|
|
+
|
|
|
|
+ var devices []*StorageDeviceMeta
|
|
|
|
+
|
|
|
|
+ // Parse each line to extract device information
|
|
|
|
+ for _, line := range lines[1:] { // Skip the header line
|
|
|
|
+ fields := strings.Fields(line)
|
|
|
|
+ if len(fields) < 7 {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ size, err := strconv.ParseInt(fields[3], 10, 64)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, fmt.Errorf("error parsing device size: %v", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ro := fields[4] == "1"
|
|
|
|
+
|
|
|
|
+ device := &StorageDeviceMeta{
|
|
|
|
+ Name: fields[0],
|
|
|
|
+ Size: size,
|
|
|
|
+ RO: ro,
|
|
|
|
+ DevType: fields[5],
|
|
|
|
+ MountPoint: fields[6],
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Filter devices based on minimum size
|
|
|
|
+ if size >= minSize {
|
|
|
|
+ devices = append(devices, device)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return devices, nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Return the uuid of the disk by its path name (e.g. /dev/sda)
|
|
|
|
+func (m *Manager) GetDiskUUIDByPath(devicePath string) (string, error) {
|
|
|
|
+ cmd := exec.Command("sudo", "blkid", devicePath)
|
|
|
|
+
|
|
|
|
+ output, err := cmd.CombinedOutput()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return "", fmt.Errorf("blkid error: %v", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Parse the output to extract the UUID
|
|
|
|
+ fields := strings.Fields(string(output))
|
|
|
|
+ for _, field := range fields {
|
|
|
|
+ if strings.HasPrefix(field, "UUID=") {
|
|
|
|
+ uuid := strings.TrimPrefix(field, "UUID=\"")
|
|
|
|
+ uuid = strings.TrimSuffix(uuid, "\"")
|
|
|
|
+ return uuid, nil
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return "", fmt.Errorf("UUID not found for device %s", devicePath)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// CreateRAIDDevice creates a RAID device using the mdadm command.
|
|
|
|
+func (m *Manager) CreateRAIDDevice(devName string, raidLevel int, raidDev int, spareDevice int, raidDeviceIds []string, spareDeviceIds []string) error {
|
|
|
|
+ if len(raidDeviceIds) < raidDev {
|
|
|
|
+ return fmt.Errorf("insufficient RAID devices specified")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if len(spareDeviceIds) < spareDevice {
|
|
|
|
+ return fmt.Errorf("insufficient spare devices specified")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Concatenate RAID and spare device arrays
|
|
|
|
+ allDeviceIds := append(raidDeviceIds, spareDeviceIds...)
|
|
|
|
+
|
|
|
|
+ // Build the mdadm command
|
|
|
|
+ cmdArgs := []string{"mdadm", "--create", devName, fmt.Sprintf("--level=%d", raidLevel),
|
|
|
|
+ fmt.Sprintf("--raid-devices=%d", raidDev), fmt.Sprintf("--spare-devices=%d", spareDevice)}
|
|
|
|
+ cmdArgs = append(cmdArgs, allDeviceIds...)
|
|
|
|
+
|
|
|
|
+ cmd := exec.Command("sudo", cmdArgs...)
|
|
|
|
+
|
|
|
|
+ cmd.Stdout = os.Stdout
|
|
|
|
+ cmd.Stderr = os.Stderr
|
|
|
|
+
|
|
|
|
+ err := cmd.Run()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("error running mdadm command: %v", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return nil
|
|
|
|
+}
|