Merge pull request #674 from frapposelli/vsphere-driver-fixes

vSphere driver fixes
This commit is contained in:
Evan Hazlett
2015-03-02 13:06:12 -05:00
2 changed files with 150 additions and 48 deletions

View File

@@ -114,7 +114,8 @@ func (conn VcConn) VmCreate(isoPath string) error {
args = append(args, fmt.Sprintf("--m=%s", memory))
cpu := strconv.Itoa(conn.driver.CPU)
args = append(args, fmt.Sprintf("--c=%s", cpu))
args = append(args, "--disk.controller=scsi")
args = append(args, "--disk.controller=pvscsi")
args = append(args, "--net.adapter=vmxnet3")
args = append(args, "--on=false")
if conn.driver.Pool != "" {
args = append(args, fmt.Sprintf("--pool=%s", conn.driver.Pool))
@@ -168,6 +169,24 @@ func (conn VcConn) VmPowerOff() error {
}
}
func (conn VcConn) VmShutdown() error {
log.Infof("Powering off virtual machine %s of vCenter %s... ",
conn.driver.MachineName, conn.driver.IP)
args := []string{"vm.power"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, "-s")
args = append(args, conn.driver.MachineName)
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewVmError("power on", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) VmDestroy() error {
log.Infof("Deleting virtual machine %s of vCenter %s... ",
conn.driver.MachineName, conn.driver.IP)
@@ -268,6 +287,23 @@ func (conn VcConn) GuestUpload(guestUser, guestPass, localPath, remotePath strin
}
}
func (conn VcConn) GuestStart(guestUser, guestPass, remoteBin, remoteArguments string) error {
args := []string{"guest.start"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, fmt.Sprintf("--l=%s:%s", guestUser, guestPass))
args = append(args, fmt.Sprintf("--vm=%s", conn.driver.MachineName))
args = append(args, remoteBin)
args = append(args, remoteArguments)
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewGuestError("start", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) GuestDownload(guestUser, guestPass, remotePath, localPath string) error {
args := []string{"guest.download"}
args = conn.AppendConnectionString(args)

View File

@@ -5,6 +5,7 @@
package vmwarevsphere
import (
"archive/tar"
"fmt"
"io"
"io/ioutil"
@@ -14,6 +15,7 @@ import (
"path"
"path/filepath"
"strings"
"time"
log "github.com/Sirupsen/logrus"
@@ -23,12 +25,12 @@ import (
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
cssh "golang.org/x/crypto/ssh"
// cssh "golang.org/x/crypto/ssh"
)
const (
DATASTORE_DIR = "boot2docker-iso"
isoFilename = "boot2docker-vmw.iso"
isoFilename = "boot2docker-1.5.0-GH747.iso"
B2D_ISO_NAME = isoFilename
DEFAULT_CPU_NUMBER = 2
dockerConfigDir = "/var/lib/boot2docker"
@@ -231,7 +233,7 @@ func (d *Driver) PreCreateCheck() error {
// the current implementation does the following:
// 1. check whether the docker directory contains the boot2docker ISO
// 2. generate an SSH keypair
// 2. generate an SSH keypair and bundle it in a tar.
// 3. create a virtual machine with the boot2docker ISO mounted;
// 4. reconfigure the virtual machine network and disk size;
func (d *Driver) Create() error {
@@ -275,7 +277,8 @@ func (d *Driver) Create() error {
//}
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)
@@ -339,6 +342,21 @@ func (d *Driver) Create() error {
return err
}
// Generate a tar keys bundle
if err := d.generateKeyBundle(); err != nil {
return err
}
// Copy SSH keys bundle
if err := vcConn.GuestUpload(B2D_USER, B2D_PASS, path.Join(d.storePath, "userdata.tar"), "/home/docker/userdata.tar"); err != nil {
return err
}
// Expand tar file.
if err := vcConn.GuestStart(B2D_USER, B2D_PASS, "/usr/bin/sudo", "/bin/mv /home/docker/userdata.tar /var/lib/boot2docker/userdata.tar && /usr/bin/sudo tar xf /var/lib/boot2docker/userdata.tar -C /home/docker/ > /var/log/userdata.log 2>&1 && /usr/bin/sudo chown -R docker:staff /home/docker"); err != nil {
return err
}
log.Debugf("Setting hostname: %s", d.MachineName)
cmd, err := d.GetSSHCommand(fmt.Sprintf(
"echo \"127.0.0.1 %s\" | sudo tee -a /etc/hosts && sudo hostname %s && echo \"%s\" | sudo tee /etc/hostname",
@@ -380,41 +398,6 @@ func (d *Driver) Start() error {
return err
}
log.Infof("Configuring virtual machine %s... ", d.MachineName)
key, err := ioutil.ReadFile(d.publicSSHKeyPath())
if 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),
},
}
ip, err := d.GetIP()
if err != nil {
return err
}
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()
return nil
}
return errors.NewInvalidStateError(d.MachineName)
@@ -422,11 +405,11 @@ func (d *Driver) Start() error {
func (d *Driver) Stop() error {
vcConn := NewVcConn(d)
err := vcConn.VmPowerOff()
if err != nil {
if err := vcConn.VmShutdown(); err != nil {
return err
}
return err
return nil
}
func (d *Driver) Remove() error {
@@ -435,13 +418,12 @@ func (d *Driver) Remove() error {
return err
}
if machineState == state.Running {
if err = d.Stop(); err != nil {
if err = d.Kill(); err != nil {
return fmt.Errorf("can't stop VM: %s", err)
}
}
vcConn := NewVcConn(d)
err = vcConn.VmDestroy()
if err != nil {
if err = vcConn.VmDestroy(); err != nil {
return err
}
return nil
@@ -451,11 +433,40 @@ func (d *Driver) Restart() error {
if err := d.Stop(); err != nil {
return err
}
// Check for 120 seconds for the machine to stop
for i := 1; i <= 60; i++ {
machineState, err := d.GetState()
if err != nil {
return err
}
if machineState == state.Running {
log.Debugf("Not there yet %d/%d", i, 60)
time.Sleep(2 * time.Second)
continue
}
if machineState == state.Stopped {
break
}
}
machineState, err := d.GetState()
// If the VM is still running after 120 seconds just kill it.
if machineState == state.Running {
if err = d.Kill(); err != nil {
return fmt.Errorf("can't stop VM: %s", err)
}
}
return d.Start()
}
func (d *Driver) Kill() error {
return d.Stop()
vcConn := NewVcConn(d)
if err := vcConn.VmPowerOff(); err != nil {
return err
}
return nil
}
func (d *Driver) StartDocker() error {
@@ -503,7 +514,7 @@ func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) {
}
func (d *Driver) sshKeyPath() string {
return filepath.Join(d.StorePath, "id_docker_host_vsphere")
return path.Join(d.storePath, "id_rsa")
}
func (d *Driver) publicSSHKeyPath() string {
@@ -558,3 +569,58 @@ func downloadISO(dir, file, url string) error {
}
return nil
}
// 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
}