mirror of https://github.com/docker/docs.git
Test VirtualBox VM creation
Signed-off-by: David Gageot <david@gageot.net>
This commit is contained in:
parent
248596da8a
commit
ea9bbcb367
|
@ -1,10 +1,120 @@
|
||||||
package virtualbox
|
package virtualbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/docker/machine/libmachine/log"
|
||||||
|
"github.com/docker/machine/libmachine/mcnutils"
|
||||||
|
)
|
||||||
|
|
||||||
type VirtualDisk struct {
|
type VirtualDisk struct {
|
||||||
UUID string
|
UUID string
|
||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DiskCreator interface {
|
||||||
|
Create(size int, publicSSHKeyPath, diskPath string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDiskCreator() DiskCreator {
|
||||||
|
return &defaultDiskCreator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultDiskCreator struct{}
|
||||||
|
|
||||||
|
// Make a boot2docker VM disk image.
|
||||||
|
func (c *defaultDiskCreator) Create(size int, publicSSHKeyPath, diskPath string) error {
|
||||||
|
log.Debugf("Creating %d MB hard disk image...", size)
|
||||||
|
|
||||||
|
tarBuf, err := mcnutils.MakeDiskImage(publicSSHKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Calling inner createDiskImage")
|
||||||
|
|
||||||
|
return createDiskImage(diskPath, size, tarBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// createDiskImage makes a disk image at dest with the given size in MB. If r is
|
||||||
|
// not nil, it will be read as a raw disk image to convert from.
|
||||||
|
func createDiskImage(dest string, size int, r io.Reader) error {
|
||||||
|
// Convert a raw image from stdin to the dest VMDK image.
|
||||||
|
sizeBytes := int64(size) << 20 // usually won't fit in 32-bit int (max 2GB)
|
||||||
|
// FIXME: why isn't this just using the vbm*() functions?
|
||||||
|
cmd := exec.Command(vboxManageCmd, "convertfromraw", "stdin", dest,
|
||||||
|
fmt.Sprintf("%d", sizeBytes), "--format", "VMDK")
|
||||||
|
|
||||||
|
log.Debug(cmd)
|
||||||
|
|
||||||
|
if os.Getenv("MACHINE_DEBUG") != "" {
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
stdin, err := cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Starting command")
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Copying to stdin")
|
||||||
|
|
||||||
|
n, err := io.Copy(stdin, r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Filling zeroes")
|
||||||
|
|
||||||
|
// The total number of bytes written to stdin must match sizeBytes, or
|
||||||
|
// VBoxManage.exe on Windows will fail. Fill remaining with zeros.
|
||||||
|
if left := sizeBytes - n; left > 0 {
|
||||||
|
if err := zeroFill(stdin, left); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Closing STDIN")
|
||||||
|
|
||||||
|
// cmd won't exit until the stdin is closed.
|
||||||
|
if err := stdin.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Waiting on cmd")
|
||||||
|
|
||||||
|
return cmd.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// zeroFill writes n zero bytes into w.
|
||||||
|
func zeroFill(w io.Writer, n int64) error {
|
||||||
|
const blocksize = 32 << 10
|
||||||
|
zeros := make([]byte, blocksize)
|
||||||
|
var k int
|
||||||
|
var err error
|
||||||
|
for n > 0 {
|
||||||
|
if n > blocksize {
|
||||||
|
k, err = w.Write(zeros)
|
||||||
|
} else {
|
||||||
|
k, err = w.Write(zeros[:n])
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n -= int64(k)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func getVMDiskInfo(name string, vbox VBoxManager) (*VirtualDisk, error) {
|
func getVMDiskInfo(name string, vbox VBoxManager) (*VirtualDisk, error) {
|
||||||
out, err := vbox.vbmOut("showvminfo", name, "--machinereadable")
|
out, err := vbox.vbmOut("showvminfo", name, "--machinereadable")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package virtualbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/machine/libmachine/drivers"
|
||||||
|
"github.com/docker/machine/libmachine/mcnutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IPWaiter waits for an IP to be configured.
|
||||||
|
type IPWaiter interface {
|
||||||
|
Wait(d *Driver) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIPWaiter() IPWaiter {
|
||||||
|
return &sshIPWaiter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type sshIPWaiter struct{}
|
||||||
|
|
||||||
|
func (w *sshIPWaiter) Wait(d *Driver) error {
|
||||||
|
// Wait for SSH over NAT to be available before returning to user
|
||||||
|
if err := drivers.WaitForSSH(d); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail if we don't get an IP from DHCP after a given number of seconds.
|
||||||
|
if err := mcnutils.WaitForSpecific(d.hostOnlyIPAvailable, 5, 4*time.Second); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
d.IPAddress, err = d.GetIP()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package virtualbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/machine/libmachine/mcnutils"
|
||||||
|
"github.com/docker/machine/libmachine/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
// B2DUpdater describes the interactions with bd2.
|
||||||
|
type B2DUpdater interface {
|
||||||
|
UpdateISOCache(storePath, isoURL string) error
|
||||||
|
CopyIsoToMachineDir(storePath, machineName, isoURL string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewB2DUpdater() B2DUpdater {
|
||||||
|
return &b2dUtilsUpdater{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type b2dUtilsUpdater struct{}
|
||||||
|
|
||||||
|
func (u *b2dUtilsUpdater) CopyIsoToMachineDir(storePath, machineName, isoURL string) error {
|
||||||
|
return mcnutils.NewB2dUtils(storePath).CopyIsoToMachineDir(isoURL, machineName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *b2dUtilsUpdater) UpdateISOCache(storePath, isoURL string) error {
|
||||||
|
return mcnutils.NewB2dUtils(storePath).UpdateISOCache(isoURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSHKeyGenerator describes the generation of ssh keys.
|
||||||
|
type SSHKeyGenerator interface {
|
||||||
|
Generate(path string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSSHKeyGenerator() SSHKeyGenerator {
|
||||||
|
return &defaultSSHKeyGenerator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultSSHKeyGenerator struct{}
|
||||||
|
|
||||||
|
func (g *defaultSSHKeyGenerator) Generate(path string) error {
|
||||||
|
return ssh.GenerateSSHKey(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogsReader describes the reading of VBox.log
|
||||||
|
type LogsReader interface {
|
||||||
|
Read(path string) ([]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogsReader() LogsReader {
|
||||||
|
return &vBoxLogsReader{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type vBoxLogsReader struct{}
|
||||||
|
|
||||||
|
func (c *vBoxLogsReader) Read(path string) ([]string, error) {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
lines := []string{}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomInter returns random int values.
|
||||||
|
type RandomInter interface {
|
||||||
|
RandomInt(n int) int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRandomInter() RandomInter {
|
||||||
|
return &defaultRandomInter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultRandomInter struct{}
|
||||||
|
|
||||||
|
func (d *defaultRandomInter) RandomInt(n int) int {
|
||||||
|
return rand.Intn(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sleeper sleeps for given duration.
|
||||||
|
type Sleeper interface {
|
||||||
|
Sleep(d time.Duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSleeper() Sleeper {
|
||||||
|
return &defaultSleeper{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultSleeper struct{}
|
||||||
|
|
||||||
|
func (s *defaultSleeper) Sleep(d time.Duration) {
|
||||||
|
time.Sleep(d)
|
||||||
|
}
|
|
@ -1,11 +1,8 @@
|
||||||
package virtualbox
|
package virtualbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"math/rand"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -20,7 +17,6 @@ import (
|
||||||
"github.com/docker/machine/libmachine/log"
|
"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/state"
|
"github.com/docker/machine/libmachine/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -43,8 +39,15 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
VBoxManager
|
|
||||||
*drivers.BaseDriver
|
*drivers.BaseDriver
|
||||||
|
VBoxManager
|
||||||
|
b2dUpdater B2DUpdater
|
||||||
|
sshKeyGenerator SSHKeyGenerator
|
||||||
|
diskCreator DiskCreator
|
||||||
|
logsReader LogsReader
|
||||||
|
ipWaiter IPWaiter
|
||||||
|
randomInter RandomInter
|
||||||
|
sleeper Sleeper
|
||||||
CPU int
|
CPU int
|
||||||
Memory int
|
Memory int
|
||||||
DiskSize int
|
DiskSize int
|
||||||
|
@ -62,17 +65,24 @@ type Driver struct {
|
||||||
// NewDriver creates a new VirtualBox driver with default settings.
|
// NewDriver creates a new VirtualBox driver with default settings.
|
||||||
func NewDriver(hostName, storePath string) *Driver {
|
func NewDriver(hostName, storePath string) *Driver {
|
||||||
return &Driver{
|
return &Driver{
|
||||||
VBoxManager: NewVBoxManager(),
|
VBoxManager: NewVBoxManager(),
|
||||||
BaseDriver: &drivers.BaseDriver{
|
b2dUpdater: NewB2DUpdater(),
|
||||||
MachineName: hostName,
|
sshKeyGenerator: NewSSHKeyGenerator(),
|
||||||
StorePath: storePath,
|
diskCreator: NewDiskCreator(),
|
||||||
},
|
logsReader: NewLogsReader(),
|
||||||
|
ipWaiter: NewIPWaiter(),
|
||||||
|
randomInter: NewRandomInter(),
|
||||||
|
sleeper: NewSleeper(),
|
||||||
Memory: defaultMemory,
|
Memory: defaultMemory,
|
||||||
CPU: defaultCPU,
|
CPU: defaultCPU,
|
||||||
DiskSize: defaultDiskSize,
|
DiskSize: defaultDiskSize,
|
||||||
HostOnlyCIDR: defaultHostOnlyCIDR,
|
HostOnlyCIDR: defaultHostOnlyCIDR,
|
||||||
HostOnlyNicType: defaultHostOnlyNictype,
|
HostOnlyNicType: defaultHostOnlyNictype,
|
||||||
HostOnlyPromiscMode: defaultHostOnlyPromiscMode,
|
HostOnlyPromiscMode: defaultHostOnlyPromiscMode,
|
||||||
|
BaseDriver: &drivers.BaseDriver{
|
||||||
|
MachineName: hostName,
|
||||||
|
StorePath: storePath,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,8 +233,7 @@ func (d *Driver) PreCreateCheck() error {
|
||||||
|
|
||||||
// Downloading boot2docker to cache should be done here to make sure
|
// Downloading boot2docker to cache should be done here to make sure
|
||||||
// that a download failure will not leave a machine half created.
|
// that a download failure will not leave a machine half created.
|
||||||
b2dutils := mcnutils.NewB2dUtils(d.StorePath)
|
if err := d.b2dUpdater.UpdateISOCache(d.StorePath, d.Boot2DockerURL); err != nil {
|
||||||
if err := b2dutils.UpdateISOCache(d.Boot2DockerURL); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,22 +250,19 @@ func (d *Driver) IsVTXDisabledInTheVM() (bool, error) {
|
||||||
logPath := filepath.Join(d.ResolveStorePath(d.MachineName), "Logs", "VBox.log")
|
logPath := filepath.Join(d.ResolveStorePath(d.MachineName), "Logs", "VBox.log")
|
||||||
log.Debugf("Checking vm logs: %s", logPath)
|
log.Debugf("Checking vm logs: %s", logPath)
|
||||||
|
|
||||||
file, err := os.Open(logPath)
|
lines, err := d.logsReader.Read(logPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer file.Close()
|
for _, line := range lines {
|
||||||
|
if strings.Contains(line, "VT-x is disabled") {
|
||||||
scanner := bufio.NewScanner(file)
|
|
||||||
for scanner.Scan() {
|
|
||||||
if strings.Contains(scanner.Text(), "VT-x is disabled") {
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
if strings.Contains(scanner.Text(), "the host CPU does NOT support HW virtualization") {
|
if strings.Contains(line, "the host CPU does NOT support HW virtualization") {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
if strings.Contains(scanner.Text(), "VERR_VMX_UNABLE_TO_START_VM") {
|
if strings.Contains(line, "VERR_VMX_UNABLE_TO_START_VM") {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,8 +271,16 @@ func (d *Driver) IsVTXDisabledInTheVM() (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) Create() error {
|
func (d *Driver) Create() error {
|
||||||
b2dutils := mcnutils.NewB2dUtils(d.StorePath)
|
if err := d.CreateVM(); err != nil {
|
||||||
if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Starting the VM...")
|
||||||
|
return d.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Driver) CreateVM() error {
|
||||||
|
if err := d.b2dUpdater.CopyIsoToMachineDir(d.StorePath, d.MachineName, d.Boot2DockerURL); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,12 +322,12 @@ func (d *Driver) Create() error {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Infof("Creating SSH key...")
|
log.Infof("Creating SSH key...")
|
||||||
if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
|
if err := d.sshKeyGenerator.Generate(d.GetSSHKeyPath()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Creating disk image...")
|
log.Debugf("Creating disk image...")
|
||||||
if err := d.generateDiskImage(d.DiskSize); err != nil {
|
if err := d.diskCreator.Create(d.DiskSize, d.publicSSHKeyPath(), d.diskPath()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -438,8 +452,7 @@ func (d *Driver) Create() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Starting the VM...")
|
return nil
|
||||||
return d.Start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) hostOnlyIPAvailable() bool {
|
func (d *Driver) hostOnlyIPAvailable() bool {
|
||||||
|
@ -502,7 +515,7 @@ func (d *Driver) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Waiting for an IP...")
|
log.Infof("Waiting for an IP...")
|
||||||
if err := d.waitForIP(); err != nil {
|
if err := d.ipWaiter.Wait(d); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +548,7 @@ func (d *Driver) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to be sure the host-only adapter is not used by the VM
|
// We have to be sure the host-only adapter is not used by the VM
|
||||||
time.Sleep(5 * time.Second)
|
d.sleeper.Sleep(5 * time.Second)
|
||||||
|
|
||||||
log.Debugf("Fixing %+v...", hostOnlyAdapter)
|
log.Debugf("Fixing %+v...", hostOnlyAdapter)
|
||||||
if err := hostOnlyAdapter.SaveIPv4(d.VBoxManager); err != nil {
|
if err := hostOnlyAdapter.SaveIPv4(d.VBoxManager); err != nil {
|
||||||
|
@ -543,14 +556,14 @@ func (d *Driver) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to be sure the adapter is updated before starting the VM
|
// We have to be sure the adapter is updated before starting the VM
|
||||||
time.Sleep(5 * time.Second)
|
d.sleeper.Sleep(5 * time.Second)
|
||||||
|
|
||||||
if err := d.vbm("startvm", d.MachineName, "--type", "headless"); err != nil {
|
if err := d.vbm("startvm", d.MachineName, "--type", "headless"); err != nil {
|
||||||
return fmt.Errorf("Unable to start the VM: %s", err)
|
return fmt.Errorf("Unable to start the VM: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Waiting for an IP...")
|
log.Infof("Waiting for an IP...")
|
||||||
return d.waitForIP()
|
return d.ipWaiter.Wait(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) Stop() error {
|
func (d *Driver) Stop() error {
|
||||||
|
@ -575,7 +588,7 @@ func (d *Driver) Stop() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if s == state.Running {
|
if s == state.Running {
|
||||||
time.Sleep(1 * time.Second)
|
d.sleeper.Sleep(1 * time.Second)
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -594,30 +607,13 @@ func (d *Driver) Restart() error {
|
||||||
|
|
||||||
d.IPAddress = ""
|
d.IPAddress = ""
|
||||||
|
|
||||||
return d.waitForIP()
|
return d.ipWaiter.Wait(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) Kill() error {
|
func (d *Driver) Kill() error {
|
||||||
return d.vbm("controlvm", d.MachineName, "poweroff")
|
return d.vbm("controlvm", d.MachineName, "poweroff")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) waitForIP() error {
|
|
||||||
// Wait for SSH over NAT to be available before returning to user
|
|
||||||
if err := drivers.WaitForSSH(d); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bail if we don't get an IP from DHCP after a given number of seconds.
|
|
||||||
if err := mcnutils.WaitForSpecific(d.hostOnlyIPAvailable, 5, 4*time.Second); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
d.IPAddress, err = d.GetIP()
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) Remove() error {
|
func (d *Driver) Remove() error {
|
||||||
s, err := d.GetState()
|
s, err := d.GetState()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -637,7 +633,7 @@ func (d *Driver) Remove() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// vbox will not release it's lock immediately after the stop
|
// vbox will not release it's lock immediately after the stop
|
||||||
time.Sleep(1 * time.Second)
|
d.sleeper.Sleep(1 * time.Second)
|
||||||
return d.vbm("unregistervm", "--delete", d.MachineName)
|
return d.vbm("unregistervm", "--delete", d.MachineName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,20 +701,6 @@ func (d *Driver) diskPath() string {
|
||||||
return d.ResolveStorePath("disk.vmdk")
|
return d.ResolveStorePath("disk.vmdk")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a boot2docker VM disk image.
|
|
||||||
func (d *Driver) generateDiskImage(size int) error {
|
|
||||||
log.Debugf("Creating %d MB hard disk image...", size)
|
|
||||||
|
|
||||||
tarBuf, err := mcnutils.MakeDiskImage(d.publicSSHKeyPath())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("Calling inner createDiskImage")
|
|
||||||
|
|
||||||
return createDiskImage(d.diskPath(), size, tarBuf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) setupHostOnlyNetwork(machineName string) (*hostOnlyNetwork, error) {
|
func (d *Driver) setupHostOnlyNetwork(machineName string) (*hostOnlyNetwork, error) {
|
||||||
hostOnlyCIDR := d.HostOnlyCIDR
|
hostOnlyCIDR := d.HostOnlyCIDR
|
||||||
|
|
||||||
|
@ -744,7 +726,7 @@ func (d *Driver) setupHostOnlyNetwork(machineName string) (*hostOnlyNetwork, err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dhcpAddr, err := getRandomIPinSubnet(ip)
|
dhcpAddr, err := getRandomIPinSubnet(d, ip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -788,82 +770,6 @@ func parseAndValidateCIDR(hostOnlyCIDR string) (net.IP, *net.IPNet, error) {
|
||||||
return ip, network, nil
|
return ip, network, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createDiskImage makes a disk image at dest with the given size in MB. If r is
|
|
||||||
// not nil, it will be read as a raw disk image to convert from.
|
|
||||||
func createDiskImage(dest string, size int, r io.Reader) error {
|
|
||||||
// Convert a raw image from stdin to the dest VMDK image.
|
|
||||||
sizeBytes := int64(size) << 20 // usually won't fit in 32-bit int (max 2GB)
|
|
||||||
// FIXME: why isn't this just using the vbm*() functions?
|
|
||||||
cmd := exec.Command(vboxManageCmd, "convertfromraw", "stdin", dest,
|
|
||||||
fmt.Sprintf("%d", sizeBytes), "--format", "VMDK")
|
|
||||||
|
|
||||||
log.Debug(cmd)
|
|
||||||
|
|
||||||
if os.Getenv("MACHINE_DEBUG") != "" {
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
}
|
|
||||||
|
|
||||||
stdin, err := cmd.StdinPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("Starting command")
|
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("Copying to stdin")
|
|
||||||
|
|
||||||
n, err := io.Copy(stdin, r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("Filling zeroes")
|
|
||||||
|
|
||||||
// The total number of bytes written to stdin must match sizeBytes, or
|
|
||||||
// VBoxManage.exe on Windows will fail. Fill remaining with zeros.
|
|
||||||
if left := sizeBytes - n; left > 0 {
|
|
||||||
if err := zeroFill(stdin, left); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("Closing STDIN")
|
|
||||||
|
|
||||||
// cmd won't exit until the stdin is closed.
|
|
||||||
if err := stdin.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("Waiting on cmd")
|
|
||||||
|
|
||||||
return cmd.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// zeroFill writes n zero bytes into w.
|
|
||||||
func zeroFill(w io.Writer, n int64) error {
|
|
||||||
const blocksize = 32 << 10
|
|
||||||
zeros := make([]byte, blocksize)
|
|
||||||
var k int
|
|
||||||
var err error
|
|
||||||
for n > 0 {
|
|
||||||
if n > blocksize {
|
|
||||||
k, err = w.Write(zeros)
|
|
||||||
} else {
|
|
||||||
k, err = w.Write(zeros[:n])
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
n -= int64(k)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select an available port, trying the specified
|
// Select an available port, trying the specified
|
||||||
// port first, falling back on an OS selected port.
|
// port first, falling back on an OS selected port.
|
||||||
func getAvailableTCPPort(port int) (int, error) {
|
func getAvailableTCPPort(port int) (int, error) {
|
||||||
|
@ -910,14 +816,14 @@ func setPortForwarding(d *Driver, interfaceNum int, mapName, protocol string, gu
|
||||||
|
|
||||||
// getRandomIPinSubnet returns a pseudo-random net.IP in the same
|
// getRandomIPinSubnet returns a pseudo-random net.IP in the same
|
||||||
// subnet as the IP passed
|
// subnet as the IP passed
|
||||||
func getRandomIPinSubnet(baseIP net.IP) (net.IP, error) {
|
func getRandomIPinSubnet(d *Driver, baseIP net.IP) (net.IP, error) {
|
||||||
var dhcpAddr net.IP
|
var dhcpAddr net.IP
|
||||||
|
|
||||||
nAddr := baseIP.To4()
|
nAddr := baseIP.To4()
|
||||||
// select pseudo-random DHCP addr; make sure not to clash with the host
|
// select pseudo-random DHCP addr; make sure not to clash with the host
|
||||||
// only try 5 times and bail if no random received
|
// only try 5 times and bail if no random received
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
n := rand.Intn(25)
|
n := d.randomInter.RandomInt(25)
|
||||||
if byte(n) != nAddr[3] {
|
if byte(n) != nAddr[3] {
|
||||||
dhcpAddr = net.IPv4(nAddr[0], nAddr[1], nAddr[2], byte(n))
|
dhcpAddr = net.IPv4(nAddr[0], nAddr[1], nAddr[2], byte(n))
|
||||||
break
|
break
|
||||||
|
|
|
@ -6,30 +6,15 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/machine/libmachine/drivers"
|
"github.com/docker/machine/libmachine/drivers"
|
||||||
"github.com/docker/machine/libmachine/state"
|
"github.com/docker/machine/libmachine/state"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDriverName(t *testing.T) {
|
|
||||||
driverName := newTestDriver("default").DriverName()
|
|
||||||
|
|
||||||
assert.Equal(t, "virtualbox", driverName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSSHHostname(t *testing.T) {
|
|
||||||
hostname, err := newTestDriver("default").GetSSHHostname()
|
|
||||||
|
|
||||||
assert.Equal(t, "127.0.0.1", hostname)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDefaultSSHUsername(t *testing.T) {
|
|
||||||
username := newTestDriver("default").GetSSHUsername()
|
|
||||||
|
|
||||||
assert.Equal(t, "docker", username)
|
|
||||||
}
|
|
||||||
|
|
||||||
type VBoxManagerMock struct {
|
type VBoxManagerMock struct {
|
||||||
args string
|
args string
|
||||||
stdOut string
|
stdOut string
|
||||||
|
@ -54,6 +39,29 @@ func (v *VBoxManagerMock) vbmOutErr(args ...string) (string, string, error) {
|
||||||
return "", "", errors.New("Invalid args")
|
return "", "", errors.New("Invalid args")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newTestDriver(name string) *Driver {
|
||||||
|
return NewDriver(name, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDriverName(t *testing.T) {
|
||||||
|
driverName := newTestDriver("default").DriverName()
|
||||||
|
|
||||||
|
assert.Equal(t, "virtualbox", driverName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSSHHostname(t *testing.T) {
|
||||||
|
hostname, err := newTestDriver("default").GetSSHHostname()
|
||||||
|
|
||||||
|
assert.Equal(t, "127.0.0.1", hostname)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefaultSSHUsername(t *testing.T) {
|
||||||
|
username := newTestDriver("default").GetSSHUsername()
|
||||||
|
|
||||||
|
assert.Equal(t, "docker", username)
|
||||||
|
}
|
||||||
|
|
||||||
func TestState(t *testing.T) {
|
func TestState(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
stdOut string
|
stdOut string
|
||||||
|
@ -108,9 +116,11 @@ func TestStateErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetRandomIPinSubnet(t *testing.T) {
|
func TestGetRandomIPinSubnet(t *testing.T) {
|
||||||
|
driver := newTestDriver("default")
|
||||||
|
|
||||||
// test IP 1.2.3.4
|
// test IP 1.2.3.4
|
||||||
testIP := net.IPv4(byte(1), byte(2), byte(3), byte(4))
|
testIP := net.IPv4(byte(1), byte(2), byte(3), byte(4))
|
||||||
newIP, err := getRandomIPinSubnet(testIP)
|
newIP, err := getRandomIPinSubnet(driver, testIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -187,12 +197,8 @@ func TestInvalidNetworkIpCIDR(t *testing.T) {
|
||||||
assert.Nil(t, network)
|
assert.Nil(t, network)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestDriver(name string) *Driver {
|
|
||||||
return NewDriver(name, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetConfigFromFlags(t *testing.T) {
|
func TestSetConfigFromFlags(t *testing.T) {
|
||||||
driver := NewDriver("default", "path")
|
driver := newTestDriver("default")
|
||||||
|
|
||||||
checkFlags := &drivers.CheckDriverOptions{
|
checkFlags := &drivers.CheckDriverOptions{
|
||||||
FlagsValues: map[string]interface{}{},
|
FlagsValues: map[string]interface{}{},
|
||||||
|
@ -204,3 +210,271 @@ func TestSetConfigFromFlags(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Empty(t, checkFlags.InvalidFlags)
|
assert.Empty(t, checkFlags.InvalidFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MockCreateOperations struct {
|
||||||
|
test *testing.T
|
||||||
|
expectedCalls []Call
|
||||||
|
call int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Call struct {
|
||||||
|
signature string
|
||||||
|
output string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) vbm(args ...string) error {
|
||||||
|
_, _, err := v.vbmOutErr(args...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) vbmOut(args ...string) (string, error) {
|
||||||
|
stdout, _, err := v.vbmOutErr(args...)
|
||||||
|
return stdout, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) vbmOutErr(args ...string) (string, string, error) {
|
||||||
|
output, err := v.doCall("vbm " + strings.Join(args, " "))
|
||||||
|
return output, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) UpdateISOCache(storePath, isoURL string) error {
|
||||||
|
_, err := v.doCall("UpdateISOCache " + storePath + " " + isoURL)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) CopyIsoToMachineDir(storePath, machineName, isoURL string) error {
|
||||||
|
_, err := v.doCall("CopyIsoToMachineDir " + storePath + " " + machineName + " " + isoURL)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) Generate(path string) error {
|
||||||
|
_, err := v.doCall("Generate " + path)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) Create(size int, publicSSHKeyPath, diskPath string) error {
|
||||||
|
_, err := v.doCall("Create " + fmt.Sprintf("%d %s %s", size, publicSSHKeyPath, diskPath))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) Read(path string) ([]string, error) {
|
||||||
|
_, err := v.doCall("Read " + path)
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) Wait(d *Driver) error {
|
||||||
|
_, err := v.doCall("WaitIP")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) RandomInt(n int) int {
|
||||||
|
return 6
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) Sleep(d time.Duration) {
|
||||||
|
v.doCall("Sleep " + fmt.Sprintf("%v", d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) expectCall(callSignature, output string, err error) {
|
||||||
|
v.expectedCalls = append(v.expectedCalls, Call{
|
||||||
|
signature: callSignature,
|
||||||
|
output: output,
|
||||||
|
err: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MockCreateOperations) doCall(callSignature string) (string, error) {
|
||||||
|
if v.call >= len(v.expectedCalls) {
|
||||||
|
v.test.Fatal("Unexpected call", callSignature)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
call := v.expectedCalls[v.call]
|
||||||
|
if call.signature != "IGNORE CALL" && (callSignature != call.signature) {
|
||||||
|
v.test.Fatal("Unexpected call", callSignature)
|
||||||
|
}
|
||||||
|
|
||||||
|
v.call++
|
||||||
|
|
||||||
|
return call.output, call.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateVM(t *testing.T) {
|
||||||
|
shareName, shareDir := getShareDriveAndName()
|
||||||
|
|
||||||
|
operations := &MockCreateOperations{
|
||||||
|
test: t,
|
||||||
|
expectedCalls: []Call{
|
||||||
|
{"CopyIsoToMachineDir path default http://b2d.org", "", nil},
|
||||||
|
{"Generate path/machines/default/id_rsa", "", nil},
|
||||||
|
{"Create 20000 path/machines/default/id_rsa.pub path/machines/default/disk.vmdk", "", nil},
|
||||||
|
{"vbm createvm --basefolder path/machines/default --name default --register", "", nil},
|
||||||
|
{"vbm modifyvm default --firmware bios --bioslogofadein off --bioslogofadeout off --bioslogodisplaytime 0 --biosbootmenu disabled --ostype Linux26_64 --cpus 1 --memory 1024 --acpi on --ioapic on --rtcuseutc on --natdnshostresolver1 off --natdnsproxy1 off --cpuhotplug off --pae on --hpet on --hwvirtex on --nestedpaging on --largepages on --vtxvpid on --accelerate3d off --boot1 dvd", "", nil},
|
||||||
|
{"vbm modifyvm default --nic1 nat --nictype1 82540EM --cableconnected1 on", "", nil},
|
||||||
|
{"vbm storagectl default --name SATA --add sata --hostiocache on", "", nil},
|
||||||
|
{"vbm storageattach default --storagectl SATA --port 0 --device 0 --type dvddrive --medium path/machines/default/boot2docker.iso", "", nil},
|
||||||
|
{"vbm storageattach default --storagectl SATA --port 1 --device 0 --type hdd --medium path/machines/default/disk.vmdk", "", nil},
|
||||||
|
{"vbm guestproperty set default /VirtualBox/GuestAdd/SharedFolders/MountPrefix /", "", nil},
|
||||||
|
{"vbm guestproperty set default /VirtualBox/GuestAdd/SharedFolders/MountDir /", "", nil},
|
||||||
|
{"vbm sharedfolder add default --name " + shareName + " --hostpath " + shareDir + " --automount", "", nil},
|
||||||
|
{"vbm setextradata default VBoxInternal2/SharedFoldersEnableSymlinksCreate/" + shareName + " 1", "", nil},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
driver := NewDriver("default", "path")
|
||||||
|
driver.Boot2DockerURL = "http://b2d.org"
|
||||||
|
driver.VBoxManager = operations
|
||||||
|
driver.b2dUpdater = operations
|
||||||
|
driver.sshKeyGenerator = operations
|
||||||
|
driver.diskCreator = operations
|
||||||
|
driver.logsReader = operations
|
||||||
|
driver.ipWaiter = operations
|
||||||
|
driver.randomInter = operations
|
||||||
|
driver.sleeper = operations
|
||||||
|
|
||||||
|
err := driver.CreateVM()
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStart(t *testing.T) {
|
||||||
|
operations := &MockCreateOperations{
|
||||||
|
test: t,
|
||||||
|
expectedCalls: []Call{
|
||||||
|
{"vbm showvminfo default --machinereadable", `VMState="poweroff"`, nil},
|
||||||
|
{"vbm list hostonlyifs", "", nil},
|
||||||
|
{"vbm hostonlyif create", "Interface 'VirtualBox Host-Only Ethernet Adapter' was successfully created", nil},
|
||||||
|
{"vbm hostonlyif ipconfig VirtualBox Host-Only Ethernet Adapter --ip 192.168.99.1 --netmask 255.255.255.0", "", nil},
|
||||||
|
{"vbm list hostonlyifs", `
|
||||||
|
Name: VirtualBox Host-Only Ethernet Adapter
|
||||||
|
GUID: 786f6276-656e-4074-8000-0a0027000000
|
||||||
|
DHCP: Disabled
|
||||||
|
IPAddress: 192.168.99.1
|
||||||
|
NetworkMask: 255.255.255.0
|
||||||
|
IPV6Address:
|
||||||
|
IPV6NetworkMaskPrefixLength: 0
|
||||||
|
HardwareAddress: 0a:00:27:00:00:00
|
||||||
|
MediumType: Ethernet
|
||||||
|
Status: Up
|
||||||
|
VBoxNetworkName: HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter`, nil},
|
||||||
|
{"vbm list dhcpservers", "", nil},
|
||||||
|
{"vbm list dhcpservers", "", nil},
|
||||||
|
{"vbm dhcpserver add --netname HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter --ip 192.168.99.6 --netmask 255.255.255.0 --lowerip 192.168.99.100 --upperip 192.168.99.254 --enable", "", nil},
|
||||||
|
{"vbm modifyvm default --nic2 hostonly --nictype2 82540EM --nicpromisc2 deny --hostonlyadapter2 VirtualBox Host-Only Ethernet Adapter --cableconnected2 on", "", nil},
|
||||||
|
{"IGNORE CALL", "", nil},
|
||||||
|
{"IGNORE CALL", "", nil},
|
||||||
|
{"vbm startvm default --type headless", "", nil},
|
||||||
|
{"Read path/machines/default/default/Logs/VBox.log", "", nil},
|
||||||
|
{"WaitIP", "", nil},
|
||||||
|
{"vbm list hostonlyifs", `
|
||||||
|
Name: VirtualBox Host-Only Ethernet Adapter
|
||||||
|
GUID: 786f6276-656e-4074-8000-0a0027000000
|
||||||
|
DHCP: Disabled
|
||||||
|
IPAddress: 192.168.99.1
|
||||||
|
NetworkMask: 255.255.255.0
|
||||||
|
IPV6Address:
|
||||||
|
IPV6NetworkMaskPrefixLength: 0
|
||||||
|
HardwareAddress: 0a:00:27:00:00:00
|
||||||
|
MediumType: Ethernet
|
||||||
|
Status: Up
|
||||||
|
VBoxNetworkName: HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter`, nil},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
driver := NewDriver("default", "path")
|
||||||
|
driver.Boot2DockerURL = "http://b2d.org"
|
||||||
|
driver.VBoxManager = operations
|
||||||
|
driver.b2dUpdater = operations
|
||||||
|
driver.sshKeyGenerator = operations
|
||||||
|
driver.diskCreator = operations
|
||||||
|
driver.logsReader = operations
|
||||||
|
driver.ipWaiter = operations
|
||||||
|
driver.randomInter = operations
|
||||||
|
driver.sleeper = operations
|
||||||
|
|
||||||
|
err := driver.Start()
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStartWithHostOnlyAdapterCreationBug(t *testing.T) {
|
||||||
|
operations := &MockCreateOperations{
|
||||||
|
test: t,
|
||||||
|
expectedCalls: []Call{
|
||||||
|
{"vbm showvminfo default --machinereadable", `VMState="poweroff"`, nil},
|
||||||
|
{"vbm list hostonlyifs", "", nil},
|
||||||
|
{"vbm hostonlyif create", "", errors.New("error: Failed to create the host-only adapter")},
|
||||||
|
{"vbm list hostonlyifs", "", nil},
|
||||||
|
{"vbm list hostonlyifs", `
|
||||||
|
Name: VirtualBox Host-Only Ethernet Adapter
|
||||||
|
GUID: 786f6276-656e-4074-8000-0a0027000000
|
||||||
|
DHCP: Disabled
|
||||||
|
IPAddress: 192.168.99.1
|
||||||
|
NetworkMask: 255.255.255.0
|
||||||
|
IPV6Address:
|
||||||
|
IPV6NetworkMaskPrefixLength: 0
|
||||||
|
HardwareAddress: 0a:00:27:00:00:00
|
||||||
|
MediumType: Ethernet
|
||||||
|
Status: Up
|
||||||
|
VBoxNetworkName: HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter`, nil},
|
||||||
|
{"vbm hostonlyif ipconfig VirtualBox Host-Only Ethernet Adapter --ip 192.168.99.1 --netmask 255.255.255.0", "", nil},
|
||||||
|
{"vbm list hostonlyifs", `
|
||||||
|
Name: VirtualBox Host-Only Ethernet Adapter
|
||||||
|
GUID: 786f6276-656e-4074-8000-0a0027000000
|
||||||
|
DHCP: Disabled
|
||||||
|
IPAddress: 192.168.99.1
|
||||||
|
NetworkMask: 255.255.255.0
|
||||||
|
IPV6Address:
|
||||||
|
IPV6NetworkMaskPrefixLength: 0
|
||||||
|
HardwareAddress: 0a:00:27:00:00:00
|
||||||
|
MediumType: Ethernet
|
||||||
|
Status: Up
|
||||||
|
VBoxNetworkName: HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter`, nil},
|
||||||
|
{"vbm list dhcpservers", "", nil},
|
||||||
|
{"vbm list dhcpservers", "", nil},
|
||||||
|
{"vbm dhcpserver add --netname HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter --ip 192.168.99.6 --netmask 255.255.255.0 --lowerip 192.168.99.100 --upperip 192.168.99.254 --enable", "", nil},
|
||||||
|
{"vbm modifyvm default --nic2 hostonly --nictype2 82540EM --nicpromisc2 deny --hostonlyadapter2 VirtualBox Host-Only Ethernet Adapter --cableconnected2 on", "", nil},
|
||||||
|
{"IGNORE CALL", "", nil},
|
||||||
|
{"IGNORE CALL", "", nil},
|
||||||
|
{"vbm startvm default --type headless", "", nil},
|
||||||
|
{"Read path/machines/default/default/Logs/VBox.log", "", nil},
|
||||||
|
{"WaitIP", "", nil},
|
||||||
|
{"vbm list hostonlyifs", `
|
||||||
|
Name: VirtualBox Host-Only Ethernet Adapter
|
||||||
|
GUID: 786f6276-656e-4074-8000-0a0027000000
|
||||||
|
DHCP: Disabled
|
||||||
|
IPAddress: 192.168.99.100
|
||||||
|
NetworkMask: 255.255.255.0
|
||||||
|
IPV6Address:
|
||||||
|
IPV6NetworkMaskPrefixLength: 0
|
||||||
|
HardwareAddress: 0a:00:27:00:00:00
|
||||||
|
MediumType: Ethernet
|
||||||
|
Status: Up
|
||||||
|
VBoxNetworkName: HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter`, nil},
|
||||||
|
{"vbm showvminfo default --machinereadable", `VMState="running"`, nil},
|
||||||
|
{"vbm controlvm default acpipowerbutton", "", nil},
|
||||||
|
{"vbm showvminfo default --machinereadable", `VMState="stopped"`, nil},
|
||||||
|
{"Sleep 5s", "", nil},
|
||||||
|
{"vbm hostonlyif ipconfig VirtualBox Host-Only Ethernet Adapter --ip 192.168.99.1 --netmask 255.255.255.0", "", nil},
|
||||||
|
{"Sleep 5s", "", nil},
|
||||||
|
{"vbm startvm default --type headless", "", nil},
|
||||||
|
{"WaitIP", "", nil},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
driver := NewDriver("default", "path")
|
||||||
|
driver.Boot2DockerURL = "http://b2d.org"
|
||||||
|
driver.VBoxManager = operations
|
||||||
|
driver.b2dUpdater = operations
|
||||||
|
driver.sshKeyGenerator = operations
|
||||||
|
driver.diskCreator = operations
|
||||||
|
driver.logsReader = operations
|
||||||
|
driver.ipWaiter = operations
|
||||||
|
driver.randomInter = operations
|
||||||
|
driver.sleeper = operations
|
||||||
|
|
||||||
|
err := driver.Start()
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue