mirror of https://github.com/docker/docs.git
Update vSphere driver to work with govmomi instead of wrapping govc.
Signed-off-by: Fabio Rapposelli <fabio@vmware.com>
This commit is contained in:
parent
1976613fa8
commit
2e90b7cb55
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
/*
|
|
||||||
* 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"
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package vmwarevsphere
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/machine/libmachine/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
GovcCmd = "govc"
|
|
||||||
)
|
|
||||||
|
|
||||||
func govc(args ...string) error {
|
|
||||||
cmd := exec.Command(GovcCmd, args...)
|
|
||||||
|
|
||||||
log.Debugf("govc 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("govcOutErr 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
|
|
||||||
}
|
|
|
@ -1,313 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package vmwarevsphere
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/machine/drivers/vmwarevsphere/errors"
|
|
||||||
"github.com/docker/machine/libmachine/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
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 != "" {
|
|
||||||
return errors.NewDatastoreError(conn.driver.Datastore, "mkdir", stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (conn VcConn) DatastoreUpload(localPath, destination string) error {
|
|
||||||
stdout, err := conn.DatastoreLs(destination)
|
|
||||||
if err == nil && strings.Contains(stdout, isoFilename) {
|
|
||||||
log.Infof("boot2docker ISO already uploaded, skipping upload... ")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Uploading %s to %s on datastore %s of vCenter %s... ",
|
|
||||||
localPath, destination, conn.driver.Datastore, conn.driver.IP)
|
|
||||||
|
|
||||||
dsPath := fmt.Sprintf("%s/%s", destination, isoFilename)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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=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))
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
return errors.NewVMError("power on", conn.driver.MachineName, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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/%s", conn.driver.MachineName, 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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
return errors.NewGuestError("upload", conn.driver.MachineName, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
|
@ -9,51 +9,68 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/machine/libmachine/log"
|
|
||||||
|
|
||||||
"github.com/docker/machine/drivers/vmwarevsphere/errors"
|
|
||||||
"github.com/docker/machine/libmachine/drivers"
|
"github.com/docker/machine/libmachine/drivers"
|
||||||
|
"github.com/docker/machine/libmachine/log"
|
||||||
"github.com/docker/machine/libmachine/mcnflag"
|
"github.com/docker/machine/libmachine/mcnflag"
|
||||||
"github.com/docker/machine/libmachine/mcnutils"
|
"github.com/docker/machine/libmachine/mcnutils"
|
||||||
"github.com/docker/machine/libmachine/ssh"
|
"github.com/docker/machine/libmachine/ssh"
|
||||||
"github.com/docker/machine/libmachine/state"
|
"github.com/docker/machine/libmachine/state"
|
||||||
|
|
||||||
|
"github.com/vmware/govmomi"
|
||||||
|
"github.com/vmware/govmomi/find"
|
||||||
|
"github.com/vmware/govmomi/guest"
|
||||||
|
"github.com/vmware/govmomi/object"
|
||||||
|
"github.com/vmware/govmomi/vim25/mo"
|
||||||
|
"github.com/vmware/govmomi/vim25/soap"
|
||||||
|
"github.com/vmware/govmomi/vim25/types"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
isoFilename = "boot2docker.iso"
|
isoFilename = "boot2docker.iso"
|
||||||
B2DUser = "docker"
|
// B2DUser is the guest User for tools login
|
||||||
B2DPass = "tcuser"
|
B2DUser = "docker"
|
||||||
|
// B2DPass is the guest Pass for tools login
|
||||||
|
B2DPass = "tcuser"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
*drivers.BaseDriver
|
*drivers.BaseDriver
|
||||||
CPU int
|
|
||||||
Memory int
|
Memory int
|
||||||
DiskSize int
|
DiskSize int
|
||||||
Boot2DockerURL string
|
CPU int
|
||||||
IP string
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
Network string
|
|
||||||
Datastore string
|
|
||||||
Datacenter string
|
|
||||||
Pool string
|
|
||||||
HostIP string
|
|
||||||
ISO string
|
ISO string
|
||||||
|
Boot2DockerURL string
|
||||||
|
CPUS int
|
||||||
|
|
||||||
|
IP string
|
||||||
|
Port int
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Network string
|
||||||
|
Datastore string
|
||||||
|
Datacenter string
|
||||||
|
Pool string
|
||||||
|
HostSystem string
|
||||||
|
|
||||||
|
SSHPassword string
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
defaultSSHUser = B2DUser
|
||||||
|
defaultSSHPass = B2DPass
|
||||||
defaultCpus = 2
|
defaultCpus = 2
|
||||||
defaultMemory = 2048
|
defaultMemory = 2048
|
||||||
defaultDiskSize = 20000
|
defaultDiskSize = 20480
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetCreateFlags registers the flags this driver adds to
|
// GetCreateFlags registers the flags this driver adds to
|
||||||
// "docker hosts create"
|
// "docker-machine create"
|
||||||
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
|
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
|
||||||
return []mcnflag.Flag{
|
return []mcnflag.Flag{
|
||||||
mcnflag.IntFlag{
|
mcnflag.IntFlag{
|
||||||
|
@ -84,6 +101,12 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
|
||||||
Name: "vmwarevsphere-vcenter",
|
Name: "vmwarevsphere-vcenter",
|
||||||
Usage: "vSphere IP/hostname for vCenter",
|
Usage: "vSphere IP/hostname for vCenter",
|
||||||
},
|
},
|
||||||
|
mcnflag.IntFlag{
|
||||||
|
EnvVar: "VSPHERE_VCENTER_PORT",
|
||||||
|
Name: "vmwarevsphere-vcenter-port",
|
||||||
|
Usage: "vSphere Port for vCenter",
|
||||||
|
Value: 443,
|
||||||
|
},
|
||||||
mcnflag.StringFlag{
|
mcnflag.StringFlag{
|
||||||
EnvVar: "VSPHERE_USERNAME",
|
EnvVar: "VSPHERE_USERNAME",
|
||||||
Name: "vmwarevsphere-username",
|
Name: "vmwarevsphere-username",
|
||||||
|
@ -115,19 +138,21 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
|
||||||
Usage: "vSphere resource pool for docker VM",
|
Usage: "vSphere resource pool for docker VM",
|
||||||
},
|
},
|
||||||
mcnflag.StringFlag{
|
mcnflag.StringFlag{
|
||||||
EnvVar: "VSPHERE_COMPUTE_IP",
|
EnvVar: "VSPHERE_HOSTSYSTEM",
|
||||||
Name: "vmwarevsphere-compute-ip",
|
Name: "vmwarevsphere-hostsystem",
|
||||||
Usage: "vSphere compute host IP where the docker VM will be instantiated",
|
Usage: "vSphere compute resource where the docker VM will be instantiated (use <cluster>/* or <cluster>/<host> if using a cluster)",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDriver(hostName, storePath string) drivers.Driver {
|
func NewDriver(hostName, storePath string) drivers.Driver {
|
||||||
return &Driver{
|
return &Driver{
|
||||||
CPU: defaultCpus,
|
CPUS: defaultCpus,
|
||||||
Memory: defaultMemory,
|
Memory: defaultMemory,
|
||||||
DiskSize: defaultDiskSize,
|
DiskSize: defaultDiskSize,
|
||||||
|
SSHPassword: defaultSSHPass,
|
||||||
BaseDriver: &drivers.BaseDriver{
|
BaseDriver: &drivers.BaseDriver{
|
||||||
|
SSHUser: defaultSSHUser,
|
||||||
MachineName: hostName,
|
MachineName: hostName,
|
||||||
StorePath: storePath,
|
StorePath: storePath,
|
||||||
},
|
},
|
||||||
|
@ -159,13 +184,14 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
|
||||||
d.DiskSize = flags.Int("vmwarevsphere-disk-size")
|
d.DiskSize = flags.Int("vmwarevsphere-disk-size")
|
||||||
d.Boot2DockerURL = flags.String("vmwarevsphere-boot2docker-url")
|
d.Boot2DockerURL = flags.String("vmwarevsphere-boot2docker-url")
|
||||||
d.IP = flags.String("vmwarevsphere-vcenter")
|
d.IP = flags.String("vmwarevsphere-vcenter")
|
||||||
|
d.Port = flags.Int("vmwarevsphere-vcenter-port")
|
||||||
d.Username = flags.String("vmwarevsphere-username")
|
d.Username = flags.String("vmwarevsphere-username")
|
||||||
d.Password = flags.String("vmwarevsphere-password")
|
d.Password = flags.String("vmwarevsphere-password")
|
||||||
d.Network = flags.String("vmwarevsphere-network")
|
d.Network = flags.String("vmwarevsphere-network")
|
||||||
d.Datastore = flags.String("vmwarevsphere-datastore")
|
d.Datastore = flags.String("vmwarevsphere-datastore")
|
||||||
d.Datacenter = flags.String("vmwarevsphere-datacenter")
|
d.Datacenter = flags.String("vmwarevsphere-datacenter")
|
||||||
d.Pool = flags.String("vmwarevsphere-pool")
|
d.Pool = flags.String("vmwarevsphere-pool")
|
||||||
d.HostIP = flags.String("vmwarevsphere-compute-ip")
|
d.HostSystem = flags.String("vmwarevsphere-hostsystem")
|
||||||
d.SwarmMaster = flags.Bool("swarm-master")
|
d.SwarmMaster = flags.Bool("swarm-master")
|
||||||
d.SwarmHost = flags.String("swarm-host")
|
d.SwarmHost = flags.String("swarm-host")
|
||||||
d.SwarmDiscovery = flags.String("swarm-discovery")
|
d.SwarmDiscovery = flags.String("swarm-discovery")
|
||||||
|
@ -176,7 +202,11 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) GetURL() (string, error) {
|
func (d *Driver) GetURL() (string, error) {
|
||||||
ip, _ := d.GetIP()
|
|
||||||
|
ip, err := d.GetIP()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
if ip == "" {
|
if ip == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
@ -186,27 +216,60 @@ func (d *Driver) GetURL() (string, error) {
|
||||||
func (d *Driver) GetIP() (string, error) {
|
func (d *Driver) GetIP() (string, error) {
|
||||||
status, err := d.GetState()
|
status, err := d.GetState()
|
||||||
if status != state.Running {
|
if status != state.Running {
|
||||||
return "", errors.NewInvalidStateError(d.MachineName)
|
return "", drivers.ErrHostIsNotRunning
|
||||||
}
|
}
|
||||||
vcConn := NewVcConn(d)
|
|
||||||
rawIP, err := vcConn.VMFetchIP()
|
// Create context
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
c, err := d.vsphereLogin(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm, err := d.fetchVM(c, ctx, d.MachineName)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawIP, err := vm.WaitForIP(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
ip := strings.Trim(strings.Split(rawIP, "\n")[0], " ")
|
ip := strings.Trim(strings.Split(rawIP, "\n")[0], " ")
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) GetState() (state.State, error) {
|
func (d *Driver) GetState() (state.State, error) {
|
||||||
vcConn := NewVcConn(d)
|
|
||||||
stdout, err := vcConn.VMInfo()
|
// Create context
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
c, err := d.vsphereLogin(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state.None, err
|
return state.None, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(stdout, "poweredOn") {
|
vm, err := d.fetchVM(c, ctx, d.MachineName)
|
||||||
|
if err != nil {
|
||||||
|
return state.None, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var mvm mo.VirtualMachine
|
||||||
|
|
||||||
|
err = c.RetrieveOne(ctx, vm.Reference(), nil, &mvm)
|
||||||
|
if err != nil {
|
||||||
|
return state.None, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s := mvm.Summary
|
||||||
|
|
||||||
|
if strings.Contains(string(s.Runtime.PowerState), "poweredOn") {
|
||||||
return state.Running, nil
|
return state.Running, nil
|
||||||
} else if strings.Contains(stdout, "poweredOff") {
|
} else if strings.Contains(string(s.Runtime.PowerState), "poweredOff") {
|
||||||
return state.Stopped, nil
|
return state.Stopped, nil
|
||||||
}
|
}
|
||||||
return state.None, nil
|
return state.None, nil
|
||||||
|
@ -214,17 +277,52 @@ func (d *Driver) GetState() (state.State, error) {
|
||||||
|
|
||||||
// PreCreateCheck checks that the machine creation process can be started safely.
|
// PreCreateCheck checks that the machine creation process can be started safely.
|
||||||
func (d *Driver) PreCreateCheck() error {
|
func (d *Driver) PreCreateCheck() error {
|
||||||
if err := d.checkVsphereConfig(); err != nil {
|
log.Debug("Connecting to vSphere for pre-create checks...")
|
||||||
|
// Create context
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
c, err := d.vsphereLogin(ctx)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Downloading boot2docker to cache should be done here to make sure
|
// Create a new finder
|
||||||
// that a download failure will not leave a machine half created.
|
f := find.NewFinder(c.Client, true)
|
||||||
b2dutils := mcnutils.NewB2dUtils(d.StorePath)
|
|
||||||
if err := b2dutils.UpdateISOCache(d.Boot2DockerURL); err != nil {
|
dc, err := d.getDatacenter(f, ctx)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.SetDatacenter(dc)
|
||||||
|
|
||||||
|
if _, err := d.getDatastore(f, ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := d.getNetwork(f, ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hs, err := d.getHostSystem(f, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourcePool
|
||||||
|
if d.Pool != "" {
|
||||||
|
// Find specified Resource Pool
|
||||||
|
if _, err := f.ResourcePool(ctx, d.Pool); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Pick default Resource Pool for Host System
|
||||||
|
if _, err := hs.ResourcePool(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,32 +342,140 @@ func (d *Driver) Create() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
vcConn := NewVcConn(d)
|
// Create context
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
c, err := d.vsphereLogin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Create a new finder
|
||||||
|
f := find.NewFinder(c.Client, true)
|
||||||
|
|
||||||
|
dc, err := d.getDatacenter(f, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.SetDatacenter(dc)
|
||||||
|
|
||||||
|
dss, err := d.getDatastore(f, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
net, err := d.getNetwork(f, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hs, err := d.getHostSystem(f, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var rp *object.ResourcePool
|
||||||
|
if d.Pool != "" {
|
||||||
|
// Find specified Resource Pool
|
||||||
|
rp, err = f.ResourcePool(ctx, d.Pool)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Pick default Resource Pool for Host System
|
||||||
|
rp, err = hs.ResourcePool(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec := types.VirtualMachineConfigSpec{
|
||||||
|
Name: d.MachineName,
|
||||||
|
GuestId: "otherLinux64Guest",
|
||||||
|
Files: &types.VirtualMachineFileInfo{VmPathName: fmt.Sprintf("[%s]", dss.Name())},
|
||||||
|
NumCPUs: d.CPU,
|
||||||
|
MemoryMB: int64(d.Memory),
|
||||||
|
}
|
||||||
|
|
||||||
|
scsi, err := object.SCSIControllerTypes().CreateSCSIController("pvscsi")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{
|
||||||
|
Operation: types.VirtualDeviceConfigSpecOperationAdd,
|
||||||
|
Device: scsi,
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Infof("Creating VM...")
|
||||||
|
folders, err := dc.Folders(ctx)
|
||||||
|
task, err := folders.VmFolder.CreateVM(ctx, spec, rp, hs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := task.WaitForResult(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
log.Infof("Uploading Boot2docker ISO ...")
|
log.Infof("Uploading Boot2docker ISO ...")
|
||||||
if err := vcConn.DatastoreMkdir(d.MachineName); err != nil {
|
dsurl, err := dss.URL(ctx, dc, fmt.Sprintf("%s/%s", d.MachineName, isoFilename))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p := soap.DefaultUpload
|
||||||
|
if err = c.Client.UploadFile(d.ISO, dsurl, &p); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(d.ISO); os.IsNotExist(err) {
|
// Retrieve the new VM
|
||||||
log.Errorf("Unable to find boot2docker ISO at %s", d.ISO)
|
vm := object.NewVirtualMachine(c.Client, info.Result.(types.ManagedObjectReference))
|
||||||
return errors.NewIncompleteVsphereConfigError(d.ISO)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := vcConn.DatastoreUpload(d.ISO, d.MachineName); err != nil {
|
devices, err := vm.Device(ctx)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
isoPath := fmt.Sprintf("%s/%s", d.MachineName, isoFilename)
|
var add []types.BaseVirtualDevice
|
||||||
if err := vcConn.VMCreate(isoPath); err != nil {
|
|
||||||
|
controller, err := devices.FindDiskController("scsi")
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Configuring the virtual machine %s... ", d.MachineName)
|
disk := devices.CreateDisk(controller, dss.Path(fmt.Sprintf("%s/%s.vmdk", d.MachineName, d.MachineName)))
|
||||||
if err := vcConn.VMDiskCreate(); err != nil {
|
|
||||||
|
// Convert MB to KB
|
||||||
|
disk.CapacityInKB = int64(d.DiskSize) * 1024
|
||||||
|
|
||||||
|
add = append(add, disk)
|
||||||
|
ide, err := devices.FindIDEController("")
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := vcConn.VMAttachNetwork(); err != nil {
|
cdrom, err := devices.CreateCdrom(ide)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
add = append(add, devices.InsertIso(cdrom, dss.Path(fmt.Sprintf("%s/%s", d.MachineName, isoFilename))))
|
||||||
|
|
||||||
|
backing, err := net.EthernetCardBackingInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
netdev, err := object.EthernetCardTypes().CreateEthernetCard("vmxnet3", backing)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Reconfiguring VM...")
|
||||||
|
add = append(add, netdev)
|
||||||
|
if vm.AddDevice(ctx, add...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,18 +483,57 @@ func (d *Driver) Create() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Infof("Provisioning certs and ssh keys...")
|
||||||
// Generate a tar keys bundle
|
// Generate a tar keys bundle
|
||||||
if err := d.generateKeyBundle(); err != nil {
|
if err := d.generateKeyBundle(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy SSH keys bundle
|
opman := guest.NewOperationsManager(c.Client, vm.Reference())
|
||||||
if err := vcConn.GuestUpload(B2DUser, B2DPass, d.ResolveStorePath("userdata.tar"), "/home/docker/userdata.tar"); err != nil {
|
|
||||||
|
fileman, err := opman.FileManager(ctx)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand tar file.
|
src := d.ResolveStorePath("userdata.tar")
|
||||||
if err := vcConn.GuestStart(B2DUser, B2DPass, "/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 {
|
s, err := os.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
auth := AuthFlag{}
|
||||||
|
flag := FileAttrFlag{}
|
||||||
|
auth.auth.Username = B2DUser
|
||||||
|
auth.auth.Password = B2DPass
|
||||||
|
flag.SetPerms(0, 0, 660)
|
||||||
|
url, err := fileman.InitiateFileTransferToGuest(ctx, auth.Auth(), "/home/docker/userdata.tar", flag.Attr(), s.Size(), true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u, err := c.Client.ParseURL(url)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = c.Client.UploadFile(src, u, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
procman, err := opman.ProcessManager(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var env []string
|
||||||
|
guestspec := types.GuestProgramSpec{
|
||||||
|
ProgramPath: "/usr/bin/sudo",
|
||||||
|
Arguments: "/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",
|
||||||
|
WorkingDirectory: "",
|
||||||
|
EnvVariables: env,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = procman.StartProgram(ctx, auth.Auth(), &guestspec)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,27 +552,53 @@ func (d *Driver) Start() error {
|
||||||
return nil
|
return nil
|
||||||
case state.Stopped:
|
case state.Stopped:
|
||||||
// TODO add transactional or error handling in the following steps
|
// TODO add transactional or error handling in the following steps
|
||||||
vcConn := NewVcConn(d)
|
// Create context
|
||||||
err := vcConn.VMPowerOn()
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
if err != nil {
|
defer cancel()
|
||||||
return err
|
|
||||||
}
|
c, err := d.vsphereLogin(ctx)
|
||||||
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
d.IPAddress, err = d.GetIP()
|
vm, err := d.fetchVM(c, ctx, d.MachineName)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof("Powering on VM...")
|
||||||
|
task, err := vm.PowerOn(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = task.WaitForResult(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Waiting for VMware Tools to come online...")
|
||||||
|
if d.IPAddress, err = d.GetIP(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return errors.NewInvalidStateError(d.MachineName)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) Stop() error {
|
func (d *Driver) Stop() error {
|
||||||
vcConn := NewVcConn(d)
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
if err := vcConn.VMShutdown(); err != nil {
|
defer cancel()
|
||||||
|
|
||||||
|
c, err := d.vsphereLogin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
vm, err := d.fetchVM(c, ctx, d.MachineName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof("Powering off VM...")
|
||||||
|
if err := vm.ShutdownGuest(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,8 +617,56 @@ func (d *Driver) Remove() error {
|
||||||
return fmt.Errorf("can't stop VM: %s", err)
|
return fmt.Errorf("can't stop VM: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vcConn := NewVcConn(d)
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
if err = vcConn.VMDestroy(); err != nil {
|
defer cancel()
|
||||||
|
|
||||||
|
c, err := d.vsphereLogin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new finder
|
||||||
|
f := find.NewFinder(c.Client, true)
|
||||||
|
|
||||||
|
dc, err := d.getDatacenter(f, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.SetDatacenter(dc)
|
||||||
|
|
||||||
|
dss, err := d.getDatastore(f, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove B2D Iso from VM folder
|
||||||
|
m := object.NewFileManager(c.Client)
|
||||||
|
task, err := m.DeleteDatastoreFile(ctx, dss.Path(fmt.Sprintf("%s/%s", d.MachineName, isoFilename)), dc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = task.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
if types.IsFileNotFound(err) {
|
||||||
|
// Ignore error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vm, err := d.fetchVM(c, ctx, d.MachineName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
task, err = vm.Destroy(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = task.WaitForResult(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -385,8 +704,26 @@ func (d *Driver) Restart() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) Kill() error {
|
func (d *Driver) Kill() error {
|
||||||
vcConn := NewVcConn(d)
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
if err := vcConn.VMPowerOff(); err != nil {
|
defer cancel()
|
||||||
|
|
||||||
|
c, err := d.vsphereLogin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
vm, err := d.fetchVM(c, ctx, d.MachineName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof("Powering off VM forcibly...")
|
||||||
|
task, err := vm.PowerOff(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = task.WaitForResult(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,28 +740,6 @@ func (d *Driver) publicSSHKeyPath() string {
|
||||||
return d.GetSSHKeyPath() + ".pub"
|
return d.GetSSHKeyPath() + ".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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a boot2docker userdata.tar key bundle
|
// Make a boot2docker userdata.tar key bundle
|
||||||
func (d *Driver) generateKeyBundle() error {
|
func (d *Driver) generateKeyBundle() error {
|
||||||
log.Debugf("Creating Tar key bundle...")
|
log.Debugf("Creating Tar key bundle...")
|
||||||
|
@ -480,19 +795,145 @@ func (d *Driver) generateKeyBundle() error {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) UpgradeISO() error {
|
func (d *Driver) vsphereLogin(ctx context.Context) (*govmomi.Client, error) {
|
||||||
|
|
||||||
vcConn := NewVcConn(d)
|
// Parse URL from string
|
||||||
|
u, err := url.Parse(fmt.Sprintf("https://%s:%d/sdk", d.IP, d.Port))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// set username and password for the URL
|
||||||
|
u.User = url.UserPassword(d.Username, d.Password)
|
||||||
|
|
||||||
if _, err := os.Stat(d.ISO); os.IsNotExist(err) {
|
// Connect and log in to ESX or vCenter
|
||||||
log.Errorf("Unable to find boot2docker ISO at %s", d.ISO)
|
c, err := govmomi.NewClient(ctx, u, true)
|
||||||
return errors.NewIncompleteVsphereConfigError(d.ISO)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := vcConn.DatastoreUpload(d.ISO, d.MachineName); err != nil {
|
return c, nil
|
||||||
return err
|
}
|
||||||
|
|
||||||
|
func (d *Driver) fetchVM(c *govmomi.Client, ctx context.Context, vmname string) (*object.VirtualMachine, error) {
|
||||||
|
|
||||||
|
// Create a new finder
|
||||||
|
f := find.NewFinder(c.Client, true)
|
||||||
|
|
||||||
|
var vm *object.VirtualMachine
|
||||||
|
var err error
|
||||||
|
|
||||||
|
dc, err := d.getDatacenter(f, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return vm, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
f.SetDatacenter(dc)
|
||||||
|
|
||||||
|
vm, err = f.VirtualMachine(ctx, vmname)
|
||||||
|
if err != nil {
|
||||||
|
return vm, err
|
||||||
|
}
|
||||||
|
return vm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthFlag struct {
|
||||||
|
auth types.NamePasswordAuthentication
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *AuthFlag) Auth() types.BaseGuestAuthentication {
|
||||||
|
return &f.auth
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileAttrFlag struct {
|
||||||
|
types.GuestPosixFileAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileAttrFlag) SetPerms(owner, group, perms int) {
|
||||||
|
f.OwnerId = owner
|
||||||
|
f.GroupId = group
|
||||||
|
f.Permissions = int64(perms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileAttrFlag) Attr() types.BaseGuestFileAttributes {
|
||||||
|
return &f.GuestPosixFileAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) getDatacenter(f *find.Finder, ctx context.Context) (dc *object.Datacenter, err error) {
|
||||||
|
|
||||||
|
// Datacenter
|
||||||
|
if d.Datacenter != "" {
|
||||||
|
// Find specified Datacenter
|
||||||
|
dc, err = f.Datacenter(ctx, d.Datacenter)
|
||||||
|
if err != nil {
|
||||||
|
return dc, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Use default Datacenter
|
||||||
|
dc, err = f.DefaultDatacenter(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return dc, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("Datacenter found: ", dc)
|
||||||
|
return dc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) getDatastore(f *find.Finder, ctx context.Context) (dss *object.Datastore, err error) {
|
||||||
|
|
||||||
|
// Datastore
|
||||||
|
if d.Datastore != "" {
|
||||||
|
// Find specified Datastore
|
||||||
|
dss, err = f.Datastore(ctx, d.Datastore)
|
||||||
|
if err != nil {
|
||||||
|
return dss, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Find default Datastore
|
||||||
|
dss, err = f.DefaultDatastore(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return dss, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("Datastore found: ", dss)
|
||||||
|
return dss, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) getNetwork(f *find.Finder, ctx context.Context) (net object.NetworkReference, err error) {
|
||||||
|
|
||||||
|
// Network
|
||||||
|
if d.Network != "" {
|
||||||
|
// Find specified Network
|
||||||
|
net, err = f.Network(ctx, d.Network)
|
||||||
|
if err != nil {
|
||||||
|
return net, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Find default Network
|
||||||
|
net, err = f.DefaultNetwork(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return net, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("Network found: ", net)
|
||||||
|
return net, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Driver) getHostSystem(f *find.Finder, ctx context.Context) (hs *object.HostSystem, err error) {
|
||||||
|
// HostSystem
|
||||||
|
if d.HostSystem != "" {
|
||||||
|
// Find specified HostSystem
|
||||||
|
hs, err = f.HostSystem(ctx, d.HostSystem)
|
||||||
|
if err != nil {
|
||||||
|
return hs, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Find default HostSystem
|
||||||
|
hs, err = f.DefaultHostSystem(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return hs, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("HostSystem found: ", hs)
|
||||||
|
return hs, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue