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