diff --git a/README.md b/README.md index 007f4de..0131abb 100644 --- a/README.md +++ b/README.md @@ -84,15 +84,16 @@ $ sudo chmod u+s $GOPATH/bin/docker-machine-driver-xhyve ### Available flags -| Flag name | Environment variable | Type | Description | Default | -|----------------------------------|--------------------------------|--------|------------------------------------------|----------------------------------------------------------| -| `--xhyve-boot2docker-url` | `XHYVE_BOOT2DOCKER_URL` | string | The URL(Path) of the boot2docker image | `$HOME/.docker/machine/cache/boot2docker.iso` | -| `--xhyve-cpu-count` | `XHYVE_CPU_COUNT` | int | Number of CPUs to use the create the VM | `1` | -| `--xhyve-memory-size` | `XHYVE_MEMORY_SIZE` | int | Size of memory for the guest | `1024` | -| `--xhyve-disk-size` | `XHYVE_DISK_SIZE` | int | Size of disk for the guest (MB) | `20000` | -| `--xhyve-boot-cmd` | `XHYVE_BOOT_CMD` | string | Booting xhyve iPXE commands | See [boot2docker/boot2docker/doc/AUTOMATED_SCRIPT.md][1] | -| `--xhyve-virtio-9p` | `XHYVE_VIRTIO_9P` | bool | Enable `virtio-9p` folder share | `false` | -| `--xhyve-experimental-nfs-share` | `XHYVE_EXPERIMENTAL_NFS_SHARE` | bool | Enable `NFS` folder share (experimental) | `false` | +| Flag name | Environment variable | Type | Description | Default | +|---------------------------------------|---------------------------------------|--------|------------------------------------------|----------------------------------------------------------| +| `--xhyve-boot2docker-url` | `XHYVE_BOOT2DOCKER_URL` | string | The URL(Path) of the boot2docker image | `$HOME/.docker/machine/cache/boot2docker.iso` | +| `--xhyve-cpu-count` | `XHYVE_CPU_COUNT` | int | Number of CPUs to use the create the VM | `1` | +| `--xhyve-memory-size` | `XHYVE_MEMORY_SIZE` | int | Size of memory for the guest | `1024` | +| `--xhyve-disk-size` | `XHYVE_DISK_SIZE` | int | Size of disk for the guest (MB) | `20000` | +| `--xhyve-boot-cmd` | `XHYVE_BOOT_CMD` | string | Booting xhyve iPXE commands | See [boot2docker/boot2docker/doc/AUTOMATED_SCRIPT.md][1] | +| `--xhyve-virtio-9p` | `XHYVE_VIRTIO_9P` | bool | Enable `virtio-9p` folder share | `false` | +| `--xhyve-experimental-nfs-share` | `XHYVE_EXPERIMENTAL_NFS_SHARE` | bool | Enable `NFS` folder share (experimental) | `false` | +| `--xhyve-experimental-attach-image` | `XHYVE_EXPERIMENTAL_ATTACH_IMAGE` | string | Attach a custom disk image (experimental)| ` ` | If you want use `virtio-9p` folder sharing, need custom `boot2docker.iso`. See https://github.com/zchee/boot2docker-legacy/releases. diff --git a/xhyve/xhyve.go b/xhyve/xhyve.go index 74d3b2a..71c2a06 100644 --- a/xhyve/xhyve.go +++ b/xhyve/xhyve.go @@ -10,6 +10,7 @@ import ( "os" "os/exec" "os/user" + "path" "path/filepath" "regexp" "runtime" @@ -44,26 +45,31 @@ const ( defaultUUID = "" defaultNFSShare = false rootVolumeName = "root-volume" - defaultDiskNumber = -1 defaultVirtio9p = false ) +type DiskImage struct { + Path string + diskNumber int +} + type Driver struct { *drivers.BaseDriver *b2d.B2dUtils - Boot2DockerURL string - BootCmd string - CPU int - CaCertPath string - DiskSize int64 - MacAddr string - Memory int - PrivateKeyPath string - UUID string - NFSShare bool - DiskNumber int - Virtio9p bool - Virtio9pFolder string + Boot2DockerURL string + BootCmd string + CPU int + CaCertPath string + DiskSize int64 + MacAddr string + Memory int + PrivateKeyPath string + UUID string + NFSShare bool + Virtio9p bool + Virtio9pFolder string + RootVolumeDiskImage *DiskImage + DiskImages []*DiskImage } var ( @@ -89,8 +95,10 @@ func NewDriver(hostName, storePath string) *Driver { PrivateKeyPath: defaultPrivateKeyPath, UUID: defaultUUID, NFSShare: defaultNFSShare, - DiskNumber: defaultDiskNumber, Virtio9p: defaultVirtio9p, + RootVolumeDiskImage: &DiskImage{ + Path: rootVolumeName + ".sparsebundle", + }, } } @@ -128,6 +136,11 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag { Usage: "Command of booting kexec protocol", Value: defaultBootCmd, }, + mcnflag.StringSliceFlag{ + EnvVar: "XHYVE_EXPERIMENTAL_ATTACH_IMAGE", + Name: "xhyve-experimental-attach-image", + Usage: "Attach a sparsebundle image.", + }, mcnflag.BoolFlag{ EnvVar: "XHYVE_VIRTIO_9P", Name: "xhyve-virtio-9p", @@ -187,6 +200,9 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.Virtio9p = flags.Bool("xhyve-virtio-9p") d.Virtio9pFolder = "/Users" d.NFSShare = flags.Bool("xhyve-experimental-nfs-share") + for _, v := range flags.StringSlice("xhyve-experimental-attach-image") { + d.DiskImages = append(d.DiskImages, &DiskImage{Path: v}) + } return nil } @@ -411,7 +427,12 @@ func (d *Driver) Start() error { os.Remove(pid) } - d.attachDiskImage() + d.attachDiskImage(d.RootVolumeDiskImage) + + for _, v := range d.DiskImages { + log.Info("Attaching optional volume ", v.Path) + d.attachDiskImage(v) + } args := d.xhyveArgs() args = append(args, "-F", fmt.Sprintf("%s", pid)) @@ -463,7 +484,11 @@ func (d *Driver) Stop() error { } d.IPAddress = "" - d.detachDiskImage() + d.detachDiskImage(d.RootVolumeDiskImage) + + for _, v := range d.DiskImages { + d.detachDiskImage(v) + } return nil } @@ -483,7 +508,7 @@ func (d *Driver) Remove() error { } } - if err := d.removeDiskImage(); err != nil { + if err := d.removeDiskImage(d.RootVolumeDiskImage); err != nil { return err } @@ -582,13 +607,13 @@ func (d *Driver) extractKernelImages() error { } func (d *Driver) generateDiskImage(count int64) error { - diskPath := d.ResolveStorePath(rootVolumeName) + diskPath := d.ResolveStorePath(d.RootVolumeDiskImage.Path) if err := hdiutil("create", "-megabytes", fmt.Sprintf("%d", count), "-type", "SPARSEBUNDLE", diskPath); err != nil { return err } - if err := d.attachDiskImage(); err != nil { + if err := d.attachDiskImage(d.RootVolumeDiskImage); err != nil { return err } @@ -597,7 +622,7 @@ func (d *Driver) generateDiskImage(count int64) error { return err } - file, err := os.OpenFile(fmt.Sprintf("/dev/rdisk%d", d.DiskNumber), os.O_WRONLY, 0644) + file, err := os.OpenFile(fmt.Sprintf("/dev/rdisk%d", d.RootVolumeDiskImage.diskNumber), os.O_WRONLY, 0644) if err != nil { return err } @@ -612,8 +637,14 @@ func (d *Driver) generateDiskImage(count int64) error { return nil } -func (d *Driver) attachDiskImage() error { - diskPath := d.ResolveStorePath(rootVolumeName + ".sparsebundle") +func (d *Driver) attachDiskImage(dImage *DiskImage) error { + var diskPath string + if !path.IsAbs(dImage.Path) { + diskPath = d.ResolveStorePath(dImage.Path) + } else { + diskPath = dImage.Path + } + cmd := exec.Command("hdiutil", "attach", "-nomount", "-noverify", "-noautofsck", diskPath) output, err := cmd.Output() if err != nil { @@ -625,7 +656,7 @@ func (d *Driver) attachDiskImage() error { return fmt.Errorf("Failed parsing disk number, hdiutil output: %s", string(output)) } - d.DiskNumber, err = strconv.Atoi(string(matches[1])) + dImage.diskNumber, err = strconv.Atoi(string(matches[1])) if err != nil { return err } @@ -633,18 +664,24 @@ func (d *Driver) attachDiskImage() error { return nil } -func (d *Driver) detachDiskImage() error { - if err := hdiutil("detach", fmt.Sprintf("/dev/disk%d", d.DiskNumber)); err != nil { +func (d *Driver) detachDiskImage(dImage *DiskImage) error { + if err := hdiutil("detach", fmt.Sprintf("/dev/disk%d", dImage.diskNumber)); err != nil { return err } - d.DiskNumber = -1 + dImage.diskNumber = -1 return nil } -func (d *Driver) removeDiskImage() error { - diskPath := d.ResolveStorePath(rootVolumeName + ".sparsebundle") +func (d *Driver) removeDiskImage(dImage *DiskImage) error { + var diskPath string + if !path.IsAbs(dImage.Path) { + diskPath = d.ResolveStorePath(dImage.Path) + } else { + diskPath = dImage.Path + } + return os.RemoveAll(diskPath) } @@ -804,7 +841,7 @@ func (d *Driver) xhyveArgs() []string { vmlinuz := d.ResolveStorePath("vmlinuz64") initrd := d.ResolveStorePath("initrd.img") iso := d.ResolveStorePath(isoFilename) - img := fmt.Sprintf("/dev/rdisk%d", d.DiskNumber) + img := fmt.Sprintf("/dev/rdisk%d", d.RootVolumeDiskImage.diskNumber) bootcmd := d.BootCmd cpus := d.CPU @@ -812,7 +849,7 @@ func (d *Driver) xhyveArgs() []string { cpus = int(runtime.NumCPU()) } - return []string{ + args := []string{ "xhyve", "-A", "-U", fmt.Sprintf("%s", uuid), @@ -825,6 +862,14 @@ func (d *Driver) xhyveArgs() []string { "-s", fmt.Sprintf("3,ahci-cd,%s", iso), "-s", fmt.Sprintf("4:0,ahci-hd,%s", img), "-f", fmt.Sprintf("kexec,%s,%s,%s", vmlinuz, initrd, bootcmd)} + + pcislot := 5 + for _, v := range d.DiskImages { + img := fmt.Sprintf("/dev/rdisk%d", v.diskNumber) + args = append(args, "-s", fmt.Sprintf("%d:0,ahci-hd,%s", pcislot, img)) + } + + return args } func (d *Driver) getMACAdress() (string, error) { diff --git a/xhyve/xhyve_test.go b/xhyve/xhyve_test.go index c02e91d..3e1a738 100644 --- a/xhyve/xhyve_test.go +++ b/xhyve/xhyve_test.go @@ -67,6 +67,8 @@ func TestGeneratingAndDetachingDiskImage(t *testing.T) { assert.NoError(t, err) } + driver.RootVolumeDiskImage.Path = "root-volume.sparsebundle" + if err := driver.generateDiskImage(500); err != nil { assert.NoError(t, err) } @@ -75,14 +77,14 @@ func TestGeneratingAndDetachingDiskImage(t *testing.T) { assert.NoError(t, err) } - assert.NotEqual(t, -1, driver.DiskNumber) + assert.NotEqual(t, -1, driver.RootVolumeDiskImage.diskNumber) - if err := driver.detachDiskImage(); err != nil { + if err := driver.detachDiskImage(driver.RootVolumeDiskImage); err != nil { assert.NoError(t, err) } - assert.Equal(t, -1, driver.DiskNumber) + assert.Equal(t, -1, driver.RootVolumeDiskImage.diskNumber) - if err := driver.removeDiskImage(); err != nil { + if err := driver.removeDiskImage(driver.RootVolumeDiskImage); err != nil { assert.NoError(t, err) }