mirror of https://github.com/docker/docs.git
142 lines
2.9 KiB
Go
142 lines
2.9 KiB
Go
package virtualbox
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
|
|
"github.com/docker/machine/libmachine/log"
|
|
"github.com/docker/machine/libmachine/mcnutils"
|
|
)
|
|
|
|
type VirtualDisk struct {
|
|
UUID string
|
|
Path string
|
|
}
|
|
|
|
type DiskCreator interface {
|
|
Create(size int, publicSSHKeyPath, diskPath string) error
|
|
}
|
|
|
|
func NewDiskCreator() DiskCreator {
|
|
return &defaultDiskCreator{}
|
|
}
|
|
|
|
type defaultDiskCreator struct{}
|
|
|
|
// Make a boot2docker VM disk image.
|
|
func (c *defaultDiskCreator) Create(size int, publicSSHKeyPath, diskPath string) error {
|
|
log.Debugf("Creating %d MB hard disk image...", size)
|
|
|
|
tarBuf, err := mcnutils.MakeDiskImage(publicSSHKeyPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Debug("Calling inner createDiskImage")
|
|
|
|
return createDiskImage(diskPath, size, tarBuf)
|
|
}
|
|
|
|
// createDiskImage makes a disk image at dest with the given size in MB. If r is
|
|
// not nil, it will be read as a raw disk image to convert from.
|
|
func createDiskImage(dest string, size int, r io.Reader) error {
|
|
// Convert a raw image from stdin to the dest VMDK image.
|
|
sizeBytes := int64(size) << 20 // usually won't fit in 32-bit int (max 2GB)
|
|
// FIXME: why isn't this just using the vbm*() functions?
|
|
cmd := exec.Command(vboxManageCmd, "convertfromraw", "stdin", dest,
|
|
fmt.Sprintf("%d", sizeBytes), "--format", "VMDK")
|
|
|
|
log.Debug(cmd)
|
|
|
|
if os.Getenv("MACHINE_DEBUG") != "" {
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
}
|
|
|
|
stdin, err := cmd.StdinPipe()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Debug("Starting command")
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Debug("Copying to stdin")
|
|
|
|
n, err := io.Copy(stdin, r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Debug("Filling zeroes")
|
|
|
|
// The total number of bytes written to stdin must match sizeBytes, or
|
|
// VBoxManage.exe on Windows will fail. Fill remaining with zeros.
|
|
if left := sizeBytes - n; left > 0 {
|
|
if err := zeroFill(stdin, left); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
log.Debug("Closing STDIN")
|
|
|
|
// cmd won't exit until the stdin is closed.
|
|
if err := stdin.Close(); err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Debug("Waiting on cmd")
|
|
|
|
return cmd.Wait()
|
|
}
|
|
|
|
// zeroFill writes n zero bytes into w.
|
|
func zeroFill(w io.Writer, n int64) error {
|
|
const blocksize = 32 << 10
|
|
zeros := make([]byte, blocksize)
|
|
var k int
|
|
var err error
|
|
for n > 0 {
|
|
if n > blocksize {
|
|
k, err = w.Write(zeros)
|
|
} else {
|
|
k, err = w.Write(zeros[:n])
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
n -= int64(k)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getVMDiskInfo(name string, vbox VBoxManager) (*VirtualDisk, error) {
|
|
out, err := vbox.vbmOut("showvminfo", name, "--machinereadable")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
disk := &VirtualDisk{}
|
|
|
|
err = parseKeyValues(out, reEqualQuoteLine, func(key, val string) error {
|
|
switch key {
|
|
case "SATA-1-0":
|
|
disk.Path = val
|
|
case "SATA-ImageUUID-1-0":
|
|
disk.UUID = val
|
|
}
|
|
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return disk, nil
|
|
}
|