diff --git a/mantle/platform/qemu.go b/mantle/platform/qemu.go index 07e763c7fe..f2e3948daa 100644 --- a/mantle/platform/qemu.go +++ b/mantle/platform/qemu.go @@ -38,6 +38,7 @@ import ( "net" "os" "path/filepath" + "strconv" "strings" "syscall" "time" @@ -101,47 +102,35 @@ type Disk struct { nbdServCmd exec.Cmd // command to serve the disk } -// ParseDiskSpec converts a disk specification into a Disk. The format is: -// [:,,...]. -func ParseDiskSpec(spec string) (*Disk, error) { - split := strings.Split(spec, ":") - var size string +func ParseDisk(spec string) (*Disk, error) { + var diskmap map[string]string + var disksize string var channel string - multipathed := false - sectorSize := 0 + var sectorSize int64 serial_opt := []string{} - if len(split) == 1 { - size = split[0] - } else if len(split) == 2 { - size = split[0] - for _, opt := range strings.Split(split[1], ",") { - if opt == "mpath" { - multipathed = true - } else if opt == "4k" { - sectorSize = 4096 - } else if strings.HasPrefix(opt, "channel=") { - channel = strings.TrimPrefix(opt, "channel=") - if channel == "" { - return nil, fmt.Errorf("invalid channel opt %s", opt) - } - } else if strings.HasPrefix(opt, "serial=") { - serial := strings.TrimPrefix(opt, "serial=") - if serial == "" { - return nil, fmt.Errorf("invalid serial opt %s", opt) - } - serial_opt = []string{"serial=" + serial} - } else { - return nil, fmt.Errorf("unknown disk option %s", opt) - } - } - } else { - return nil, fmt.Errorf("invalid disk spec %s", spec) + multipathed := false + var err error + + if disksize, diskmap, err = util.ParseDiskSpec(spec); err != nil { + return nil, fmt.Errorf("failed to parse disk spec %s", spec) + } + if value, found := diskmap["Channel"]; found { + channel = value + } + if value, found := diskmap["SectorSize"]; found { + sectorSize, _ = strconv.ParseInt(value, 10, 32) + } + if value, found := diskmap["MultiPathDisk"]; found { + multipathed, _ = strconv.ParseBool(value) + } + if value, found := diskmap["DeviceOpts"]; found { + serial_opt = append(serial_opt, value) } return &Disk{ - Size: size, + Size: disksize, Channel: channel, DeviceOpts: serial_opt, - SectorSize: sectorSize, + SectorSize: int(sectorSize), MultiPathDisk: multipathed, }, nil } @@ -1225,7 +1214,7 @@ func (builder *QemuBuilder) AddDisk(disk *Disk) error { // AddDisksFromSpecs adds multiple secondary disks from their specs. func (builder *QemuBuilder) AddDisksFromSpecs(specs []string) error { for _, spec := range specs { - if disk, err := ParseDiskSpec(spec); err != nil { + if disk, err := ParseDisk(spec); err != nil { return errors.Wrapf(err, "parsing additional disk spec '%s'", spec) } else if err = builder.AddDisk(disk); err != nil { return errors.Wrapf(err, "adding additional disk '%s'", spec) diff --git a/mantle/util/common.go b/mantle/util/common.go index d78d7fa2ff..df92174576 100644 --- a/mantle/util/common.go +++ b/mantle/util/common.go @@ -19,6 +19,7 @@ import ( "os" "os/exec" "path/filepath" + "strings" "time" "unsafe" @@ -120,3 +121,40 @@ func RunCmdTimeout(timeout time.Duration, cmd string, args ...string) error { return fmt.Errorf("%s timed out after %s", cmd, timeout) } } + +// ParseDiskSpec converts a disk specification into a Disk. The format is: +// [:,,...], like ["5G:interface=NVME"] +func ParseDiskSpec(spec string) (string, map[string]string, error) { + diskmap := map[string]string{} + split := strings.Split(spec, ":") + var disksize string + if len(split) == 1 { + disksize = split[0] + } else if len(split) == 2 { + disksize = split[0] + for _, opt := range strings.Split(split[1], ",") { + if opt == "mpath" { + diskmap["MultiPathDisk"] = "true" + } else if opt == "4k" { + diskmap["SectorSize"] = "4096" + } else if strings.HasPrefix(opt, "channel=") { + channel := strings.TrimPrefix(opt, "channel=") + if channel == "" { + return "", nil, fmt.Errorf("invalid channel opt %s", opt) + } + diskmap["Channel"] = channel + } else if strings.HasPrefix(opt, "serial=") { + serial := strings.TrimPrefix(opt, "serial=") + if serial == "" { + return "", nil, fmt.Errorf("invalid serial opt %s", opt) + } + diskmap["DeviceOpts"] = "serial=" + serial + } else { + return "", nil, fmt.Errorf("unknown disk option %s", opt) + } + } + } else { + return "", nil, fmt.Errorf("invalid disk spec %s", spec) + } + return disksize, diskmap, nil +}