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 `