forked from linuxkit/linuxkit
/
run_vmware.go
245 lines (215 loc) · 6.67 KB
/
run_vmware.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
package main
import (
"flag"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
log "github.com/Sirupsen/logrus"
)
//Version 12 relates to Fusion 8 and WS 12
//virtualHW.version = "12"
const vmxHW string = `config.version = "8"
virtualHW.version = "12"
vmci0.present = "TRUE"
floppy0.present = "FALSE"
displayName = "%s"
numvcpus = "%d"
memsize = "%d"
scsi0.present = "TRUE"
scsi0.sharedBus = "none"
scsi0.virtualDev = "lsilogic"
`
const vmxDisk string = `
scsi0:0.present = "TRUE"
scsi0:0.fileName = "%s"
scsi0:0.deviceType = "scsi-hardDisk"
`
const vmxDiskPersistent string = `scsi0:1.present = "TRUE"
scsi0:1.fileName = "%s"
scsi0:1.deviceType = "scsi-hardDisk"
`
const vmxCdrom string = `ide1:0.present = "TRUE"
ide1:0.fileName = "%s"
ide1:0.deviceType = "cdrom-image"
`
const vmxPCI string = `pciBridge0.present = "TRUE"
pciBridge4.present = "TRUE"
pciBridge4.virtualDev = "pcieRootPort"
pciBridge4.functions = "8"
pciBridge5.present = "TRUE"
pciBridge5.virtualDev = "pcieRootPort"
pciBridge5.functions = "8"
pciBridge6.present = "TRUE"
pciBridge6.virtualDev = "pcieRootPort"
pciBridge6.functions = "8"
pciBridge7.present = "TRUE"
pciBridge7.virtualDev = "pcieRootPort"
pciBridge7.functions = "8"
ethernet0.pciSlotNumber = "32"
ethernet0.present = "TRUE"
ethernet0.virtualDev = "e1000"
ethernet0.networkName = "Inside"
ethernet0.generatedAddressOffset = "0"
guestOS = "other3xlinux-64"
`
func runVMware(args []string) {
invoked := filepath.Base(os.Args[0])
flags := flag.NewFlagSet("vmware", flag.ExitOnError)
flags.Usage = func() {
fmt.Printf("USAGE: %s run vmware [options] prefix\n\n", invoked)
fmt.Printf("'prefix' specifies the path to the VM image.\n")
fmt.Printf("\n")
fmt.Printf("Options:\n")
flags.PrintDefaults()
}
cpus := flags.Int("cpus", 1, "Number of CPUs")
mem := flags.Int("mem", 1024, "Amount of memory in MB")
var disks Disks
flags.Var(&disks, "disk", "Disk config. [file=]path[,size=1G]")
state := flags.String("state", "", "Path to directory to keep VM state in")
if err := flags.Parse(args); err != nil {
log.Fatal("Unable to parse args")
}
remArgs := flags.Args()
if len(remArgs) == 0 {
fmt.Println("Please specify the prefix to the image to boot")
flags.Usage()
os.Exit(1)
}
prefix := remArgs[0]
if *state == "" {
*state = prefix + "-state"
}
if err := os.MkdirAll(*state, 0755); err != nil {
log.Fatalf("Could not create state directory: %v", err)
}
var vmrunPath, vmDiskManagerPath string
var vmrunArgs []string
switch runtime.GOOS {
case "windows":
vmrunPath = "C:\\Program\\ files\\VMware Workstation\\vmrun.exe"
vmDiskManagerPath = "C:\\Program\\ files\\VMware Workstation\\vmware-vdiskmanager.exe"
vmrunArgs = []string{"-T", "ws", "start"}
case "darwin":
vmrunPath = "/Applications/VMware Fusion.app/Contents/Library/vmrun"
vmDiskManagerPath = "/Applications/VMware Fusion.app/Contents/Library/vmware-vdiskmanager"
vmrunArgs = []string{"-T", "fusion", "start"}
default:
vmrunPath = "vmrun"
vmDiskManagerPath = "vmware-vdiskmanager"
fullVMrunPath, err := exec.LookPath(vmrunPath)
if err != nil {
// Kept as separate error as people may manually change their environment vars
log.Fatalf("Unable to find %s within the $PATH", vmrunPath)
}
vmrunPath = fullVMrunPath
vmrunArgs = []string{"-T", "ws", "start"}
}
// Check vmrunPath exists before attempting to execute
if _, err := os.Stat(vmrunPath); os.IsNotExist(err) {
log.Fatalf("ERROR VMware executables can not be found, ensure software is installed")
}
for i, d := range disks {
id := ""
if i != 0 {
id = strconv.Itoa(i)
}
if d.Size != 0 && d.Path == "" {
d.Path = filepath.Join(*state, "disk"+id+".vmdk")
}
if d.Format != "" && d.Format != "vmdk" {
log.Fatalf("only vmdk supported for VMware driver")
}
if d.Path == "" {
log.Fatalf("disk specified with no size or name")
}
disks[i] = d
}
for _, d := range disks {
// Check vmDiskManagerPath exist before attempting to execute
if _, err := os.Stat(vmDiskManagerPath); os.IsNotExist(err) {
log.Fatalf("ERROR VMware Disk Manager executables can not be found, ensure software is installed")
}
// If disk doesn't exist then create one, error if disk is unreadable
if _, err := os.Stat(d.Path); err != nil {
if os.IsPermission(err) {
log.Fatalf("Unable to read file [%s], please check permissions", d.Path)
} else if os.IsNotExist(err) {
log.Infof("Creating new VMware disk [%s]", d.Path)
vmDiskCmd := exec.Command(vmDiskManagerPath, "-c", "-s", fmt.Sprintf("%dMB", d.Size), "-a", "lsilogic", "-t", "0", d.Path)
if err = vmDiskCmd.Run(); err != nil {
log.Fatalf("Error creating disk [%s]: %v", d.Path, err)
}
} else {
log.Fatalf("Unable to read file [%s]: %v", d.Path, err)
}
} else {
log.Infof("Using existing disk [%s]", d.Path)
}
}
if len(disks) > 1 {
log.Fatalf("VMware driver currently only supports a single disk")
}
disk := ""
if len(disks) == 1 {
disk = disks[0].Path
}
// Build the contents of the VMWare .vmx file
vmx := buildVMX(*cpus, *mem, disk, prefix)
if vmx == "" {
log.Fatalf("VMware .vmx file could not be generated, please confirm inputs")
}
// Create the .vmx file
vmxPath := filepath.Join(*state, "linuxkit.vmx")
err := ioutil.WriteFile(vmxPath, []byte(vmx), 0644)
if err != nil {
log.Fatalf("Error writing .vmx file: %v", err)
}
vmrunArgs = append(vmrunArgs, vmxPath)
cmd := exec.Command(vmrunPath, vmrunArgs...)
out, err := cmd.Output()
if err != nil {
log.Fatalf("Error starting vmrun: %v", err)
}
// check there is output to push to logging
if len(out) > 0 {
log.Info(out)
}
}
func buildVMX(cpus int, mem int, persistentDisk string, prefix string) string {
// CD-ROM can be added for use in a further release
cdromPath := ""
var returnString string
returnString += fmt.Sprintf(vmxHW, prefix, cpus, mem)
if cdromPath != "" {
returnString += fmt.Sprintf(vmxCdrom, cdromPath)
}
vmdkPath, err := filepath.Abs(prefix + ".vmdk")
if err != nil {
log.Fatalf("Unable get absolute path for boot vmdk: %v", err)
}
if _, err := os.Stat(vmdkPath); err != nil {
if os.IsPermission(err) {
log.Fatalf("Unable to read file [%s], please check permissions", vmdkPath)
}
if os.IsNotExist(err) {
log.Fatalf("File [%s] does not exist in current directory", vmdkPath)
}
} else {
returnString += fmt.Sprintf(vmxDisk, vmdkPath)
}
// Add persistentDisk to the vmx if it has been specified in the args.
if persistentDisk != "" {
persistentDisk, err = filepath.Abs(persistentDisk)
if err != nil {
log.Fatalf("Unable get absolute path for persistent disk: %v", err)
}
returnString += fmt.Sprintf(vmxDiskPersistent, persistentDisk)
}
returnString += vmxPCI
return returnString
}