From 576951e03a5438b1a87430d3ad9eb22512acc11d Mon Sep 17 00:00:00 2001 From: Evan Hazlett Date: Wed, 8 Apr 2015 09:49:52 -0400 Subject: [PATCH] wip: b2d import Signed-off-by: Evan Hazlett --- drivers/virtualbox/disk.go | 46 +++++++++++++++++ drivers/virtualbox/disk_test.go | 36 ++++++++++++++ drivers/virtualbox/vbm.go | 1 + drivers/virtualbox/virtualbox.go | 84 ++++++++++++++++++++++++-------- 4 files changed, 146 insertions(+), 21 deletions(-) create mode 100644 drivers/virtualbox/disk.go create mode 100644 drivers/virtualbox/disk_test.go diff --git a/drivers/virtualbox/disk.go b/drivers/virtualbox/disk.go new file mode 100644 index 0000000000..20d35b95b9 --- /dev/null +++ b/drivers/virtualbox/disk.go @@ -0,0 +1,46 @@ +package virtualbox + +import ( + "bufio" + "io" + "strings" +) + +type VirtualDisk struct { + UUID string + Path string +} + +func parseDiskInfo(r io.Reader) (*VirtualDisk, error) { + s := bufio.NewScanner(r) + disk := &VirtualDisk{} + for s.Scan() { + line := s.Text() + if line == "" { + continue + } + res := reEqualLine.FindStringSubmatch(line) + if res == nil { + continue + } + switch key, val := res[1], res[2]; key { + case "SATA-1-0": + disk.Path = val + case "SATA-ImageUUID-1-0": + disk.UUID = val + } + } + if err := s.Err(); err != nil { + return nil, err + } + return disk, nil +} + +func getVMDiskInfo(name string) (*VirtualDisk, error) { + out, err := vbmOut("showvminfo", name, "--machinereadable") + if err != nil { + return nil, err + } + r := strings.NewReader(out) + return parseDiskInfo(r) +} diff --git a/drivers/virtualbox/disk_test.go b/drivers/virtualbox/disk_test.go new file mode 100644 index 0000000000..b6b80cfbe7 --- /dev/null +++ b/drivers/virtualbox/disk_test.go @@ -0,0 +1,36 @@ +package virtualbox + +import ( + "strings" + "testing" +) + +var ( + testDiskInfoText = ` +storagecontrollerbootable0="on" +"SATA-0-0"="/home/ehazlett/.boot2docker/boot2docker.iso" +"SATA-IsEjected"="off" +"SATA-1-0"="/home/ehazlett/vm/test/disk.vmdk" +"SATA-ImageUUID-1-0"="12345-abcdefg" +"SATA-2-0"="none" +nic1="nat" + ` +) + +func TestVMDiskInfo(t *testing.T) { + r := strings.NewReader(testDiskInfoText) + disk, err := parseDiskInfo(r) + if err != nil { + t.Fatal(err) + } + + diskPath := "/home/ehazlett/vm/test/disk.vmdk" + diskUUID := "12345-abcdefg" + if disk.Path != diskPath { + t.Fatalf("expected disk path %s", diskPath) + } + + if disk.UUID != diskUUID { + t.Fatalf("expected disk uuid %s", diskUUID) + } +} diff --git a/drivers/virtualbox/vbm.go b/drivers/virtualbox/vbm.go index 9f0170ead3..d2223c9004 100644 --- a/drivers/virtualbox/vbm.go +++ b/drivers/virtualbox/vbm.go @@ -18,6 +18,7 @@ var ( reVMNameUUID = regexp.MustCompile(`"(.+)" {([0-9a-f-]+)}`) reVMInfoLine = regexp.MustCompile(`(?:"(.+)"|(.+))=(?:"(.*)"|(.*))`) reColonLine = regexp.MustCompile(`(.+):\s+(.*)`) + reEqualLine = regexp.MustCompile(`"(.+)"="(.*)"`) reMachineNotFound = regexp.MustCompile(`Could not find a registered machine named '(.+)'`) ) diff --git a/drivers/virtualbox/virtualbox.go b/drivers/virtualbox/virtualbox.go index 453afb5d86..83402c25ae 100644 --- a/drivers/virtualbox/virtualbox.go +++ b/drivers/virtualbox/virtualbox.go @@ -30,19 +30,20 @@ const ( ) type Driver struct { - CPU int - MachineName string - SSHUser string - SSHPort int - Memory int - DiskSize int - Boot2DockerURL string - CaCertPath string - PrivateKeyPath string - SwarmMaster bool - SwarmHost string - SwarmDiscovery string - storePath string + CPU int + MachineName string + SSHUser string + SSHPort int + Memory int + DiskSize int + Boot2DockerURL string + CaCertPath string + PrivateKeyPath string + SwarmMaster bool + SwarmHost string + SwarmDiscovery string + storePath string + Boot2DockerImportVM string } func init() { @@ -80,6 +81,11 @@ func GetCreateFlags() []cli.Flag { Usage: "The URL of the boot2docker image. Defaults to the latest available version", Value: "", }, + cli.StringFlag{ + Name: "virtualbox-import-boot2docker-vm", + Usage: "The name of a Boot2Docker VM to import", + Value: "", + }, } } @@ -147,6 +153,7 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.SwarmHost = flags.String("swarm-host") d.SwarmDiscovery = flags.String("swarm-discovery") d.SSHUser = "docker" + d.Boot2DockerImportVM = flags.String("virtualbox-import-boot2docker-vm") return nil } @@ -170,21 +177,36 @@ func (d *Driver) Create() error { return err } - log.Infof("Creating SSH key...") - b2dutils := utils.NewB2dUtils("", "") if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil { return err } - if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { - return err - } - log.Infof("Creating VirtualBox VM...") - if err := d.generateDiskImage(d.DiskSize); err != nil { - return err + // import b2d VM if requested + if d.Boot2DockerImportVM != "" { + log.Debugf("Importing disk image...") + if err := d.importB2DVM(d.Boot2DockerImportVM); err != nil { + return err + } + + log.Debugf("Importing SSH key...") + keyPath := filepath.Join(utils.GetHomeDir(), ".ssh", "id_rsa") + if err := utils.CopyFile(keyPath, d.GetSSHKeyPath()); err != nil { + return err + } + } else { + log.Debugf("Creating disk image...") + if err := d.generateDiskImage(d.DiskSize); err != nil { + return err + } + + log.Infof("Creating SSH key...") + + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { + return err + } } if err := vbm("createvm", @@ -594,6 +616,26 @@ func zeroFill(w io.Writer, n int64) error { return nil } +func (d Driver) importB2DVM(name string) error { + // make sure vm is stopped + _ = vbm("controlvm", name, "poweroff") + + diskInfo, err := getVMDiskInfo(name) + if err != nil { + return err + } + + if _, err := os.Stat(diskInfo.Path); err != nil { + return err + } + + if err := vbm("clonehd", diskInfo.Path, d.diskPath()); err != nil { + return err + } + + return nil +} + func getAvailableTCPPort() (int, error) { port := 0 for i := 0; i <= 10; i++ {