github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/builder/vmware/iso/step_create_vmx.go (about) 1 package iso 2 3 import ( 4 "context" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "runtime" 10 "strings" 11 12 vmwcommon "github.com/hashicorp/packer/builder/vmware/common" 13 "github.com/hashicorp/packer/helper/multistep" 14 "github.com/hashicorp/packer/packer" 15 "github.com/hashicorp/packer/template/interpolate" 16 ) 17 18 type vmxTemplateData struct { 19 Name string 20 GuestOS string 21 ISOPath string 22 Version string 23 24 SCSI_Present string 25 SCSI_diskAdapterType string 26 SATA_Present string 27 NVME_Present string 28 29 DiskName string 30 DiskType string 31 CDROMType string 32 CDROMType_MasterSlave string 33 34 Network_Type string 35 Network_Device string 36 Network_Adapter string 37 38 Sound_Present string 39 Usb_Present string 40 41 Serial_Present string 42 Serial_Type string 43 Serial_Endpoint string 44 Serial_Host string 45 Serial_Yield string 46 Serial_Filename string 47 Serial_Auto string 48 49 Parallel_Present string 50 Parallel_Bidirectional string 51 Parallel_Filename string 52 Parallel_Auto string 53 } 54 55 type additionalDiskTemplateData struct { 56 DiskNumber int 57 DiskName string 58 } 59 60 // This step creates the VMX file for the VM. 61 // 62 // Uses: 63 // config *config 64 // iso_path string 65 // ui packer.Ui 66 // 67 // Produces: 68 // vmx_path string - The path to the VMX file. 69 type stepCreateVMX struct { 70 tempDir string 71 } 72 73 /* serial conversions */ 74 type serialConfigPipe struct { 75 filename string 76 endpoint string 77 host string 78 yield string 79 } 80 81 type serialConfigFile struct { 82 filename string 83 yield string 84 } 85 86 type serialConfigDevice struct { 87 devicename string 88 yield string 89 } 90 91 type serialConfigAuto struct { 92 devicename string 93 yield string 94 } 95 96 type serialUnion struct { 97 serialType interface{} 98 pipe *serialConfigPipe 99 file *serialConfigFile 100 device *serialConfigDevice 101 auto *serialConfigAuto 102 } 103 104 func unformat_serial(config string) (*serialUnion, error) { 105 var defaultSerialPort string 106 if runtime.GOOS == "windows" { 107 defaultSerialPort = "COM1" 108 } else { 109 defaultSerialPort = "/dev/ttyS0" 110 } 111 112 input := strings.SplitN(config, ":", 2) 113 if len(input) < 1 { 114 return nil, fmt.Errorf("Unexpected format for serial port: %s", config) 115 } 116 117 var formatType, formatOptions string 118 formatType = input[0] 119 if len(input) == 2 { 120 formatOptions = input[1] 121 } else { 122 formatOptions = "" 123 } 124 125 switch strings.ToUpper(formatType) { 126 case "PIPE": 127 comp := strings.Split(formatOptions, ",") 128 if len(comp) < 3 || len(comp) > 4 { 129 return nil, fmt.Errorf("Unexpected format for serial port : pipe : %s", config) 130 } 131 if res := strings.ToLower(comp[1]); res != "client" && res != "server" { 132 return nil, fmt.Errorf("Unexpected format for serial port : pipe : endpoint : %s : %s", res, config) 133 } 134 if res := strings.ToLower(comp[2]); res != "app" && res != "vm" { 135 return nil, fmt.Errorf("Unexpected format for serial port : pipe : host : %s : %s", res, config) 136 } 137 res := &serialConfigPipe{ 138 filename: comp[0], 139 endpoint: comp[1], 140 host: map[string]string{"app": "TRUE", "vm": "FALSE"}[strings.ToLower(comp[2])], 141 yield: "FALSE", 142 } 143 if len(comp) == 4 { 144 res.yield = strings.ToUpper(comp[3]) 145 } 146 if res.yield != "TRUE" && res.yield != "FALSE" { 147 return nil, fmt.Errorf("Unexpected format for serial port : pipe : yield : %s : %s", res.yield, config) 148 } 149 return &serialUnion{serialType: res, pipe: res}, nil 150 151 case "FILE": 152 comp := strings.Split(formatOptions, ",") 153 if len(comp) > 2 { 154 return nil, fmt.Errorf("Unexpected format for serial port : file : %s", config) 155 } 156 157 res := &serialConfigFile{yield: "FALSE"} 158 159 res.filename = filepath.FromSlash(comp[0]) 160 161 res.yield = map[bool]string{true: strings.ToUpper(comp[0]), false: "FALSE"}[len(comp) > 1] 162 if res.yield != "TRUE" && res.yield != "FALSE" { 163 return nil, fmt.Errorf("Unexpected format for serial port : file : yield : %s : %s", res.yield, config) 164 } 165 166 return &serialUnion{serialType: res, file: res}, nil 167 168 case "DEVICE": 169 comp := strings.Split(formatOptions, ",") 170 if len(comp) > 2 { 171 return nil, fmt.Errorf("Unexpected format for serial port : device : %s", config) 172 } 173 174 res := new(serialConfigDevice) 175 176 if len(comp) == 2 { 177 res.devicename = map[bool]string{true: filepath.FromSlash(comp[0]), false: defaultSerialPort}[len(comp[0]) > 0] 178 res.yield = strings.ToUpper(comp[1]) 179 } else if len(comp) == 1 { 180 res.devicename = map[bool]string{true: filepath.FromSlash(comp[0]), false: defaultSerialPort}[len(comp[0]) > 0] 181 res.yield = "FALSE" 182 } else if len(comp) == 0 { 183 res.devicename = defaultSerialPort 184 res.yield = "FALSE" 185 } 186 187 if res.yield != "TRUE" && res.yield != "FALSE" { 188 return nil, fmt.Errorf("Unexpected format for serial port : device : yield : %s : %s", res.yield, config) 189 } 190 191 return &serialUnion{serialType: res, device: res}, nil 192 193 case "AUTO": 194 res := new(serialConfigAuto) 195 res.devicename = defaultSerialPort 196 197 if len(formatOptions) > 0 { 198 res.yield = strings.ToUpper(formatOptions) 199 } else { 200 res.yield = "FALSE" 201 } 202 203 if res.yield != "TRUE" && res.yield != "FALSE" { 204 return nil, fmt.Errorf("Unexpected format for serial port : auto : yield : %s : %s", res.yield, config) 205 } 206 207 return &serialUnion{serialType: res, auto: res}, nil 208 209 case "NONE": 210 return &serialUnion{serialType: nil}, nil 211 212 default: 213 return nil, fmt.Errorf("Unknown serial type : %s : %s", strings.ToUpper(formatType), config) 214 } 215 } 216 217 /* parallel port */ 218 type parallelUnion struct { 219 parallelType interface{} 220 file *parallelPortFile 221 device *parallelPortDevice 222 auto *parallelPortAuto 223 } 224 type parallelPortFile struct { 225 filename string 226 } 227 type parallelPortDevice struct { 228 bidirectional string 229 devicename string 230 } 231 type parallelPortAuto struct { 232 bidirectional string 233 } 234 235 func unformat_parallel(config string) (*parallelUnion, error) { 236 input := strings.SplitN(config, ":", 2) 237 if len(input) < 1 { 238 return nil, fmt.Errorf("Unexpected format for parallel port: %s", config) 239 } 240 241 var formatType, formatOptions string 242 formatType = input[0] 243 if len(input) == 2 { 244 formatOptions = input[1] 245 } else { 246 formatOptions = "" 247 } 248 249 switch strings.ToUpper(formatType) { 250 case "FILE": 251 res := ¶llelPortFile{filename: filepath.FromSlash(formatOptions)} 252 return ¶llelUnion{parallelType: res, file: res}, nil 253 case "DEVICE": 254 comp := strings.Split(formatOptions, ",") 255 if len(comp) < 1 || len(comp) > 2 { 256 return nil, fmt.Errorf("Unexpected format for parallel port: %s", config) 257 } 258 res := new(parallelPortDevice) 259 res.bidirectional = "FALSE" 260 res.devicename = filepath.FromSlash(comp[0]) 261 if len(comp) > 1 { 262 switch strings.ToUpper(comp[1]) { 263 case "BI": 264 res.bidirectional = "TRUE" 265 case "UNI": 266 res.bidirectional = "FALSE" 267 default: 268 return nil, fmt.Errorf("Unknown parallel port direction : %s : %s", strings.ToUpper(comp[0]), config) 269 } 270 } 271 return ¶llelUnion{parallelType: res, device: res}, nil 272 273 case "AUTO": 274 res := new(parallelPortAuto) 275 switch strings.ToUpper(formatOptions) { 276 case "": 277 fallthrough 278 case "UNI": 279 res.bidirectional = "FALSE" 280 case "BI": 281 res.bidirectional = "TRUE" 282 default: 283 return nil, fmt.Errorf("Unknown parallel port direction : %s : %s", strings.ToUpper(formatOptions), config) 284 } 285 return ¶llelUnion{parallelType: res, auto: res}, nil 286 287 case "NONE": 288 return ¶llelUnion{parallelType: nil}, nil 289 } 290 291 return nil, fmt.Errorf("Unexpected format for parallel port: %s", config) 292 } 293 294 /* regular steps */ 295 func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { 296 config := state.Get("config").(*Config) 297 isoPath := state.Get("iso_path").(string) 298 ui := state.Get("ui").(packer.Ui) 299 300 // Convert the iso_path into a path relative to the .vmx file if possible 301 if relativeIsoPath, err := filepath.Rel(config.VMXTemplatePath, filepath.FromSlash(isoPath)); err == nil { 302 isoPath = relativeIsoPath 303 } 304 305 ui.Say("Building and writing VMX file") 306 307 vmxTemplate := DefaultVMXTemplate 308 if config.VMXTemplatePath != "" { 309 f, err := os.Open(config.VMXTemplatePath) 310 if err != nil { 311 err := fmt.Errorf("Error reading VMX template: %s", err) 312 state.Put("error", err) 313 ui.Error(err.Error()) 314 return multistep.ActionHalt 315 } 316 defer f.Close() 317 318 rawBytes, err := ioutil.ReadAll(f) 319 if err != nil { 320 err := fmt.Errorf("Error reading VMX template: %s", err) 321 state.Put("error", err) 322 ui.Error(err.Error()) 323 return multistep.ActionHalt 324 } 325 326 vmxTemplate = string(rawBytes) 327 } 328 329 ctx := config.ctx 330 331 if len(config.AdditionalDiskSize) > 0 { 332 for i := range config.AdditionalDiskSize { 333 ctx.Data = &additionalDiskTemplateData{ 334 DiskNumber: i + 1, 335 DiskName: config.DiskName, 336 } 337 338 diskTemplate := DefaultAdditionalDiskTemplate 339 if config.VMXDiskTemplatePath != "" { 340 f, err := os.Open(config.VMXDiskTemplatePath) 341 if err != nil { 342 err := fmt.Errorf("Error reading VMX disk template: %s", err) 343 state.Put("error", err) 344 ui.Error(err.Error()) 345 return multistep.ActionHalt 346 } 347 defer f.Close() 348 349 rawBytes, err := ioutil.ReadAll(f) 350 if err != nil { 351 err := fmt.Errorf("Error reading VMX disk template: %s", err) 352 state.Put("error", err) 353 ui.Error(err.Error()) 354 return multistep.ActionHalt 355 } 356 357 diskTemplate = string(rawBytes) 358 } 359 360 diskContents, err := interpolate.Render(diskTemplate, &ctx) 361 if err != nil { 362 err := fmt.Errorf("Error preparing VMX template for additional disk: %s", err) 363 state.Put("error", err) 364 ui.Error(err.Error()) 365 return multistep.ActionHalt 366 } 367 368 vmxTemplate += diskContents 369 } 370 } 371 372 templateData := vmxTemplateData{ 373 Name: config.VMName, 374 GuestOS: config.GuestOSType, 375 DiskName: config.DiskName, 376 Version: config.Version, 377 ISOPath: isoPath, 378 379 SCSI_Present: "FALSE", 380 SCSI_diskAdapterType: "lsilogic", 381 SATA_Present: "FALSE", 382 NVME_Present: "FALSE", 383 384 DiskType: "scsi", 385 CDROMType: "ide", 386 CDROMType_MasterSlave: "0", 387 388 Network_Adapter: "e1000", 389 390 Sound_Present: map[bool]string{true: "TRUE", false: "FALSE"}[bool(config.Sound)], 391 Usb_Present: map[bool]string{true: "TRUE", false: "FALSE"}[bool(config.USB)], 392 393 Serial_Present: "FALSE", 394 Parallel_Present: "FALSE", 395 } 396 397 /// Use the disk adapter type that the user specified to tweak the .vmx 398 // Also sync the cdrom adapter type according to what's common for that disk type. 399 diskAdapterType := strings.ToLower(config.DiskAdapterType) 400 switch diskAdapterType { 401 case "ide": 402 templateData.DiskType = "ide" 403 templateData.CDROMType = "ide" 404 templateData.CDROMType_MasterSlave = "1" 405 case "sata": 406 templateData.SATA_Present = "TRUE" 407 templateData.DiskType = "sata" 408 templateData.CDROMType = "sata" 409 templateData.CDROMType_MasterSlave = "1" 410 case "nvme": 411 templateData.NVME_Present = "TRUE" 412 templateData.DiskType = "nvme" 413 templateData.SATA_Present = "TRUE" 414 templateData.CDROMType = "sata" 415 templateData.CDROMType_MasterSlave = "0" 416 case "scsi": 417 diskAdapterType = "lsilogic" 418 fallthrough 419 default: 420 templateData.SCSI_Present = "TRUE" 421 templateData.SCSI_diskAdapterType = diskAdapterType 422 templateData.DiskType = "scsi" 423 templateData.CDROMType = "ide" 424 templateData.CDROMType_MasterSlave = "0" 425 } 426 427 /// Handle the cdrom adapter type. If the disk adapter type and the 428 // cdrom adapter type are the same, then ensure that the cdrom is the 429 // slave device on whatever bus the disk adapter is on. 430 cdromAdapterType := strings.ToLower(config.CdromAdapterType) 431 if cdromAdapterType == "" { 432 cdromAdapterType = templateData.CDROMType 433 } else if cdromAdapterType == diskAdapterType { 434 templateData.CDROMType_MasterSlave = "1" 435 } else { 436 templateData.CDROMType_MasterSlave = "0" 437 } 438 439 switch cdromAdapterType { 440 case "ide": 441 templateData.CDROMType = "ide" 442 case "sata": 443 templateData.SATA_Present = "TRUE" 444 templateData.CDROMType = "sata" 445 case "scsi": 446 templateData.SCSI_Present = "TRUE" 447 templateData.CDROMType = "scsi" 448 default: 449 err := fmt.Errorf("Error processing VMX template: %s", cdromAdapterType) 450 state.Put("error", err) 451 ui.Error(err.Error()) 452 return multistep.ActionHalt 453 } 454 455 /// Assign the network adapter type into the template if one was specified. 456 network_adapter := strings.ToLower(config.NetworkAdapterType) 457 if network_adapter != "" { 458 templateData.Network_Adapter = network_adapter 459 } 460 461 /// Check the network type that the user specified 462 network := config.Network 463 driver := state.Get("driver").(vmwcommon.Driver).GetVmwareDriver() 464 465 // check to see if the driver implements a network mapper for mapping 466 // the network-type to its device-name. 467 if driver.NetworkMapper != nil { 468 469 // read network map configuration into a NetworkNameMapper. 470 netmap, err := driver.NetworkMapper() 471 if err != nil { 472 state.Put("error", err) 473 ui.Error(err.Error()) 474 return multistep.ActionHalt 475 } 476 477 // try and convert the specified network to a device. 478 devices, err := netmap.NameIntoDevices(network) 479 480 if err == nil && len(devices) > 0 { 481 // If multiple devices exist, for example for network "nat", VMware chooses 482 // the actual device. Only type "custom" allows the exact choice of a 483 // specific virtual network (see below). We allow VMware to choose the device 484 // and for device-specific operations like GuestIP, try to go over all 485 // devices that match a name (e.g. "nat"). 486 // https://pubs.vmware.com/workstation-9/index.jsp?topic=%2Fcom.vmware.ws.using.doc%2FGUID-3B504F2F-7A0B-415F-AE01-62363A95D052.html 487 templateData.Network_Type = network 488 templateData.Network_Device = "" 489 } else { 490 // otherwise, we were unable to find the type, so assume it's a custom device 491 templateData.Network_Type = "custom" 492 templateData.Network_Device = network 493 } 494 495 // if NetworkMapper is nil, then we're using something like ESX, so fall 496 // back to the previous logic of using "nat" despite it not mattering to ESX. 497 } else { 498 templateData.Network_Type = "nat" 499 templateData.Network_Device = network 500 501 network = "nat" 502 } 503 504 // store the network so that we can later figure out what ip address to bind to 505 state.Put("vmnetwork", network) 506 507 /// check if serial port has been configured 508 if config.Serial == "" { 509 templateData.Serial_Present = "FALSE" 510 } else { 511 serial, err := unformat_serial(config.Serial) 512 if err != nil { 513 err := fmt.Errorf("Error processing VMX template: %s", err) 514 state.Put("error", err) 515 ui.Error(err.Error()) 516 return multistep.ActionHalt 517 } 518 519 templateData.Serial_Present = "TRUE" 520 templateData.Serial_Filename = "" 521 templateData.Serial_Yield = "" 522 templateData.Serial_Endpoint = "" 523 templateData.Serial_Host = "" 524 templateData.Serial_Auto = "FALSE" 525 526 switch serial.serialType.(type) { 527 case *serialConfigPipe: 528 templateData.Serial_Type = "pipe" 529 templateData.Serial_Endpoint = serial.pipe.endpoint 530 templateData.Serial_Host = serial.pipe.host 531 templateData.Serial_Yield = serial.pipe.yield 532 templateData.Serial_Filename = filepath.FromSlash(serial.pipe.filename) 533 case *serialConfigFile: 534 templateData.Serial_Type = "file" 535 templateData.Serial_Filename = filepath.FromSlash(serial.file.filename) 536 case *serialConfigDevice: 537 templateData.Serial_Type = "device" 538 templateData.Serial_Filename = filepath.FromSlash(serial.device.devicename) 539 case *serialConfigAuto: 540 templateData.Serial_Type = "device" 541 templateData.Serial_Filename = filepath.FromSlash(serial.auto.devicename) 542 templateData.Serial_Yield = serial.auto.yield 543 templateData.Serial_Auto = "TRUE" 544 case nil: 545 templateData.Serial_Present = "FALSE" 546 break 547 548 default: 549 err := fmt.Errorf("Error processing VMX template: %v", serial) 550 state.Put("error", err) 551 ui.Error(err.Error()) 552 return multistep.ActionHalt 553 } 554 } 555 556 /// check if parallel port has been configured 557 if config.Parallel == "" { 558 templateData.Parallel_Present = "FALSE" 559 } else { 560 parallel, err := unformat_parallel(config.Parallel) 561 if err != nil { 562 err := fmt.Errorf("Error processing VMX template: %s", err) 563 state.Put("error", err) 564 ui.Error(err.Error()) 565 return multistep.ActionHalt 566 } 567 568 templateData.Parallel_Auto = "FALSE" 569 switch parallel.parallelType.(type) { 570 case *parallelPortFile: 571 templateData.Parallel_Present = "TRUE" 572 templateData.Parallel_Filename = filepath.FromSlash(parallel.file.filename) 573 case *parallelPortDevice: 574 templateData.Parallel_Present = "TRUE" 575 templateData.Parallel_Bidirectional = parallel.device.bidirectional 576 templateData.Parallel_Filename = filepath.FromSlash(parallel.device.devicename) 577 case *parallelPortAuto: 578 templateData.Parallel_Present = "TRUE" 579 templateData.Parallel_Auto = "TRUE" 580 templateData.Parallel_Bidirectional = parallel.auto.bidirectional 581 case nil: 582 templateData.Parallel_Present = "FALSE" 583 break 584 585 default: 586 err := fmt.Errorf("Error processing VMX template: %v", parallel) 587 state.Put("error", err) 588 ui.Error(err.Error()) 589 return multistep.ActionHalt 590 } 591 } 592 593 ctx.Data = &templateData 594 595 /// render the .vmx template 596 vmxContents, err := interpolate.Render(vmxTemplate, &ctx) 597 if err != nil { 598 err := fmt.Errorf("Error processing VMX template: %s", err) 599 state.Put("error", err) 600 ui.Error(err.Error()) 601 return multistep.ActionHalt 602 } 603 604 vmxDir := config.OutputDir 605 if config.RemoteType != "" { 606 // For remote builds, we just put the VMX in a temporary 607 // directory since it just gets uploaded anyways. 608 vmxDir, err = ioutil.TempDir("", "packer-vmx") 609 if err != nil { 610 err := fmt.Errorf("Error preparing VMX template: %s", err) 611 state.Put("error", err) 612 ui.Error(err.Error()) 613 return multistep.ActionHalt 614 } 615 616 // Set the tempDir so we clean it up 617 s.tempDir = vmxDir 618 } 619 620 vmxPath := filepath.Join(vmxDir, config.VMName+".vmx") 621 if err := vmwcommon.WriteVMX(vmxPath, vmwcommon.ParseVMX(vmxContents)); err != nil { 622 err := fmt.Errorf("Error creating VMX file: %s", err) 623 state.Put("error", err) 624 ui.Error(err.Error()) 625 return multistep.ActionHalt 626 } 627 628 state.Put("vmx_path", vmxPath) 629 630 return multistep.ActionContinue 631 } 632 633 func (s *stepCreateVMX) Cleanup(multistep.StateBag) { 634 if s.tempDir != "" { 635 os.RemoveAll(s.tempDir) 636 } 637 } 638 639 // This is the default VMX template used if no other template is given. 640 // This is hardcoded here. If you wish to use a custom template please 641 // do so by specifying in the builder configuration. 642 const DefaultVMXTemplate = ` 643 .encoding = "UTF-8" 644 bios.bootOrder = "hdd,CDROM" 645 checkpoint.vmState = "" 646 cleanShutdown = "TRUE" 647 config.version = "8" 648 displayName = "{{ .Name }}" 649 ehci.pciSlotNumber = "34" 650 ehci.present = "TRUE" 651 ethernet0.addressType = "generated" 652 ethernet0.bsdName = "en0" 653 ethernet0.connectionType = "{{ .Network_Type }}" 654 ethernet0.vnet = "{{ .Network_Device }}" 655 ethernet0.displayName = "Ethernet" 656 ethernet0.linkStatePropagation.enable = "FALSE" 657 ethernet0.pciSlotNumber = "33" 658 ethernet0.present = "TRUE" 659 ethernet0.virtualDev = "{{ .Network_Adapter }}" 660 ethernet0.wakeOnPcktRcv = "FALSE" 661 extendedConfigFile = "{{ .Name }}.vmxf" 662 floppy0.present = "FALSE" 663 guestOS = "{{ .GuestOS }}" 664 gui.fullScreenAtPowerOn = "FALSE" 665 gui.viewModeAtPowerOn = "windowed" 666 hgfs.linkRootShare = "TRUE" 667 hgfs.mapRootShare = "TRUE" 668 669 scsi0.present = "{{ .SCSI_Present }}" 670 scsi0.virtualDev = "{{ .SCSI_diskAdapterType }}" 671 scsi0.pciSlotNumber = "16" 672 scsi0:0.redo = "" 673 sata0.present = "{{ .SATA_Present }}" 674 nvme0.present = "{{ .NVME_Present }}" 675 676 {{ .DiskType }}0:0.present = "TRUE" 677 {{ .DiskType }}0:0.fileName = "{{ .DiskName }}.vmdk" 678 679 {{ .CDROMType }}0:{{ .CDROMType_MasterSlave }}.present = "TRUE" 680 {{ .CDROMType }}0:{{ .CDROMType_MasterSlave }}.fileName = "{{ .ISOPath }}" 681 {{ .CDROMType }}0:{{ .CDROMType_MasterSlave }}.deviceType = "cdrom-image" 682 683 isolation.tools.hgfs.disable = "FALSE" 684 memsize = "512" 685 nvram = "{{ .Name }}.nvram" 686 pciBridge0.pciSlotNumber = "17" 687 pciBridge0.present = "TRUE" 688 pciBridge4.functions = "8" 689 pciBridge4.pciSlotNumber = "21" 690 pciBridge4.present = "TRUE" 691 pciBridge4.virtualDev = "pcieRootPort" 692 pciBridge5.functions = "8" 693 pciBridge5.pciSlotNumber = "22" 694 pciBridge5.present = "TRUE" 695 pciBridge5.virtualDev = "pcieRootPort" 696 pciBridge6.functions = "8" 697 pciBridge6.pciSlotNumber = "23" 698 pciBridge6.present = "TRUE" 699 pciBridge6.virtualDev = "pcieRootPort" 700 pciBridge7.functions = "8" 701 pciBridge7.pciSlotNumber = "24" 702 pciBridge7.present = "TRUE" 703 pciBridge7.virtualDev = "pcieRootPort" 704 powerType.powerOff = "soft" 705 powerType.powerOn = "soft" 706 powerType.reset = "soft" 707 powerType.suspend = "soft" 708 proxyApps.publishToHost = "FALSE" 709 replay.filename = "" 710 replay.supported = "FALSE" 711 712 // Sound 713 sound.startConnected = "{{ .Sound_Present }}" 714 sound.present = "{{ .Sound_Present }}" 715 sound.fileName = "-1" 716 sound.autodetect = "TRUE" 717 718 tools.syncTime = "TRUE" 719 tools.upgrade.policy = "upgradeAtPowerCycle" 720 721 // USB 722 usb.pciSlotNumber = "32" 723 usb.present = "{{ .Usb_Present }}" 724 725 // Serial 726 serial0.present = "{{ .Serial_Present }}" 727 serial0.startConnected = "{{ .Serial_Present }}" 728 serial0.fileName = "{{ .Serial_Filename }}" 729 serial0.autodetect = "{{ .Serial_Auto }}" 730 serial0.fileType = "{{ .Serial_Type }}" 731 serial0.yieldOnMsrRead = "{{ .Serial_Yield }}" 732 serial0.pipe.endPoint = "{{ .Serial_Endpoint }}" 733 serial0.tryNoRxLoss = "{{ .Serial_Host }}" 734 735 // Parallel 736 parallel0.present = "{{ .Parallel_Present }}" 737 parallel0.startConnected = "{{ .Parallel_Present }}" 738 parallel0.fileName = "{{ .Parallel_Filename }}" 739 parallel0.autodetect = "{{ .Parallel_Auto }}" 740 parallel0.bidirectional = "{{ .Parallel_Bidirectional }}" 741 742 virtualHW.productCompatibility = "hosted" 743 virtualHW.version = "{{ .Version }}" 744 vmci0.id = "1861462627" 745 vmci0.pciSlotNumber = "35" 746 vmci0.present = "TRUE" 747 vmotion.checkpointFBSize = "65536000" 748 ` 749 750 const DefaultAdditionalDiskTemplate = ` 751 scsi0:{{ .DiskNumber }}.fileName = "{{ .DiskName}}-{{ .DiskNumber }}.vmdk" 752 scsi0:{{ .DiskNumber }}.present = "TRUE" 753 scsi0:{{ .DiskNumber }}.redo = "" 754 `