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 := &parallelPortFile{filename: filepath.FromSlash(formatOptions)}
   252  		return &parallelUnion{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 &parallelUnion{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 &parallelUnion{parallelType: res, auto: res}, nil
   286  
   287  	case "NONE":
   288  		return &parallelUnion{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  `