Skip to content

Commit

Permalink
util: put ParseDiskSpec func to common
Browse files Browse the repository at this point in the history
  • Loading branch information
HuijingHei committed May 29, 2023
1 parent 3dff7ab commit e853e0e
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 62 deletions.
44 changes: 17 additions & 27 deletions mantle/platform/api/gcloud/compute.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package gcloud
import (
"crypto/rand"
"fmt"
"strconv"
"strings"
"time"

Expand All @@ -35,32 +34,23 @@ func (a *API) vmname() string {
return fmt.Sprintf("%s-%x", a.options.BaseName, b)
}

// ["5G:interface=NVME"], by default the disk type is local-ssd
func ParseDiskSpec(spec string, zone string) (*compute.AttachedDisk, error) {
split := strings.Split(spec, ":")
// ["5G:channel=nvme"], by default the disk type is local-ssd
func ParseDisk(spec string, zone string) (*compute.AttachedDisk, error) {
var diskmap map[string]string
var disksize int64
var diskinterface string
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 strings.HasPrefix(opt, "interface=") {
diskinterface = strings.TrimPrefix(opt, "interface=")
if diskinterface == "" || (diskinterface != "NVME" && diskinterface != "SCSI") {
return nil, fmt.Errorf("invalid interface opt %s", opt)
}
} else {
return nil, fmt.Errorf("unknown disk option %s", opt)
}
}
} else {
return nil, fmt.Errorf("invalid disk spec %s", spec)
var err error

if disksize, diskmap, err = util.ParseDiskSpec(spec); err != nil {
return nil, fmt.Errorf("failed to parse disk spec %s: %w", spec, err)
}
disksize = strings.TrimSuffix(disksize, "G")
size, err := strconv.ParseInt(disksize, 10, 32)
if err != nil {
return nil, fmt.Errorf("invalid size opt %s: %w", disksize, err)
for key, value := range diskmap {
switch key {
case "Channel":
diskinterface = strings.ToUpper(value)
default:
return nil, fmt.Errorf("invalid key %s", key)
}
}

return &compute.AttachedDisk{
Expand All @@ -70,7 +60,7 @@ func ParseDiskSpec(spec string, zone string) (*compute.AttachedDisk, error) {
Interface: diskinterface,
InitializeParams: &compute.AttachedDiskInitializeParams{
DiskType: "/zones/" + zone + "/diskTypes/local-ssd",
DiskSizeGb: size,
DiskSizeGb: disksize,
},
}, nil
}
Expand Down Expand Up @@ -165,7 +155,7 @@ func (a *API) mkinstance(userdata, name string, keys []*agent.Key, opts platform
// attach aditional disk
for _, spec := range opts.AdditionalDisks {
plog.Debugf("Parsing disk spec %q\n", spec)
disk, err := ParseDiskSpec(spec, a.options.Zone)
disk, err := ParseDisk(spec, a.options.Zone)
if err != nil {
return nil, fmt.Errorf("failed to parse spec %s: %w", spec, err)
}
Expand Down
63 changes: 28 additions & 35 deletions mantle/platform/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"net"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
Expand Down Expand Up @@ -101,47 +102,39 @@ type Disk struct {
nbdServCmd exec.Cmd // command to serve the disk
}

// ParseDiskSpec converts a disk specification into a Disk. The format is:
// <size>[:<opt1>,<opt2>,...].
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 int64
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)
}
multipathed := false
var err error

if disksize, diskmap, err = util.ParseDiskSpec(spec); err != nil {
return nil, fmt.Errorf("failed to parse disk spec %s: %w", spec, err)
}

for key, value := range diskmap {
switch key {
case "Channel":
channel = value
case "SectorSize":
sectorSize, _ = strconv.ParseInt(value, 10, 32)
case "MultiPathDisk":
multipathed, _ = strconv.ParseBool(value)
case "DeviceOpts":
serial_opt = append(serial_opt, value)
default:
return nil, fmt.Errorf("invalid key %s", key)
}
} else {
return nil, fmt.Errorf("invalid disk spec %s", spec)
}

return &Disk{
Size: size,
Size: fmt.Sprintf("%dG", disksize),
Channel: channel,
DeviceOpts: serial_opt,
SectorSize: sectorSize,
SectorSize: int(sectorSize),
MultiPathDisk: multipathed,
}, nil
}
Expand Down Expand Up @@ -1225,7 +1218,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)
Expand Down
44 changes: 44 additions & 0 deletions mantle/util/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"time"
"unsafe"

Expand Down Expand Up @@ -120,3 +122,45 @@ 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:
// <size>[:<opt1>,<opt2>,...], like ["5G:channel=nvme"]
func ParseDiskSpec(spec string) (int64, map[string]string, error) {
diskmap := map[string]string{}
split := strings.Split(spec, ":")
if split[0] == "" || (!strings.HasSuffix(split[0], "G")) {
return 0, nil, fmt.Errorf("invalid size opt %s", 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 0, 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 0, nil, fmt.Errorf("invalid serial opt %s", opt)
}
diskmap["DeviceOpts"] = "serial=" + serial
} else {
return 0, nil, fmt.Errorf("unknown disk option %s", opt)
}
}
} else {
return 0, nil, fmt.Errorf("invalid disk spec %s", spec)
}
disksize = strings.TrimSuffix(disksize, "G")
size, _ := strconv.ParseInt(disksize, 10, 32)
return size, diskmap, nil
}

0 comments on commit e853e0e

Please sign in to comment.