mirror of https://github.com/docker/docs.git
Added vSphere machine driver
Signed-off-by: Fabio Rapposelli <frapposelli@vmware.com>
This commit is contained in:
parent
92dd8e01d1
commit
1bad10773c
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue