Added vSphere machine driver

Signed-off-by: Fabio Rapposelli <frapposelli@vmware.com>
This commit is contained in:
Yang Yang 2014-12-04 17:23:57 +01:00 committed by Fabio Rapposelli
parent 92dd8e01d1
commit 1bad10773c
11 changed files with 961 additions and 0 deletions

View File

@ -0,0 +1,22 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package errors
import "fmt"
type IncompleteVsphereConfigError struct {
component string
}
func NewIncompleteVsphereConfigError(component string) error {
err := IncompleteVsphereConfigError{
component: component,
}
return &err
}
func (err *IncompleteVsphereConfigError) Error() string {
return fmt.Sprintf("Incomplete vSphere information: missing %s", err.component)
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package errors
import "fmt"
type DatastoreError struct {
datastore string
operation string
reason string
}
func NewDatastoreError(datastore, operation, reason string) error {
err := DatastoreError{
datastore: datastore,
operation: operation,
reason: reason,
}
return &err
}
func (err *DatastoreError) Error() string {
return fmt.Sprintf("Unable to %s on datastore %s due to %s", err.operation, err.datastore, err.reason)
}

View File

@ -0,0 +1,22 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package errors
import (
original "errors"
"fmt"
)
func New(message string) error {
return original.New(message)
}
func NewWithFmt(message string, args ...interface{}) error {
return original.New(fmt.Sprintf(message, args...))
}
func NewWithError(message string, err error) error {
return NewWithFmt("%s: %s", message, err.Error())
}

View File

@ -0,0 +1,22 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package errors
import "fmt"
type GovcNotFoundError struct {
path string
}
func NewGovcNotFoundError(path string) error {
err := GovcNotFoundError{
path: path,
}
return &err
}
func (err *GovcNotFoundError) Error() string {
return fmt.Sprintf("govc not found: %s", err.path)
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package errors
import "fmt"
type GuestError struct {
vm string
operation string
reason string
}
func NewGuestError(vm, operation, reason string) error {
err := GuestError{
vm: vm,
operation: operation,
reason: reason,
}
return &err
}
func (err *GuestError) Error() string {
return fmt.Sprintf("Unable to %s on vm %s due to %s", err.operation, err.vm, err.reason)
}

View File

@ -0,0 +1,17 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package errors
type InvalidLoginError struct {
}
func NewInvalidLoginError() error {
err := InvalidLoginError{}
return &err
}
func (err *InvalidLoginError) Error() string {
return "cannot complete operation due to incorrect vSphere username or password"
}

View File

@ -0,0 +1,22 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package errors
import "fmt"
type InvalidStateError struct {
vm string
}
func NewInvalidStateError(vm string) error {
err := InvalidStateError{
vm: vm,
}
return &err
}
func (err *InvalidStateError) Error() string {
return fmt.Sprintf("Machine %s state invalid", err.vm)
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package errors
import "fmt"
type VmError struct {
operation string
vm string
reason string
}
func NewVmError(operation, vm, reason string) error {
err := VmError{
vm: vm,
operation: operation,
reason: reason,
}
return &err
}
func (err *VmError) Error() string {
return fmt.Sprintf("Unable to %s docker host %s: %s", err.operation, err.vm, err.reason)
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package vmwarevsphere
import (
"bytes"
"os/exec"
"strings"
log "github.com/Sirupsen/logrus"
)
var (
GovcCmd = "govc"
)
func govc(args ...string) error {
cmd := exec.Command(GovcCmd, args...)
log.Debugf("executing: %v %v", GovcCmd, strings.Join(args, " "))
if err := cmd.Run(); err != nil {
return err
}
return nil
}
func govcOutErr(args ...string) (string, string, error) {
cmd := exec.Command(GovcCmd, args...)
log.Debugf("executing: %v %v", GovcCmd, strings.Join(args, " "))
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
return stdout.String(), stderr.String(), err
}

View File

@ -0,0 +1,287 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package vmwarevsphere
import (
"fmt"
"strconv"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/docker/machine/drivers/vmwarevsphere/errors"
)
type VcConn struct {
driver *Driver
}
func NewVcConn(driver *Driver) VcConn {
return VcConn{driver: driver}
}
func (conn VcConn) DatastoreLs(path string) (string, error) {
args := []string{"datastore.ls"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--ds=%s", conn.driver.Datastore))
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, path)
stdout, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return stdout, nil
}
return "", errors.NewDatastoreError(conn.driver.Datastore, "ls", stderr)
}
func (conn VcConn) DatastoreMkdir(dirName string) error {
_, err := conn.DatastoreLs(dirName)
if err == nil {
return nil
}
log.Infof("Creating directory %s on datastore %s of vCenter %s... ",
dirName, conn.driver.Datastore, conn.driver.IP)
args := []string{"datastore.mkdir"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--ds=%s", conn.driver.Datastore))
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, dirName)
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewDatastoreError(conn.driver.Datastore, "mkdir", stderr)
}
}
func (conn VcConn) DatastoreUpload(localPath string) error {
stdout, err := conn.DatastoreLs(DATASTORE_DIR)
if err == nil && strings.Contains(stdout, B2D_ISO_NAME) {
log.Infof("boot2docker ISO already uploaded, skipping upload... ")
return nil
}
log.Infof("Uploading %s to %s on datastore %s of vCenter %s... ",
localPath, DATASTORE_DIR, conn.driver.Datastore, conn.driver.IP)
dsPath := fmt.Sprintf("%s/%s", DATASTORE_DIR, B2D_ISO_NAME)
args := []string{"datastore.upload"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--ds=%s", conn.driver.Datastore))
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, localPath)
args = append(args, dsPath)
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewDatastoreError(conn.driver.Datacenter, "upload", stderr)
}
}
func (conn VcConn) VmInfo() (string, error) {
args := []string{"vm.info"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, conn.driver.MachineName)
stdout, stderr, err := govcOutErr(args...)
if strings.Contains(stdout, "Name") && stderr == "" && err == nil {
return stdout, nil
} else {
return "", errors.NewVmError("find", conn.driver.MachineName, "VM not found")
}
}
func (conn VcConn) VmCreate(isoPath string) error {
log.Infof("Creating virtual machine %s of vCenter %s... ",
conn.driver.MachineName, conn.driver.IP)
args := []string{"vm.create"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--net=%s", conn.driver.Network))
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, fmt.Sprintf("--ds=%s", conn.driver.Datastore))
args = append(args, fmt.Sprintf("--iso=%s", isoPath))
memory := strconv.Itoa(conn.driver.Memory)
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, "--on=false")
if conn.driver.Pool != "" {
args = append(args, fmt.Sprintf("--pool=%s", conn.driver.Pool))
}
if conn.driver.HostIP != "" {
args = append(args, fmt.Sprintf("--host.ip=%s", conn.driver.HostIP))
}
args = append(args, conn.driver.MachineName)
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewVmError("create", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) VmPowerOn() error {
log.Infof("Powering on 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, "-on")
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) VmPowerOff() 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, "-off")
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)
args := []string{"vm.destroy"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, conn.driver.MachineName)
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewVmError("delete", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) VmDiskCreate() error {
args := []string{"vm.disk.create"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, fmt.Sprintf("--vm=%s", conn.driver.MachineName))
args = append(args, fmt.Sprintf("--ds=%s", conn.driver.Datastore))
args = append(args, fmt.Sprintf("--name=%s", conn.driver.MachineName))
diskSize := strconv.Itoa(conn.driver.DiskSize)
args = append(args, fmt.Sprintf("--size=%sMiB", diskSize))
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewVmError("add network", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) VmAttachNetwork() error {
args := []string{"vm.network.add"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, fmt.Sprintf("--vm=%s", conn.driver.MachineName))
args = append(args, fmt.Sprintf("--net=%s", conn.driver.Network))
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewVmError("add network", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) VmFetchIp() (string, error) {
args := []string{"vm.ip"}
args = conn.AppendConnectionString(args)
args = append(args, fmt.Sprintf("--dc=%s", conn.driver.Datacenter))
args = append(args, conn.driver.MachineName)
stdout, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return stdout, nil
} else {
return "", errors.NewVmError("fetching IP", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) GuestMkdir(guestUser, guestPass, dirName string) error {
args := []string{"guest.mkdir"}
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, "-p")
args = append(args, dirName)
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewGuestError("mkdir", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) GuestUpload(guestUser, guestPass, localPath, remotePath string) error {
args := []string{"guest.upload"}
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, "-f")
args = append(args, localPath)
args = append(args, remotePath)
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewGuestError("upload", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) GuestDownload(guestUser, guestPass, remotePath, localPath string) error {
args := []string{"guest.download"}
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, remotePath)
args = append(args, localPath)
_, stderr, err := govcOutErr(args...)
if stderr == "" && err == nil {
return nil
} else {
return errors.NewGuestError("download", conn.driver.MachineName, stderr)
}
}
func (conn VcConn) AppendConnectionString(args []string) []string {
args = append(args, fmt.Sprintf("--u=%s:%s@%s", conn.driver.Username, conn.driver.Password, conn.driver.IP))
args = append(args, "--k=true")
return args
}

View File

@ -0,0 +1,450 @@
/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package vmwarevsphere
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
"github.com/docker/docker/utils"
"github.com/docker/machine/drivers"
"github.com/docker/machine/drivers/vmwarevsphere/errors"
"github.com/docker/machine/ssh"
"github.com/docker/machine/state"
)
const (
DATASTORE_DIR = "boot2docker-iso"
B2D_ISO_NAME = "boot2docker.iso"
DEFAULT_CPU_NUMBER = 2
)
type Driver struct {
MachineName string
SSHPort int
CPU int
Memory int
DiskSize int
Boot2DockerURL string
IP string
Username string
Password string
Network string
Datastore string
Datacenter string
Pool string
HostIP string
StorePath string
ISO string
storePath string
}
type CreateFlags struct {
CPU *int
Memory *int
DiskSize *int
Boot2DockerURL *string
IP *string
Username *string
Password *string
Network *string
Datastore *string
Datacenter *string
Pool *string
HostIP *string
}
func init() {
drivers.Register("vmwarevsphere", &drivers.RegisteredDriver{
New: NewDriver,
GetCreateFlags: GetCreateFlags,
})
}
// GetCreateFlags registers the flags this driver adds to
// "docker hosts create"
func GetCreateFlags() []cli.Flag {
return []cli.Flag{
cli.IntFlag{
EnvVar: "VSPHERE_CPU_COUNT",
Name: "vmwarevsphere-cpu-count",
Usage: "vSphere CPU number for docker VM",
Value: 2,
},
cli.IntFlag{
EnvVar: "VSPHERE_MEMORY_SIZE",
Name: "vmwarevsphere-memory-size",
Usage: "vSphere size of memory for docker VM (in MB)",
Value: 2048,
},
cli.IntFlag{
EnvVar: "VSPHERE_DISK_SIZE",
Name: "vmwarevsphere-disk-size",
Usage: "vSphere size of disk for docker VM (in MB)",
Value: 20000,
},
cli.StringFlag{
EnvVar: "VSPHERE_BOOT2DOCKER_URL",
Name: "vmwarevsphere-boot2docker-url",
Usage: "vSphere URL for boot2docker image",
},
cli.StringFlag{
EnvVar: "VSPHERE_VCENTER",
Name: "vmwarevsphere-vcenter",
Usage: "vSphere IP/hostname for vCenter",
},
cli.StringFlag{
EnvVar: "VSPHERE_USERNAME",
Name: "vmwarevsphere-username",
Usage: "vSphere username",
},
cli.StringFlag{
EnvVar: "VSPHERE_PASSWORD",
Name: "vmwarevsphere-password",
Usage: "vSphere password",
},
cli.StringFlag{
EnvVar: "VSPHERE_NETWORK",
Name: "vmwarevsphere-network",
Usage: "vSphere network where the docker VM will be attached",
},
cli.StringFlag{
EnvVar: "VSPHERE_DATASTORE",
Name: "vmwarevsphere-datastore",
Usage: "vSphere datastore for docker VM",
},
cli.StringFlag{
EnvVar: "VSPHERE_DATACENTER",
Name: "vmwarevsphere-datacenter",
Usage: "vSphere datacenter for docker VM",
},
cli.StringFlag{
EnvVar: "VSPHERE_POOL",
Name: "vmwarevsphere-pool",
Usage: "vSphere resource pool for docker VM",
},
cli.StringFlag{
EnvVar: "VSPHERE_COMPUTE_IP",
Name: "vmwarevsphere-compute-ip",
Usage: "vSphere compute host IP where the docker VM will be instantiated",
},
}
}
func NewDriver(storePath string) (drivers.Driver, error) {
return &Driver{StorePath: storePath}, nil
}
func (d *Driver) DriverName() string {
return "vmwarevsphere"
}
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
d.setMachineNameIfNotSet()
d.SSHPort = 22
d.CPU = flags.Int("vmwarevsphere-cpu-count")
d.Memory = flags.Int("vmwarevsphere-memory-size")
d.DiskSize = flags.Int("vmwarevsphere-disk-size")
d.Boot2DockerURL = flags.String("vmwarevsphere-boot2docker-url")
d.IP = flags.String("vmwarevsphere-vcenter")
d.Username = flags.String("vmwarevsphere-username")
d.Password = flags.String("vmwarevsphere-password")
d.Network = flags.String("vmwarevsphere-network")
d.Datastore = flags.String("vmwarevsphere-datastore")
d.Datacenter = flags.String("vmwarevsphere-datacenter")
d.Pool = flags.String("vmwarevsphere-pool")
d.HostIP = flags.String("vmwarevsphere-compute-ip")
d.ISO = path.Join(d.storePath, "boot2docker.iso")
return nil
}
func (d *Driver) GetURL() (string, error) {
ip, _ := d.GetIP()
if ip == "" {
return "", nil
}
return fmt.Sprintf("tcp://%s:2376", ip), nil
}
func (d *Driver) GetIP() (string, error) {
status, err := d.GetState()
if status != state.Running {
return "", errors.NewInvalidStateError(d.MachineName)
}
vcConn := NewVcConn(d)
rawIp, err := vcConn.VmFetchIp()
if err != nil {
return "", err
}
ip := strings.Trim(strings.Split(rawIp, "\n")[0], " ")
return ip, nil
}
func (d *Driver) GetState() (state.State, error) {
vcConn := NewVcConn(d)
stdout, err := vcConn.VmInfo()
if err != nil {
return state.None, err
}
if strings.Contains(stdout, "poweredOn") {
return state.Running, nil
} else if strings.Contains(stdout, "poweredOff") {
return state.Stopped, nil
}
return state.None, nil
}
// the current implementation does the following:
// 1. check whether the docker directory contains the boot2docker ISO
// 2. generate an SSH keypair
// 3. create a virtual machine with the boot2docker ISO mounted;
// 4. reconfigure the virtual machine network and disk size;
func (d *Driver) Create() error {
d.setMachineNameIfNotSet()
if err := d.checkVsphereConfig(); err != nil {
return err
}
var isoURL string
if d.Boot2DockerURL != "" {
isoURL = d.Boot2DockerURL
} else {
// HACK: Docker 1.3 boot2docker image with identity auth and vmtoolsd
isoURL = "https://github.com/cloudnativeapps/boot2docker/releases/download/1.3.1_vmw-identity/boot2docker.iso"
}
log.Infof("Downloading boot2docker...")
if err := downloadISO(d.storePath, "boot2docker.iso", isoURL); err != nil {
return err
}
log.Infof("Generating SSH Keypair...")
if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil {
return err
}
vcConn := NewVcConn(d)
log.Infof("Uploading Boot2docker ISO ...")
if err := vcConn.DatastoreMkdir(DATASTORE_DIR); err != nil {
return err
}
if _, err := os.Stat(d.ISO); os.IsNotExist(err) {
log.Errorf("Unable to find boot2docker ISO at %s", d.ISO)
return errors.NewIncompleteVsphereConfigError(d.ISO)
}
if err := vcConn.DatastoreUpload(d.ISO); err != nil {
return err
}
isoPath := fmt.Sprintf("%s/%s", DATASTORE_DIR, B2D_ISO_NAME)
if err := vcConn.VmCreate(isoPath); err != nil {
return err
}
log.Infof("Configuring the virtual machine %s... ", d.MachineName)
if err := vcConn.VmDiskCreate(); err != nil {
return err
}
if err := vcConn.VmAttachNetwork(); err != nil {
return err
}
if err := d.Start(); err != nil {
return err
}
return nil
}
func (d *Driver) Start() error {
machineState, err := d.GetState()
if err != nil {
return err
}
switch machineState {
case state.Running:
log.Infof("VM %s has already been started", d.MachineName)
return nil
case state.Stopped:
// TODO add transactional or error handling in the following steps
vcConn := NewVcConn(d)
err := vcConn.VmPowerOn()
if err != nil {
return err
}
// this step waits for the vm to start and fetch its ip address;
// this guarantees that the opem-vmtools has started working...
_, err = vcConn.VmFetchIp()
if err != nil {
return err
}
log.Infof("Configuring virtual machine %s... ", d.MachineName)
err = vcConn.GuestMkdir("docker", "tcuser", "/home/docker/.ssh")
if err != nil {
return err
}
// configure the ssh key pair and download the pem file
err = vcConn.GuestUpload("docker", "tcuser", d.publicSSHKeyPath(),
"/home/docker/.ssh/authorized_keys")
if err != nil {
return err
}
// Add identity authorization keys
if err := drivers.AddPublicKeyToAuthorizedHosts(d, "/root/.docker/authorized-keys.d"); err != nil {
return err
}
// Restart Docker
cmd, err := d.GetSSHCommand("sudo /etc/init.d/docker restart")
if err != nil {
return err
}
if err := cmd.Run(); err != nil {
return err
}
return nil
}
return errors.NewInvalidStateError(d.MachineName)
}
func (d *Driver) Stop() error {
vcConn := NewVcConn(d)
err := vcConn.VmPowerOff()
if err != nil {
return err
}
return err
}
func (d *Driver) Remove() error {
machineState, err := d.GetState()
if err != nil {
return err
}
if machineState == state.Running {
if err = d.Stop(); err != nil {
return fmt.Errorf("can't stop VM: %s", err)
}
}
vcConn := NewVcConn(d)
err = vcConn.VmDestroy()
if err != nil {
return err
}
return nil
}
func (d *Driver) Restart() error {
if err := d.Stop(); err != nil {
return err
}
return d.Start()
}
func (d *Driver) Kill() error {
return d.Stop()
}
func (d *Driver) Upgrade() error {
return fmt.Errorf("upgrade is not supported for vsphere driver at this moment")
}
func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) {
ip, err := d.GetIP()
if err != nil {
return nil, err
}
return ssh.GetSSHCommand(ip, d.SSHPort, "docker", d.sshKeyPath(), args...), nil
}
func (d *Driver) setMachineNameIfNotSet() {
if d.MachineName == "" {
d.MachineName = generateVMName()
}
}
func (d *Driver) sshKeyPath() string {
return filepath.Join(d.StorePath, "id_docker_host_vsphere")
}
func (d *Driver) publicSSHKeyPath() string {
return d.sshKeyPath() + ".pub"
}
func (d *Driver) checkVsphereConfig() error {
if d.IP == "" {
return errors.NewIncompleteVsphereConfigError("vSphere IP")
}
if d.Username == "" {
return errors.NewIncompleteVsphereConfigError("vSphere username")
}
if d.Password == "" {
return errors.NewIncompleteVsphereConfigError("vSphere password")
}
if d.Network == "" {
return errors.NewIncompleteVsphereConfigError("vSphere network")
}
if d.Datastore == "" {
return errors.NewIncompleteVsphereConfigError("vSphere datastore")
}
if d.Datacenter == "" {
return errors.NewIncompleteVsphereConfigError("vSphere datacenter")
}
return nil
}
// Download boot2docker ISO image for the given tag and save it at dest.
func downloadISO(dir, file, url string) error {
rsp, err := http.Get(url)
if err != nil {
return err
}
defer rsp.Body.Close()
// Download to a temp file first then rename it to avoid partial download.
f, err := ioutil.TempFile(dir, file+".tmp")
if err != nil {
return err
}
defer os.Remove(f.Name())
if _, err := io.Copy(f, rsp.Body); err != nil {
// TODO: display download progress?
return err
}
if err := f.Close(); err != nil {
return err
}
if err := os.Rename(f.Name(), path.Join(dir, file)); err != nil {
return err
}
return nil
}
func generateVMName() string {
randomID := utils.TruncateID(utils.GenerateRandomID())
return fmt.Sprintf("docker-host-%s", randomID)
}