Merge pull request #1479 from mschygulla/enhanced-vmwarefusion-driver

[Enhancement] VMware Fusion driver
This commit is contained in:
Nathan LeClaire 2015-09-11 14:26:30 -07:00
commit b52fa33056
2 changed files with 132 additions and 4 deletions

View File

@ -6,8 +6,10 @@ package vmwarefusion
import (
"archive/tar"
"bytes"
"fmt"
"io/ioutil"
"net"
"os"
"regexp"
"runtime"
@ -21,12 +23,14 @@ import (
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
"github.com/docker/machine/utils"
cryptossh "golang.org/x/crypto/ssh"
)
const (
B2DUser = "docker"
B2DPass = "tcuser"
isoFilename = "boot2docker.iso"
B2DUser = "docker"
B2DPass = "tcuser"
isoFilename = "boot2docker.iso"
isoConfigDrive = "configdrive.iso"
)
// Driver for VMware Fusion
@ -38,6 +42,10 @@ type Driver struct {
ISO string
Boot2DockerURL string
CPUS int
SSHPassword string
ConfigDriveISO string
ConfigDriveURL string
}
func init() {
@ -56,6 +64,11 @@ func GetCreateFlags() []cli.Flag {
Name: "vmwarefusion-boot2docker-url",
Usage: "Fusion URL for boot2docker image",
},
cli.StringFlag{
EnvVar: "FUSION_CONFIGDRIVE_URL",
Name: "vmwarefusion-configdrive-url",
Usage: "Fusion URL for cloud-init configdrive",
},
cli.IntFlag{
EnvVar: "FUSION_CPU_COUNT",
Name: "vmwarefusion-cpu-count",
@ -74,6 +87,18 @@ func GetCreateFlags() []cli.Flag {
Usage: "Fusion size of disk for host VM (in MB)",
Value: 20000,
},
cli.StringFlag{
EnvVar: "FUSION_SSH_USER",
Name: "vmwarefusion-ssh-user",
Usage: "SSH user",
Value: B2DUser,
},
cli.StringFlag{
EnvVar: "FUSION_SSH_PASSWORD",
Name: "vmwarefusion-ssh-password",
Usage: "SSH password",
Value: B2DPass,
},
}
}
@ -103,11 +128,14 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
d.CPU = flags.Int("vmwarefusion-cpu-count")
d.DiskSize = flags.Int("vmwarefusion-disk-size")
d.Boot2DockerURL = flags.String("vmwarefusion-boot2docker-url")
d.ConfigDriveURL = flags.String("vmwarefusion-configdrive-url")
d.ConfigDriveISO = d.ResolveStorePath(isoConfigDrive)
d.ISO = d.ResolveStorePath(isoFilename)
d.SwarmMaster = flags.Bool("swarm-master")
d.SwarmHost = flags.String("swarm-host")
d.SwarmDiscovery = flags.String("swarm-discovery")
d.SSHUser = "docker"
d.SSHUser = flags.String("vmwarefusion-ssh-user")
d.SSHPassword = flags.String("vmwarefusion-ssh-password")
d.SSHPort = 22
// We support a maximum of 16 cpu to be consistent with Virtual Hardware 10
@ -169,6 +197,14 @@ func (d *Driver) Create() error {
return err
}
// download cloud-init config drive
if d.ConfigDriveURL != "" {
log.Infof("Downloading %s from %s", isoConfigDrive, d.ConfigDriveURL)
if err := b2dutils.DownloadISO(d.ResolveStorePath("."), isoConfigDrive, d.ConfigDriveURL); err != nil {
return err
}
}
log.Infof("Creating SSH key...")
if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
return err
@ -219,6 +255,13 @@ func (d *Driver) Create() error {
if ip != "" {
log.Debugf("Got an ip: %s", ip)
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, 22), time.Duration(2*time.Second))
if err != nil {
log.Debugf("SSH Daemon not responding yet: %s", err)
time.Sleep(2 * time.Second)
continue
}
conn.Close()
break
}
}
@ -230,6 +273,44 @@ func (d *Driver) Create() error {
// we got an IP, let's copy ssh keys over
d.IPAddress = ip
// Do not execute the rest of boot2docker specific configuration
// The uplaod of the public ssh key uses a ssh connection,
// this works without installed vmware client tools
if d.ConfigDriveURL != "" {
var keyfh *os.File
var keycontent []byte
log.Infof("Copy public SSH key to %s [%s]", d.MachineName, d.IPAddress)
// create .ssh folder in users home
if err := executeSSHCommand(fmt.Sprintf("mkdir -p /home/%s/.ssh", d.SSHUser), d); err != nil {
return err
}
// read generated public ssh key
if keyfh, err = os.Open(d.publicSSHKeyPath()); err != nil {
return err
}
defer keyfh.Close()
if keycontent, err = ioutil.ReadAll(keyfh); err != nil {
return err
}
// add public ssh key to authorized_keys
if err := executeSSHCommand(fmt.Sprintf("echo '%s' > /home/%s/.ssh/authorized_keys", string(keycontent), d.SSHUser), d); err != nil {
return err
}
// make it secure
if err := executeSSHCommand(fmt.Sprintf("chmod 600 /home/%s/.ssh/authorized_keys", d.SSHUser), d); err != nil {
return err
}
log.Debugf("Leaving create sequence early, configdrive found")
return nil
}
// Generate a tar keys bundle
if err := d.generateKeyBundle(); err != nil {
return err
@ -271,6 +352,12 @@ func (d *Driver) Start() error {
log.Infof("Starting %s...", d.MachineName)
vmrun("start", d.vmxPath(), "nogui")
// Do not execute the rest of boot2docker specific configuration, exit here
if d.ConfigDriveURL != "" {
log.Debugf("Leaving start sequence early, configdrive found")
return nil
}
log.Debugf("Mounting Shared Folders...")
var shareName, shareDir string // TODO configurable at some point
switch runtime.GOOS {
@ -475,3 +562,39 @@ func (d *Driver) generateKeyBundle() error {
return nil
}
// execute command over SSH with user / password authentication
func executeSSHCommand(command string, d *Driver) error {
log.Debugf("Execute executeSSHCommand: %s", command)
config := &cryptossh.ClientConfig{
User: d.SSHUser,
Auth: []cryptossh.AuthMethod{
cryptossh.Password(d.SSHPassword),
},
}
client, err := cryptossh.Dial("tcp", fmt.Sprintf("%s:%d", d.IPAddress, d.SSHPort), config)
if err != nil {
log.Debugf("Failed to dial:", err)
return err
}
session, err := client.NewSession()
if err != nil {
log.Debugf("Failed to create session: " + err.Error())
return err
}
defer session.Close()
var b bytes.Buffer
session.Stdout = &b
if err := session.Run(command); err != nil {
log.Debugf("Failed to run: " + err.Error())
return err
}
log.Debugf("Stdout from executeSSHCommand: %s", b.String())
return nil
}

View File

@ -45,6 +45,11 @@ sata0.present = "TRUE"
sata0:1.present = "TRUE"
sata0:1.fileName = "{{.ISO}}"
sata0:1.deviceType = "cdrom-image"
{{ if .ConfigDriveURL }}
sata0:2.present = "TRUE"
sata0:2.fileName = "{{.ConfigDriveISO}}"
sata0:2.deviceType = "cdrom-image"
{{ end }}
vmci0.present = "TRUE"
mem.hotadd = "TRUE"
memsize = "{{.Memory}}"