From 3442f8e06347285519b15521cbbd25c563eb0c46 Mon Sep 17 00:00:00 2001 From: Fabio Rapposelli Date: Fri, 27 Feb 2015 14:13:41 +0100 Subject: [PATCH 1/3] Moved VMX options around, major changes: - Moved to a paravirtualized driver for disk (pvscsi) - Moved to an enhanced paravirtualized nic (vmxnet3) - Moved CDROM to SATA - Reverted default power operations to "soft" Signed-off-by: Fabio Rapposelli --- drivers/vmwarefusion/vmx_darwin.go | 52 ++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/vmwarefusion/vmx_darwin.go b/drivers/vmwarefusion/vmx_darwin.go index 3f46f633e4..1cfc2a3e81 100644 --- a/drivers/vmwarefusion/vmx_darwin.go +++ b/drivers/vmwarefusion/vmx_darwin.go @@ -8,26 +8,52 @@ const vmx = ` .encoding = "UTF-8" config.version = "8" displayName = "{{.MachineName}}" -ethernet0.addressType = "generated" -ethernet0.connectionType = "nat" -ethernet0.linkStatePropagation.enable = "TRUE" ethernet0.present = "TRUE" -ethernet0.virtualDev = "e1000" +ethernet0.connectionType = "nat" +ethernet0.virtualDev = "vmxnet3" ethernet0.wakeOnPcktRcv = "FALSE" +ethernet0.addressType = "generated" +ethernet0.linkStatePropagation.enable = "TRUE" +pciBridge0.present = "TRUE" +pciBridge4.present = "TRUE" +pciBridge4.virtualDev = "pcieRootPort" +pciBridge4.functions = "8" +pciBridge5.present = "TRUE" +pciBridge5.virtualDev = "pcieRootPort" +pciBridge5.functions = "8" +pciBridge6.present = "TRUE" +pciBridge6.virtualDev = "pcieRootPort" +pciBridge6.functions = "8" +pciBridge7.present = "TRUE" +pciBridge7.virtualDev = "pcieRootPort" +pciBridge7.functions = "8" +pciBridge0.pciSlotNumber = "17" +pciBridge4.pciSlotNumber = "21" +pciBridge5.pciSlotNumber = "22" +pciBridge6.pciSlotNumber = "23" +pciBridge7.pciSlotNumber = "24" +scsi0.pciSlotNumber = "160" +usb.pciSlotNumber = "32" +ethernet0.pciSlotNumber = "192" +sound.pciSlotNumber = "33" +vmci0.pciSlotNumber = "35" +sata0.pciSlotNumber = "36" floppy0.present = "FALSE" -guestOS = "other26xlinux-64" +guestOS = "other3xlinux-64" hpet0.present = "TRUE" -ide1:0.deviceType = "cdrom-image" -ide1:0.fileName = "{{.ISO}}" -ide1:0.present = "TRUE" +sata0.present = "TRUE" +sata0:1.present = "TRUE" +sata0:1.fileName = "{{.ISO}}" +sata0:1.deviceType = "cdrom-image" +vmci0.present = "TRUE" mem.hotadd = "TRUE" memsize = "{{.Memory}}" -powerType.powerOff = "hard" -powerType.powerOn = "hard" -powerType.reset = "hard" -powerType.suspend = "hard" +powerType.powerOff = "soft" +powerType.powerOn = "soft" +powerType.reset = "soft" +powerType.suspend = "soft" scsi0.present = "TRUE" -scsi0.virtualDev = "lsilogic" +scsi0.virtualDev = "pvscsi" scsi0:0.fileName = "{{.MachineName}}.vmdk" scsi0:0.present = "TRUE" virtualHW.productCompatibility = "hosted" From 193e2b1613ac02db4f082692a4557532fad3eaed Mon Sep 17 00:00:00 2001 From: Fabio Rapposelli Date: Fri, 27 Feb 2015 14:18:24 +0100 Subject: [PATCH 2/3] Major rework, changes include: - Use new iso from boot2docker/boot2docker#747 - Make ssh keys persistent across reboots - Create a tar bundle of ssh keys just like Virtualbox - Seed ssh keys using VMware Tools - Added informative messages on stop/start/restart/remove - Stop command is now gracefully shutting down the VM - Fixed StopDocker() script - Added a "not supported" message to upgrade operation Fixes #507 #542 #430 #532 Signed-off-by: Fabio Rapposelli --- drivers/vmwarefusion/fusion_darwin.go | 111 +++++++++++++++++++------- 1 file changed, 80 insertions(+), 31 deletions(-) diff --git a/drivers/vmwarefusion/fusion_darwin.go b/drivers/vmwarefusion/fusion_darwin.go index 38f5e9824a..ad8f133098 100644 --- a/drivers/vmwarefusion/fusion_darwin.go +++ b/drivers/vmwarefusion/fusion_darwin.go @@ -5,6 +5,7 @@ package vmwarefusion import ( + "archive/tar" "fmt" "io" "io/ioutil" @@ -24,14 +25,13 @@ import ( "github.com/docker/machine/ssh" "github.com/docker/machine/state" "github.com/docker/machine/utils" - cssh "golang.org/x/crypto/ssh" ) const ( B2D_USER = "docker" B2D_PASS = "tcuser" dockerConfigDir = "/var/lib/boot2docker" - isoFilename = "boot2docker-vmw.iso" + isoFilename = "boot2docker-1.5.0-GH747.iso" ) // Driver for VMware Fusion @@ -168,7 +168,7 @@ func (d *Driver) Create() error { } else { // TODO: until vmw tools are merged into b2d master - // we will use the iso from the vmware team + // we will use the iso from the vmware team. //// todo: check latest release URL, download if it's new //// until then always use "latest" //isoURL, err = b2dutils.GetLatestBoot2DockerReleaseURL() @@ -176,7 +176,8 @@ func (d *Driver) Create() error { // log.Warnf("Unable to check for the latest release: %s", err) //} - isoURL := "https://github.com/cloudnativeapps/boot2docker/releases/download/v1.5.0-vmw/boot2docker-1.5.0-vmw.iso" + // see https://github.com/boot2docker/boot2docker/pull/747 + isoURL := "https://github.com/cloudnativeapps/boot2docker/releases/download/1.5.0-GH747/boot2docker-1.5.0-GH747.iso" if _, err := os.Stat(commonIsoPath); os.IsNotExist(err) { log.Infof("Downloading boot2docker.iso to %s...", commonIsoPath) @@ -255,34 +256,22 @@ func (d *Driver) Create() error { return fmt.Errorf("Machine didn't return an IP after 120 seconds, aborting") } + // we got an IP, let's copy ssh keys over d.IPAddress = ip - key, err := ioutil.ReadFile(d.publicSSHKeyPath()) - if err != nil { + // Generate a tar keys bundle + if err := d.generateKeyBundle(); err != nil { return err } - // so, vmrun above will not work without vmtools in b2d. since getting stuff into TCL - // is much more painful, we simply use the b2d password to get the initial public key - // onto the machine. from then on we use the pub key. meh. - sshConfig := &cssh.ClientConfig{ - User: B2D_USER, - Auth: []cssh.AuthMethod{ - cssh.Password(B2D_PASS), - }, - } - sshClient, err := cssh.Dial("tcp", fmt.Sprintf("%s:22", ip), sshConfig) - if err != nil { - return err - } - session, err := sshClient.NewSession() - if err != nil { - return err - } - if err := session.Run(fmt.Sprintf("mkdir /home/docker/.ssh && echo \"%s\" > /home/docker/.ssh/authorized_keys", string(key))); err != nil { - return err - } - session.Close() + // Test if /var/lib/boot2docker exists + vmrun("-gu", B2D_USER, "-gp", B2D_PASS, "directoryExistsInGuest", d.vmxPath(), "/var/lib/boot2docker") + + // Copy SSH keys bundle + vmrun("-gu", B2D_USER, "-gp", B2D_PASS, "CopyFileFromHostToGuest", d.vmxPath(), path.Join(d.storePath, "userdata.tar"), "/home/docker/userdata.tar") + + // Expand tar file. + vmrun("-gu", B2D_USER, "-gp", B2D_PASS, "runScriptInGuest", d.vmxPath(), "/bin/sh", "sudo /bin/mv /home/docker/userdata.tar /var/lib/boot2docker/userdata.tar && sudo tar xf /var/lib/boot2docker/userdata.tar -C /home/docker/ > /var/log/userdata.log 2>&1 && sudo chown -R docker:staff /home/docker") log.Debugf("Setting hostname: %s", d.MachineName) cmd, err := d.GetSSHCommand(fmt.Sprintf( @@ -302,11 +291,13 @@ func (d *Driver) Create() error { } func (d *Driver) Start() error { + log.Infof("Starting %s...", d.MachineName) vmrun("start", d.vmxPath(), "nogui") return nil } func (d *Driver) Stop() error { + log.Infof("Gracefully shutting down %s...", d.MachineName) vmrun("stop", d.vmxPath(), "nogui") return nil } @@ -319,18 +310,20 @@ func (d *Driver) Remove() error { return fmt.Errorf("Error stopping VM before deletion") } } - + log.Infof("Deleting %s...", d.MachineName) vmrun("deleteVM", d.vmxPath(), "nogui") return nil } func (d *Driver) Restart() error { + log.Infof("Gracefully restarting %s...", d.MachineName) vmrun("reset", d.vmxPath(), "nogui") return nil } func (d *Driver) Kill() error { - vmrun("stop", d.vmxPath(), "nogui") + log.Infof("Forcibly halting %s...", d.MachineName) + vmrun("stop", d.vmxPath(), "hard nogui") return nil } @@ -351,7 +344,8 @@ func (d *Driver) StartDocker() error { func (d *Driver) StopDocker() error { log.Debug("Stopping Docker...") - cmd, err := d.GetSSHCommand("if [ -e /var/run/docker.pid ]; then sudo /etc/init.d/docker stop ; fi") + // Check if pidfile exists, then if process exists, depending on that stop docker or remove pidfile + cmd, err := d.GetSSHCommand("if [ -e /var/run/docker.pid ]; then if [ -f /proc/$(cat /var/run/docker.pid)/status ]; then sudo /etc/init.d/docker stop; else rm -f /var/run/docker.pid; fi fi") if err != nil { return err } @@ -367,7 +361,7 @@ func (d *Driver) GetDockerConfigDir() string { } func (d *Driver) Upgrade() error { - return nil + return fmt.Errorf("VMware Fusion does not currently support the upgrade operation.") } func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { @@ -502,3 +496,58 @@ func (d *Driver) sshKeyPath() string { func (d *Driver) publicSSHKeyPath() string { return d.sshKeyPath() + ".pub" } + +// Make a boot2docker userdata.tar key bundle +func (d *Driver) generateKeyBundle() error { + log.Debugf("Creating Tar key bundle...") + + magicString := "boot2docker, this is vmware speaking" + + tf, err := os.Create(path.Join(d.storePath, "userdata.tar")) + if err != nil { + return err + } + defer tf.Close() + var fileWriter io.WriteCloser = tf + + tw := tar.NewWriter(fileWriter) + defer tw.Close() + + // magicString first so we can figure out who originally wrote the tar. + file := &tar.Header{Name: magicString, Size: int64(len(magicString))} + if err := tw.WriteHeader(file); err != nil { + return err + } + if _, err := tw.Write([]byte(magicString)); err != nil { + return err + } + // .ssh/key.pub => authorized_keys + file = &tar.Header{Name: ".ssh", Typeflag: tar.TypeDir, Mode: 0700} + if err := tw.WriteHeader(file); err != nil { + return err + } + pubKey, err := ioutil.ReadFile(d.publicSSHKeyPath()) + if err != nil { + return err + } + file = &tar.Header{Name: ".ssh/authorized_keys", Size: int64(len(pubKey)), Mode: 0644} + if err := tw.WriteHeader(file); err != nil { + return err + } + if _, err := tw.Write([]byte(pubKey)); err != nil { + return err + } + file = &tar.Header{Name: ".ssh/authorized_keys2", Size: int64(len(pubKey)), Mode: 0644} + if err := tw.WriteHeader(file); err != nil { + return err + } + if _, err := tw.Write([]byte(pubKey)); err != nil { + return err + } + if err := tw.Close(); err != nil { + return err + } + + return nil + +} From 9410b5b20839e9e417339218ce0aded668f52145 Mon Sep 17 00:00:00 2001 From: Fabio Rapposelli Date: Fri, 27 Feb 2015 17:37:54 +0100 Subject: [PATCH 3/3] Add automatic assignments of vCPUs based on host CPUs. Fixes #535 Signed-off-by: Fabio Rapposelli --- drivers/vmwarefusion/fusion_darwin.go | 9 +++++++++ drivers/vmwarefusion/vmx_darwin.go | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/vmwarefusion/fusion_darwin.go b/drivers/vmwarefusion/fusion_darwin.go index ad8f133098..53f421bc53 100644 --- a/drivers/vmwarefusion/fusion_darwin.go +++ b/drivers/vmwarefusion/fusion_darwin.go @@ -15,6 +15,7 @@ import ( "path" "path/filepath" "regexp" + "runtime" "strings" "text/template" "time" @@ -40,6 +41,7 @@ type Driver struct { IPAddress string Memory int DiskSize int + CPUs int ISO string Boot2DockerURL string CaCertPath string @@ -105,6 +107,13 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.SwarmHost = flags.String("swarm-host") d.SwarmDiscovery = flags.String("swarm-discovery") + // We support a maximum of 16 cpu to be consistent with Virtual Hardware 10 + // specs. + d.CPUs = int(runtime.NumCPU()) + if d.CPUs > 16 { + d.CPUs = 16 + } + return nil } diff --git a/drivers/vmwarefusion/vmx_darwin.go b/drivers/vmwarefusion/vmx_darwin.go index 1cfc2a3e81..c5e87ad539 100644 --- a/drivers/vmwarefusion/vmx_darwin.go +++ b/drivers/vmwarefusion/vmx_darwin.go @@ -60,4 +60,5 @@ virtualHW.productCompatibility = "hosted" virtualHW.version = "10" msg.autoanswer = "TRUE" uuid.action = "create" +numvcpus = "{{.CPUs}}" `