This repository has been archived by the owner on Sep 12, 2024. It is now read-only.
forked from docker/machine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
disk.go
141 lines (111 loc) · 2.86 KB
/
disk.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package virtualbox
import (
"fmt"
"io"
"os"
"os/exec"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
)
type VirtualDisk struct {
UUID 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) {
out, err := vbox.vbmOut("showvminfo", name, "--machinereadable")
if err != nil {
return nil, err
}
disk := &VirtualDisk{}
err = parseKeyValues(out, reEqualQuoteLine, func(key, val string) error {
switch key {
case "SATA-1-0":
disk.Path = val
case "SATA-ImageUUID-1-0":
disk.UUID = val
}
return nil
})
if err != nil {
return nil, err
}
return disk, nil
}