github.phpd.cn/hashicorp/packer@v1.3.2/builder/vmware/iso/step_create_vmx_test.go (about) 1 package iso 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "math" 8 "math/rand" 9 "os" 10 "path/filepath" 11 "runtime" 12 "strconv" 13 "strings" 14 15 "testing" 16 17 "github.com/hashicorp/packer/packer" 18 "github.com/hashicorp/packer/provisioner/shell" 19 "github.com/hashicorp/packer/template" 20 ) 21 22 var vmxTestBuilderConfig = map[string]string{ 23 "type": `"vmware-iso"`, 24 "iso_url": `"https://archive.org/download/ut-ttylinux-i686-12.6/ut-ttylinux-i686-12.6.iso"`, 25 "iso_checksum_type": `"md5"`, 26 "iso_checksum": `"43c1feeae55a44c6ef694b8eb18408a6"`, 27 "ssh_username": `"root"`, 28 "ssh_password": `"password"`, 29 "ssh_wait_timeout": `"45s"`, 30 "boot_command": `["<enter><wait5><wait10>","root<enter><wait>password<enter><wait>","udhcpc<enter><wait>"]`, 31 "shutdown_command": `"/sbin/shutdown -h; exit 0"`, 32 } 33 34 var vmxTestProvisionerConfig = map[string]string{ 35 "type": `"shell"`, 36 "inline": `["echo hola mundo"]`, 37 } 38 39 const vmxTestTemplate string = `{"builders":[{%s}],"provisioners":[{%s}]}` 40 41 func tmpnam(prefix string) string { 42 var path string 43 var err error 44 45 const length = 16 46 47 dir := os.TempDir() 48 max := int(math.Pow(2, float64(length))) 49 50 n, err := rand.Intn(max), nil 51 for path = filepath.Join(dir, prefix+strconv.Itoa(n)); err == nil; _, err = os.Stat(path) { 52 n = rand.Intn(max) 53 path = filepath.Join(dir, prefix+strconv.Itoa(n)) 54 } 55 return path 56 } 57 58 func createFloppyOutput(prefix string) (string, string, error) { 59 output := tmpnam(prefix) 60 f, err := os.Create(output) 61 if err != nil { 62 return "", "", fmt.Errorf("Unable to create empty %s: %s", output, err) 63 } 64 f.Close() 65 66 vmxData := []string{ 67 `"floppy0.present":"TRUE"`, 68 `"floppy0.fileType":"file"`, 69 `"floppy0.clientDevice":"FALSE"`, 70 `"floppy0.fileName":"%s"`, 71 `"floppy0.startConnected":"TRUE"`, 72 } 73 74 outputFile := strings.Replace(output, "\\", "\\\\", -1) 75 vmxString := fmt.Sprintf("{"+strings.Join(vmxData, ",")+"}", outputFile) 76 return output, vmxString, nil 77 } 78 79 func readFloppyOutput(path string) (string, error) { 80 f, err := os.Open(path) 81 if err != nil { 82 return "", fmt.Errorf("Unable to open file %s", path) 83 } 84 defer f.Close() 85 data, err := ioutil.ReadAll(f) 86 if err != nil { 87 return "", fmt.Errorf("Unable to read file: %s", err) 88 } 89 if len(data) == 0 { 90 return "", nil 91 } 92 return string(data[:bytes.IndexByte(data, 0)]), nil 93 } 94 95 func setupVMwareBuild(t *testing.T, builderConfig map[string]string, provisionerConfig map[string]string) error { 96 ui := packer.TestUi(t) 97 98 // create builder config and update with user-supplied options 99 cfgBuilder := map[string]string{} 100 for k, v := range vmxTestBuilderConfig { 101 cfgBuilder[k] = v 102 } 103 for k, v := range builderConfig { 104 cfgBuilder[k] = v 105 } 106 107 // convert our builder config into a single sprintfable string 108 builderLines := []string{} 109 for k, v := range cfgBuilder { 110 builderLines = append(builderLines, fmt.Sprintf(`"%s":%s`, k, v)) 111 } 112 113 // create provisioner config and update with user-supplied options 114 cfgProvisioner := map[string]string{} 115 for k, v := range vmxTestProvisionerConfig { 116 cfgProvisioner[k] = v 117 } 118 for k, v := range provisionerConfig { 119 cfgProvisioner[k] = v 120 } 121 122 // convert our provisioner config into a single sprintfable string 123 provisionerLines := []string{} 124 for k, v := range cfgProvisioner { 125 provisionerLines = append(provisionerLines, fmt.Sprintf(`"%s":%s`, k, v)) 126 } 127 128 // and now parse them into a template 129 configString := fmt.Sprintf(vmxTestTemplate, strings.Join(builderLines, `,`), strings.Join(provisionerLines, `,`)) 130 131 tpl, err := template.Parse(strings.NewReader(configString)) 132 if err != nil { 133 t.Fatalf("Unable to parse test config: %s", err) 134 } 135 136 // create our config to test the vmware-iso builder 137 components := packer.ComponentFinder{ 138 Builder: func(n string) (packer.Builder, error) { 139 return &Builder{}, nil 140 }, 141 Hook: func(n string) (packer.Hook, error) { 142 return &packer.DispatchHook{}, nil 143 }, 144 PostProcessor: func(n string) (packer.PostProcessor, error) { 145 return &packer.MockPostProcessor{}, nil 146 }, 147 Provisioner: func(n string) (packer.Provisioner, error) { 148 return &shell.Provisioner{}, nil 149 }, 150 } 151 config := packer.CoreConfig{ 152 Template: tpl, 153 Components: components, 154 } 155 156 // create a core using our template 157 core, err := packer.NewCore(&config) 158 if err != nil { 159 t.Fatalf("Unable to create core: %s", err) 160 } 161 162 // now we can prepare our build 163 b, err := core.Build("vmware-iso") 164 if err != nil { 165 t.Fatalf("Unable to create build: %s", err) 166 } 167 168 warn, err := b.Prepare() 169 if len(warn) > 0 { 170 for _, w := range warn { 171 t.Logf("Configuration warning: %s", w) 172 } 173 } 174 175 // and then finally build it 176 cache := &packer.FileCache{CacheDir: os.TempDir()} 177 artifacts, err := b.Run(ui, cache) 178 if err != nil { 179 t.Fatalf("Failed to build artifact: %s", err) 180 } 181 182 // check to see that we only got one artifact back 183 if len(artifacts) == 1 { 184 return artifacts[0].Destroy() 185 } 186 187 // otherwise some number of errors happened 188 t.Logf("Unexpected number of artifacts returned: %d", len(artifacts)) 189 errors := make([]error, 0) 190 for _, artifact := range artifacts { 191 if err := artifact.Destroy(); err != nil { 192 errors = append(errors, err) 193 } 194 } 195 if len(errors) > 0 { 196 t.Errorf("%d Errors returned while trying to destroy artifacts", len(errors)) 197 return fmt.Errorf("Error while trying to destroy artifacts: %v", errors) 198 } 199 return nil 200 } 201 202 func TestStepCreateVmx_SerialFile(t *testing.T) { 203 if os.Getenv("PACKER_ACC") == "" { 204 t.Skip("This test is only run with PACKER_ACC=1 due to the requirement of access to the VMware binaries.") 205 } 206 207 tmpfile := tmpnam("SerialFileInput.") 208 209 serialConfig := map[string]string{ 210 "serial": fmt.Sprintf(`"file:%s"`, filepath.ToSlash(tmpfile)), 211 } 212 213 error := setupVMwareBuild(t, serialConfig, map[string]string{}) 214 if error != nil { 215 t.Errorf("Unable to read file: %s", error) 216 } 217 218 f, err := os.Stat(tmpfile) 219 if err != nil { 220 t.Errorf("VMware builder did not create a file for serial port: %s", err) 221 } 222 223 if f != nil { 224 if err := os.Remove(tmpfile); err != nil { 225 t.Fatalf("Unable to remove file %s: %s", tmpfile, err) 226 } 227 } 228 } 229 230 func TestStepCreateVmx_SerialPort(t *testing.T) { 231 if os.Getenv("PACKER_ACC") == "" { 232 t.Skip("This test is only run with PACKER_ACC=1 due to the requirement of access to the VMware binaries.") 233 } 234 235 var defaultSerial string 236 if runtime.GOOS == "windows" { 237 defaultSerial = "COM1" 238 } else { 239 defaultSerial = "/dev/ttyS0" 240 } 241 242 config := map[string]string{ 243 "serial": fmt.Sprintf(`"device:%s"`, filepath.ToSlash(defaultSerial)), 244 } 245 provision := map[string]string{ 246 "inline": `"dmesg | egrep -o '^serial8250: ttyS1 at' > /dev/fd0"`, 247 } 248 249 // where to write output 250 output, vmxData, err := createFloppyOutput("SerialPortOutput.") 251 if err != nil { 252 t.Fatalf("Error creating output: %s", err) 253 } 254 defer func() { 255 if _, err := os.Stat(output); err == nil { 256 os.Remove(output) 257 } 258 }() 259 config["vmx_data"] = vmxData 260 t.Logf("Preparing to write output to %s", output) 261 262 // whee 263 err = setupVMwareBuild(t, config, provision) 264 if err != nil { 265 t.Errorf("%s", err) 266 } 267 268 // check the output 269 data, err := readFloppyOutput(output) 270 if err != nil { 271 t.Errorf("%s", err) 272 } 273 274 if data != "serial8250: ttyS1 at\n" { 275 t.Errorf("Serial port not detected : %v", data) 276 } 277 } 278 279 func TestStepCreateVmx_ParallelPort(t *testing.T) { 280 if os.Getenv("PACKER_ACC") == "" { 281 t.Skip("This test is only run with PACKER_ACC=1 due to the requirement of access to the VMware binaries.") 282 } 283 284 var defaultParallel string 285 if runtime.GOOS == "windows" { 286 defaultParallel = "LPT1" 287 } else { 288 defaultParallel = "/dev/lp0" 289 } 290 291 config := map[string]string{ 292 "parallel": fmt.Sprintf(`"device:%s,uni"`, filepath.ToSlash(defaultParallel)), 293 } 294 provision := map[string]string{ 295 "inline": `"cat /proc/modules | egrep -o '^parport ' > /dev/fd0"`, 296 } 297 298 // where to write output 299 output, vmxData, err := createFloppyOutput("ParallelPortOutput.") 300 if err != nil { 301 t.Fatalf("Error creating output: %s", err) 302 } 303 defer func() { 304 if _, err := os.Stat(output); err == nil { 305 os.Remove(output) 306 } 307 }() 308 config["vmx_data"] = vmxData 309 t.Logf("Preparing to write output to %s", output) 310 311 // whee 312 error := setupVMwareBuild(t, config, provision) 313 if error != nil { 314 t.Errorf("%s", error) 315 } 316 317 // check the output 318 data, err := readFloppyOutput(output) 319 if err != nil { 320 t.Errorf("%s", err) 321 } 322 323 if data != "parport \n" { 324 t.Errorf("Parallel port not detected : %v", data) 325 } 326 } 327 328 func TestStepCreateVmx_Usb(t *testing.T) { 329 if os.Getenv("PACKER_ACC") == "" { 330 t.Skip("This test is only run with PACKER_ACC=1 due to the requirement of access to the VMware binaries.") 331 } 332 333 config := map[string]string{ 334 "usb": `"TRUE"`, 335 } 336 provision := map[string]string{ 337 "inline": `"dmesg | egrep -m1 -o 'USB hub found$' > /dev/fd0"`, 338 } 339 340 // where to write output 341 output, vmxData, err := createFloppyOutput("UsbOutput.") 342 if err != nil { 343 t.Fatalf("Error creating output: %s", err) 344 } 345 defer func() { 346 if _, err := os.Stat(output); err == nil { 347 os.Remove(output) 348 } 349 }() 350 config["vmx_data"] = vmxData 351 t.Logf("Preparing to write output to %s", output) 352 353 // whee 354 error := setupVMwareBuild(t, config, provision) 355 if error != nil { 356 t.Errorf("%s", error) 357 } 358 359 // check the output 360 data, err := readFloppyOutput(output) 361 if err != nil { 362 t.Errorf("%s", err) 363 } 364 365 if data != "USB hub found\n" { 366 t.Errorf("USB support not detected : %v", data) 367 } 368 } 369 370 func TestStepCreateVmx_Sound(t *testing.T) { 371 if os.Getenv("PACKER_ACC") == "" { 372 t.Skip("This test is only run with PACKER_ACC=1 due to the requirement of access to the VMware binaries.") 373 } 374 375 config := map[string]string{ 376 "sound": `"TRUE"`, 377 } 378 provision := map[string]string{ 379 "inline": `"cat /proc/modules | egrep -o '^soundcore' > /dev/fd0"`, 380 } 381 382 // where to write output 383 output, vmxData, err := createFloppyOutput("SoundOutput.") 384 if err != nil { 385 t.Fatalf("Error creating output: %s", err) 386 } 387 defer func() { 388 if _, err := os.Stat(output); err == nil { 389 os.Remove(output) 390 } 391 }() 392 config["vmx_data"] = vmxData 393 t.Logf("Preparing to write output to %s", output) 394 395 // whee 396 error := setupVMwareBuild(t, config, provision) 397 if error != nil { 398 t.Errorf("Unable to read file: %s", error) 399 } 400 401 // check the output 402 data, err := readFloppyOutput(output) 403 if err != nil { 404 t.Errorf("%s", err) 405 } 406 407 if data != "soundcore\n" { 408 t.Errorf("Soundcard not detected : %v", data) 409 } 410 }