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 <fabio@vmware.com>
This commit is contained in:
Fabio Rapposelli
2015-02-27 14:18:24 +01:00
parent 3442f8e063
commit 193e2b1613

View File

@@ -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
}