github.com/rothwerx/packer@v0.9.0/builder/vmware/iso/step_create_vmx.go (about)

     1  package iso
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	"github.com/mitchellh/multistep"
    10  	vmwcommon "github.com/mitchellh/packer/builder/vmware/common"
    11  	"github.com/mitchellh/packer/packer"
    12  	"github.com/mitchellh/packer/template/interpolate"
    13  )
    14  
    15  type vmxTemplateData struct {
    16  	Name     string
    17  	GuestOS  string
    18  	DiskName string
    19  	ISOPath  string
    20  	Version  string
    21  }
    22  
    23  type additionalDiskTemplateData struct {
    24  	DiskNumber int
    25  	DiskName   string
    26  }
    27  
    28  // This step creates the VMX file for the VM.
    29  //
    30  // Uses:
    31  //   config *config
    32  //   iso_path string
    33  //   ui     packer.Ui
    34  //
    35  // Produces:
    36  //   vmx_path string - The path to the VMX file.
    37  type stepCreateVMX struct {
    38  	tempDir string
    39  }
    40  
    41  func (s *stepCreateVMX) Run(state multistep.StateBag) multistep.StepAction {
    42  	config := state.Get("config").(*Config)
    43  	isoPath := state.Get("iso_path").(string)
    44  	ui := state.Get("ui").(packer.Ui)
    45  
    46  	ui.Say("Building and writing VMX file")
    47  
    48  	vmxTemplate := DefaultVMXTemplate
    49  	if config.VMXTemplatePath != "" {
    50  		f, err := os.Open(config.VMXTemplatePath)
    51  		if err != nil {
    52  			err := fmt.Errorf("Error reading VMX template: %s", err)
    53  			state.Put("error", err)
    54  			ui.Error(err.Error())
    55  			return multistep.ActionHalt
    56  		}
    57  		defer f.Close()
    58  
    59  		rawBytes, err := ioutil.ReadAll(f)
    60  		if err != nil {
    61  			err := fmt.Errorf("Error reading VMX template: %s", err)
    62  			state.Put("error", err)
    63  			ui.Error(err.Error())
    64  			return multistep.ActionHalt
    65  		}
    66  
    67  		vmxTemplate = string(rawBytes)
    68  	}
    69  
    70  	ctx := config.ctx
    71  
    72  	if len(config.AdditionalDiskSize) > 0 {
    73  		for i, _ := range config.AdditionalDiskSize {
    74  			ctx.Data = &additionalDiskTemplateData{
    75  				DiskNumber: i + 1,
    76  				DiskName:   config.DiskName,
    77  			}
    78  
    79  			diskTemplate := DefaultAdditionalDiskTemplate
    80  			if config.VMXDiskTemplatePath != "" {
    81  				f, err := os.Open(config.VMXDiskTemplatePath)
    82  				if err != nil {
    83  					err := fmt.Errorf("Error reading VMX disk template: %s", err)
    84  					state.Put("error", err)
    85  					ui.Error(err.Error())
    86  					return multistep.ActionHalt
    87  				}
    88  				defer f.Close()
    89  
    90  				rawBytes, err := ioutil.ReadAll(f)
    91  				if err != nil {
    92  					err := fmt.Errorf("Error reading VMX disk template: %s", err)
    93  					state.Put("error", err)
    94  					ui.Error(err.Error())
    95  					return multistep.ActionHalt
    96  				}
    97  
    98  				diskTemplate = string(rawBytes)
    99  			}
   100  
   101  			diskContents, err := interpolate.Render(diskTemplate, &ctx)
   102  			if err != nil {
   103  				err := fmt.Errorf("Error preparing VMX template for additional disk: %s", err)
   104  				state.Put("error", err)
   105  				ui.Error(err.Error())
   106  				return multistep.ActionHalt
   107  			}
   108  
   109  			vmxTemplate += diskContents
   110  		}
   111  	}
   112  
   113  	ctx.Data = &vmxTemplateData{
   114  		Name:     config.VMName,
   115  		GuestOS:  config.GuestOSType,
   116  		DiskName: config.DiskName,
   117  		Version:  config.Version,
   118  		ISOPath:  isoPath,
   119  	}
   120  
   121  	vmxContents, err := interpolate.Render(vmxTemplate, &ctx)
   122  	if err != nil {
   123  		err := fmt.Errorf("Error procesing VMX template: %s", err)
   124  		state.Put("error", err)
   125  		ui.Error(err.Error())
   126  		return multistep.ActionHalt
   127  	}
   128  
   129  	vmxDir := config.OutputDir
   130  	if config.RemoteType != "" {
   131  		// For remote builds, we just put the VMX in a temporary
   132  		// directory since it just gets uploaded anyways.
   133  		vmxDir, err = ioutil.TempDir("", "packer-vmx")
   134  		if err != nil {
   135  			err := fmt.Errorf("Error preparing VMX template: %s", err)
   136  			state.Put("error", err)
   137  			ui.Error(err.Error())
   138  			return multistep.ActionHalt
   139  		}
   140  
   141  		// Set the tempDir so we clean it up
   142  		s.tempDir = vmxDir
   143  	}
   144  
   145  	vmxPath := filepath.Join(vmxDir, config.VMName+".vmx")
   146  	if err := vmwcommon.WriteVMX(vmxPath, vmwcommon.ParseVMX(vmxContents)); err != nil {
   147  		err := fmt.Errorf("Error creating VMX file: %s", err)
   148  		state.Put("error", err)
   149  		ui.Error(err.Error())
   150  		return multistep.ActionHalt
   151  	}
   152  
   153  	state.Put("vmx_path", vmxPath)
   154  
   155  	return multistep.ActionContinue
   156  }
   157  
   158  func (s *stepCreateVMX) Cleanup(multistep.StateBag) {
   159  	if s.tempDir != "" {
   160  		os.RemoveAll(s.tempDir)
   161  	}
   162  }
   163  
   164  // This is the default VMX template used if no other template is given.
   165  // This is hardcoded here. If you wish to use a custom template please
   166  // do so by specifying in the builder configuration.
   167  const DefaultVMXTemplate = `
   168  .encoding = "UTF-8"
   169  bios.bootOrder = "hdd,CDROM"
   170  checkpoint.vmState = ""
   171  cleanShutdown = "TRUE"
   172  config.version = "8"
   173  displayName = "{{ .Name }}"
   174  ehci.pciSlotNumber = "34"
   175  ehci.present = "TRUE"
   176  ethernet0.addressType = "generated"
   177  ethernet0.bsdName = "en0"
   178  ethernet0.connectionType = "nat"
   179  ethernet0.displayName = "Ethernet"
   180  ethernet0.linkStatePropagation.enable = "FALSE"
   181  ethernet0.pciSlotNumber = "33"
   182  ethernet0.present = "TRUE"
   183  ethernet0.virtualDev = "e1000"
   184  ethernet0.wakeOnPcktRcv = "FALSE"
   185  extendedConfigFile = "{{ .Name }}.vmxf"
   186  floppy0.present = "FALSE"
   187  guestOS = "{{ .GuestOS }}"
   188  gui.fullScreenAtPowerOn = "FALSE"
   189  gui.viewModeAtPowerOn = "windowed"
   190  hgfs.linkRootShare = "TRUE"
   191  hgfs.mapRootShare = "TRUE"
   192  ide1:0.present = "TRUE"
   193  ide1:0.fileName = "{{ .ISOPath }}"
   194  ide1:0.deviceType = "cdrom-image"
   195  isolation.tools.hgfs.disable = "FALSE"
   196  memsize = "512"
   197  nvram = "{{ .Name }}.nvram"
   198  pciBridge0.pciSlotNumber = "17"
   199  pciBridge0.present = "TRUE"
   200  pciBridge4.functions = "8"
   201  pciBridge4.pciSlotNumber = "21"
   202  pciBridge4.present = "TRUE"
   203  pciBridge4.virtualDev = "pcieRootPort"
   204  pciBridge5.functions = "8"
   205  pciBridge5.pciSlotNumber = "22"
   206  pciBridge5.present = "TRUE"
   207  pciBridge5.virtualDev = "pcieRootPort"
   208  pciBridge6.functions = "8"
   209  pciBridge6.pciSlotNumber = "23"
   210  pciBridge6.present = "TRUE"
   211  pciBridge6.virtualDev = "pcieRootPort"
   212  pciBridge7.functions = "8"
   213  pciBridge7.pciSlotNumber = "24"
   214  pciBridge7.present = "TRUE"
   215  pciBridge7.virtualDev = "pcieRootPort"
   216  powerType.powerOff = "soft"
   217  powerType.powerOn = "soft"
   218  powerType.reset = "soft"
   219  powerType.suspend = "soft"
   220  proxyApps.publishToHost = "FALSE"
   221  replay.filename = ""
   222  replay.supported = "FALSE"
   223  scsi0.pciSlotNumber = "16"
   224  scsi0.present = "TRUE"
   225  scsi0.virtualDev = "lsilogic"
   226  scsi0:0.fileName = "{{ .DiskName }}.vmdk"
   227  scsi0:0.present = "TRUE"
   228  scsi0:0.redo = ""
   229  sound.startConnected = "FALSE"
   230  tools.syncTime = "TRUE"
   231  tools.upgrade.policy = "upgradeAtPowerCycle"
   232  usb.pciSlotNumber = "32"
   233  usb.present = "FALSE"
   234  virtualHW.productCompatibility = "hosted"
   235  virtualHW.version = "{{ .Version }}"
   236  vmci0.id = "1861462627"
   237  vmci0.pciSlotNumber = "35"
   238  vmci0.present = "TRUE"
   239  vmotion.checkpointFBSize = "65536000"
   240  `
   241  
   242  const DefaultAdditionalDiskTemplate = `
   243  scsi0:{{ .DiskNumber }}.fileName = "{{ .DiskName}}-{{ .DiskNumber }}.vmdk"
   244  scsi0:{{ .DiskNumber }}.present = "TRUE"
   245  scsi0:{{ .DiskNumber }}.redo = ""
   246  `