Skip to content

Commit c77ffa3

Browse files
committed
Merge pull request docker-archive-public#2806 from dgageot/unit-test-vb
Test VirtualBox VM creation
2 parents 26d0187 + ea9bbcb commit c77ffa3

File tree

5 files changed

+600
-168
lines changed

5 files changed

+600
-168
lines changed

drivers/virtualbox/disk.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,120 @@
11
package virtualbox
22

3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
"os/exec"
8+
9+
"github.com/docker/machine/libmachine/log"
10+
"github.com/docker/machine/libmachine/mcnutils"
11+
)
12+
313
type VirtualDisk struct {
414
UUID string
515
Path string
616
}
717

18+
type DiskCreator interface {
19+
Create(size int, publicSSHKeyPath, diskPath string) error
20+
}
21+
22+
func NewDiskCreator() DiskCreator {
23+
return &defaultDiskCreator{}
24+
}
25+
26+
type defaultDiskCreator struct{}
27+
28+
// Make a boot2docker VM disk image.
29+
func (c *defaultDiskCreator) Create(size int, publicSSHKeyPath, diskPath string) error {
30+
log.Debugf("Creating %d MB hard disk image...", size)
31+
32+
tarBuf, err := mcnutils.MakeDiskImage(publicSSHKeyPath)
33+
if err != nil {
34+
return err
35+
}
36+
37+
log.Debug("Calling inner createDiskImage")
38+
39+
return createDiskImage(diskPath, size, tarBuf)
40+
}
41+
42+
// createDiskImage makes a disk image at dest with the given size in MB. If r is
43+
// not nil, it will be read as a raw disk image to convert from.
44+
func createDiskImage(dest string, size int, r io.Reader) error {
45+
// Convert a raw image from stdin to the dest VMDK image.
46+
sizeBytes := int64(size) << 20 // usually won't fit in 32-bit int (max 2GB)
47+
// FIXME: why isn't this just using the vbm*() functions?
48+
cmd := exec.Command(vboxManageCmd, "convertfromraw", "stdin", dest,
49+
fmt.Sprintf("%d", sizeBytes), "--format", "VMDK")
50+
51+
log.Debug(cmd)
52+
53+
if os.Getenv("MACHINE_DEBUG") != "" {
54+
cmd.Stdout = os.Stdout
55+
cmd.Stderr = os.Stderr
56+
}
57+
58+
stdin, err := cmd.StdinPipe()
59+
if err != nil {
60+
return err
61+
}
62+
63+
log.Debug("Starting command")
64+
65+
if err := cmd.Start(); err != nil {
66+
return err
67+
}
68+
69+
log.Debug("Copying to stdin")
70+
71+
n, err := io.Copy(stdin, r)
72+
if err != nil {
73+
return err
74+
}
75+
76+
log.Debug("Filling zeroes")
77+
78+
// The total number of bytes written to stdin must match sizeBytes, or
79+
// VBoxManage.exe on Windows will fail. Fill remaining with zeros.
80+
if left := sizeBytes - n; left > 0 {
81+
if err := zeroFill(stdin, left); err != nil {
82+
return err
83+
}
84+
}
85+
86+
log.Debug("Closing STDIN")
87+
88+
// cmd won't exit until the stdin is closed.
89+
if err := stdin.Close(); err != nil {
90+
return err
91+
}
92+
93+
log.Debug("Waiting on cmd")
94+
95+
return cmd.Wait()
96+
}
97+
98+
// zeroFill writes n zero bytes into w.
99+
func zeroFill(w io.Writer, n int64) error {
100+
const blocksize = 32 << 10
101+
zeros := make([]byte, blocksize)
102+
var k int
103+
var err error
104+
for n > 0 {
105+
if n > blocksize {
106+
k, err = w.Write(zeros)
107+
} else {
108+
k, err = w.Write(zeros[:n])
109+
}
110+
if err != nil {
111+
return err
112+
}
113+
n -= int64(k)
114+
}
115+
return nil
116+
}
117+
8118
func getVMDiskInfo(name string, vbox VBoxManager) (*VirtualDisk, error) {
9119
out, err := vbox.vbmOut("showvminfo", name, "--machinereadable")
10120
if err != nil {

drivers/virtualbox/ip.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package virtualbox
2+
3+
import (
4+
"time"
5+
6+
"github.com/docker/machine/libmachine/drivers"
7+
"github.com/docker/machine/libmachine/mcnutils"
8+
)
9+
10+
// IPWaiter waits for an IP to be configured.
11+
type IPWaiter interface {
12+
Wait(d *Driver) error
13+
}
14+
15+
func NewIPWaiter() IPWaiter {
16+
return &sshIPWaiter{}
17+
}
18+
19+
type sshIPWaiter struct{}
20+
21+
func (w *sshIPWaiter) Wait(d *Driver) error {
22+
// Wait for SSH over NAT to be available before returning to user
23+
if err := drivers.WaitForSSH(d); err != nil {
24+
return err
25+
}
26+
27+
// Bail if we don't get an IP from DHCP after a given number of seconds.
28+
if err := mcnutils.WaitForSpecific(d.hostOnlyIPAvailable, 5, 4*time.Second); err != nil {
29+
return err
30+
}
31+
32+
var err error
33+
d.IPAddress, err = d.GetIP()
34+
35+
return err
36+
}

drivers/virtualbox/misc.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package virtualbox
2+
3+
import (
4+
"bufio"
5+
"math/rand"
6+
"os"
7+
8+
"time"
9+
10+
"github.com/docker/machine/libmachine/mcnutils"
11+
"github.com/docker/machine/libmachine/ssh"
12+
)
13+
14+
// B2DUpdater describes the interactions with bd2.
15+
type B2DUpdater interface {
16+
UpdateISOCache(storePath, isoURL string) error
17+
CopyIsoToMachineDir(storePath, machineName, isoURL string) error
18+
}
19+
20+
func NewB2DUpdater() B2DUpdater {
21+
return &b2dUtilsUpdater{}
22+
}
23+
24+
type b2dUtilsUpdater struct{}
25+
26+
func (u *b2dUtilsUpdater) CopyIsoToMachineDir(storePath, machineName, isoURL string) error {
27+
return mcnutils.NewB2dUtils(storePath).CopyIsoToMachineDir(isoURL, machineName)
28+
}
29+
30+
func (u *b2dUtilsUpdater) UpdateISOCache(storePath, isoURL string) error {
31+
return mcnutils.NewB2dUtils(storePath).UpdateISOCache(isoURL)
32+
}
33+
34+
// SSHKeyGenerator describes the generation of ssh keys.
35+
type SSHKeyGenerator interface {
36+
Generate(path string) error
37+
}
38+
39+
func NewSSHKeyGenerator() SSHKeyGenerator {
40+
return &defaultSSHKeyGenerator{}
41+
}
42+
43+
type defaultSSHKeyGenerator struct{}
44+
45+
func (g *defaultSSHKeyGenerator) Generate(path string) error {
46+
return ssh.GenerateSSHKey(path)
47+
}
48+
49+
// LogsReader describes the reading of VBox.log
50+
type LogsReader interface {
51+
Read(path string) ([]string, error)
52+
}
53+
54+
func NewLogsReader() LogsReader {
55+
return &vBoxLogsReader{}
56+
}
57+
58+
type vBoxLogsReader struct{}
59+
60+
func (c *vBoxLogsReader) Read(path string) ([]string, error) {
61+
file, err := os.Open(path)
62+
if err != nil {
63+
return []string{}, err
64+
}
65+
66+
defer file.Close()
67+
68+
lines := []string{}
69+
70+
scanner := bufio.NewScanner(file)
71+
for scanner.Scan() {
72+
lines = append(lines, scanner.Text())
73+
}
74+
75+
return lines, nil
76+
}
77+
78+
// RandomInter returns random int values.
79+
type RandomInter interface {
80+
RandomInt(n int) int
81+
}
82+
83+
func NewRandomInter() RandomInter {
84+
return &defaultRandomInter{}
85+
}
86+
87+
type defaultRandomInter struct{}
88+
89+
func (d *defaultRandomInter) RandomInt(n int) int {
90+
return rand.Intn(n)
91+
}
92+
93+
// Sleeper sleeps for given duration.
94+
type Sleeper interface {
95+
Sleep(d time.Duration)
96+
}
97+
98+
func NewSleeper() Sleeper {
99+
return &defaultSleeper{}
100+
}
101+
102+
type defaultSleeper struct{}
103+
104+
func (s *defaultSleeper) Sleep(d time.Duration) {
105+
time.Sleep(d)
106+
}

0 commit comments

Comments
 (0)