diff --git a/builder/vmware/common/step_clean_vmx.go b/builder/vmware/common/step_clean_vmx.go index db0db5aac..1db8a81ee 100644 --- a/builder/vmware/common/step_clean_vmx.go +++ b/builder/vmware/common/step_clean_vmx.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "log" - "regexp" "strings" "github.com/hashicorp/packer/helper/multistep" @@ -37,40 +36,85 @@ func (s StepCleanVMX) Run(_ context.Context, state multistep.StateBag) multistep return multistep.ActionHalt } - // Delete the floppy0 entries so the floppy is no longer mounted - ui.Message("Unmounting floppy from VMX...") - for k := range vmxData { - if strings.HasPrefix(k, "floppy0.") { - log.Printf("Deleting key: %s", k) - delete(vmxData, k) - } - } - vmxData["floppy0.present"] = "FALSE" + // Grab our list of devices added during the build out of the statebag + for _, device := range state.Get("temporaryDevices").([]string) { + // Instead of doing this in one pass which would be more efficient, + // we do it per device-type so that the logic appears to be the same + // as the prior implementation. - devRe := regexp.MustCompile(`^(ide|sata)\d:\d\.`) - for k, v := range vmxData { - ide := devRe.FindString(k) - if ide == "" || v != "cdrom-image" { - continue - } + // Walk through all the devices that were temporarily added and figure + // out which type it is in order to figure out how to disable it. + // Right now only floppy, cdrom devices, ethernet, and devices that use + // ".present" are supported. + if strings.HasPrefix(device, "floppy") { + // We can identify a floppy device because it begins with "floppy" + ui.Message(fmt.Sprintf("Unmounting %s from VMX...", device)) + + // Delete the floppy%d entries so the floppy is no longer mounted + for k := range vmxData { + if strings.HasPrefix(k, fmt.Sprintf("%s.", device)) { + log.Printf("Deleting key for floppy device: %s", k) + delete(vmxData, k) + } + } + vmxData[fmt.Sprintf("%s.present", device)] = "FALSE" + + } else if strings.HasPrefix(vmxData[fmt.Sprintf("%s.devicetype", device)], "cdrom-") { + // We can identify something is a cdrom if it has a ".devicetype" + // attribute that begins with "cdrom-" + ui.Message(fmt.Sprintf("Detaching ISO from CD-ROM device %s...", device)) - ui.Message("Detaching ISO from CD-ROM device...") + // Simply turn the CDROM device into a native cdrom instead of an iso + vmxData[fmt.Sprintf("%s.devicetype", device)] = "cdrom-raw" + vmxData[fmt.Sprintf("%s.filename", device)] = "auto detect" + vmxData[fmt.Sprintf("%s.clientdevice", device)] = "TRUE" - vmxData[ide+"devicetype"] = "cdrom-raw" - vmxData[ide+"filename"] = "auto detect" - vmxData[ide+"clientdevice"] = "TRUE" + } else if strings.HasPrefix(device, "ethernet") && s.RemoveEthernetInterfaces { + // We can identify an ethernet device because it begins with "ethernet" + // Although we're supporting this, as of now it's not in use due + // to these interfaces not ever being added to the "temporaryDevices" statebag. + ui.Message(fmt.Sprintf("Removing %s interface...", device)) + + // Delete the ethernet%d entries so the ethernet interface is removed. + // This corresponds to the same logic defined below. + for k := range vmxData { + if strings.HasPrefix(k, fmt.Sprintf("%s.", device)) { + log.Printf("Deleting key for ethernet device: %s", k) + delete(vmxData, k) + } + } + + } else { + + // First check to see if we can simply disable the device + if _, ok := vmxData[fmt.Sprintf("%s.present", device)]; ok { + ui.Message(fmt.Sprintf("Disabling device %s of an unknown device type...", device)) + vmxData[fmt.Sprintf("%s.present", device)] = "FALSE" + } else { + // Okay, so this wasn't so simple. Let's just log info about the + // device and not tamper with any of its keys + log.Printf("Refusing to remove device due to being of an unsupported type: %s\n", device) + for k := range vmxData { + if strings.HasPrefix(k, fmt.Sprintf("%s.", device)) { + log.Printf("Leaving unsupported device key: %s\n", k) + } + } + } + } } + // Disable the VNC server if necessary if s.VNCEnabled { ui.Message("Disabling VNC server...") vmxData["remotedisplay.vnc.enabled"] = "FALSE" } + // Disable any ethernet devices if necessary if s.RemoveEthernetInterfaces { ui.Message("Removing Ethernet Interfaces...") for k := range vmxData { if strings.HasPrefix(k, "ethernet") { - log.Printf("Deleting key: %s", k) + log.Printf("Deleting key for ethernet device: %s", k) delete(vmxData, k) } } diff --git a/builder/vmware/common/step_clean_vmx_test.go b/builder/vmware/common/step_clean_vmx_test.go index 0f4df3df2..3987fb2c4 100644 --- a/builder/vmware/common/step_clean_vmx_test.go +++ b/builder/vmware/common/step_clean_vmx_test.go @@ -40,8 +40,12 @@ func TestStepCleanVMX_floppyPath(t *testing.T) { t.Fatalf("err: %s", err) } + // Set the path to the temporary vmx state.Put("vmx_path", vmxPath) + // Add the floppy device to the list of temporary build devices + state.Put("temporaryDevices", []string{"floppy0"}) + // Test the run if action := step.Run(context.Background(), state); action != multistep.ActionContinue { t.Fatalf("bad action: %#v", action) @@ -89,8 +93,12 @@ func TestStepCleanVMX_isoPath(t *testing.T) { t.Fatalf("err: %s", err) } + // Set the path to the temporary vmx state.Put("vmx_path", vmxPath) + // Add the cdrom device to the list of temporary build devices + state.Put("temporaryDevices", []string{"ide0:0"}) + // Test the run if action := step.Run(context.Background(), state); action != multistep.ActionContinue { t.Fatalf("bad action: %#v", action) @@ -141,8 +149,12 @@ func TestStepCleanVMX_ethernet(t *testing.T) { t.Fatalf("err: %s", err) } + // Set the path to the temporary vmx state.Put("vmx_path", vmxPath) + // TODO: Add the ethernet devices to the list of temporary build devices + // state.Put("temporaryDevices", []string{"ethernet0", "ethernet1"}) + // Test the run if action := step.Run(context.Background(), state); action != multistep.ActionContinue { t.Fatalf("bad action: %#v", action) diff --git a/builder/vmware/common/step_configure_vmx.go b/builder/vmware/common/step_configure_vmx.go index 73f0d60fb..a4ebd7ae6 100644 --- a/builder/vmware/common/step_configure_vmx.go +++ b/builder/vmware/common/step_configure_vmx.go @@ -65,13 +65,22 @@ func (s *StepConfigureVMX) Run(_ context.Context, state multistep.StateBag) mult // Set a floppy disk, but only if we should if !s.SkipFloppy { + // Grab list of temporary builder devices so we can append the floppy to it + tmpBuildDevices := state.Get("temporaryDevices").([]string) + // Set a floppy disk if we have one if floppyPathRaw, ok := state.GetOk("floppy_path"); ok { log.Println("Floppy path present, setting in VMX") vmxData["floppy0.present"] = "TRUE" vmxData["floppy0.filetype"] = "file" vmxData["floppy0.filename"] = floppyPathRaw.(string) + + // Add it to our list of build devices to later remove + tmpBuildDevices = append(tmpBuildDevices, "floppy0") } + + // Build the list back in our statebag + state.Put("temporaryDevices", tmpBuildDevices) } // If the build is taking place on a remote ESX server, the displayName diff --git a/builder/vmware/common/step_test.go b/builder/vmware/common/step_test.go index c8a12abb6..d1daffab5 100644 --- a/builder/vmware/common/step_test.go +++ b/builder/vmware/common/step_test.go @@ -15,5 +15,6 @@ func testState(t *testing.T) multistep.StateBag { Reader: new(bytes.Buffer), Writer: new(bytes.Buffer), }) + state.Put("temporaryDevices", []string{}) return state } diff --git a/builder/vmware/iso/builder.go b/builder/vmware/iso/builder.go index dc49f157d..9b37d8503 100644 --- a/builder/vmware/iso/builder.go +++ b/builder/vmware/iso/builder.go @@ -65,6 +65,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("ui", ui) state.Put("sshConfig", &b.config.SSHConfig) state.Put("driverConfig", &b.config.DriverConfig) + state.Put("temporaryDevices", []string{}) // Devices (in .vmx) created by packer during building steps := []multistep.Step{ &vmwcommon.StepPrepareTools{ diff --git a/builder/vmware/iso/step_create_vmx.go b/builder/vmware/iso/step_create_vmx.go index 4fa5254f8..5a46c14ef 100644 --- a/builder/vmware/iso/step_create_vmx.go +++ b/builder/vmware/iso/step_create_vmx.go @@ -243,6 +243,13 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist return multistep.ActionHalt } + /// Now that we figured out the CDROM device to add, store it + /// to the list of temporary build devices in our statebag + tmpBuildDevices := state.Get("temporaryDevices").([]string) + tmpCdromDevice := fmt.Sprintf("%s0:%s", templateData.CDROMType, templateData.CDROMType_PrimarySecondary) + tmpBuildDevices = append(tmpBuildDevices, tmpCdromDevice) + state.Put("temporaryDevices", tmpBuildDevices) + /// Assign the network adapter type into the template if one was specified. network_adapter := strings.ToLower(config.HWConfig.NetworkAdapterType) if network_adapter != "" { diff --git a/builder/vmware/vmx/builder.go b/builder/vmware/vmx/builder.go index 22ed9555d..e3f6a8c8b 100644 --- a/builder/vmware/vmx/builder.go +++ b/builder/vmware/vmx/builder.go @@ -67,6 +67,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("ui", ui) state.Put("sshConfig", &b.config.SSHConfig) state.Put("driverConfig", &b.config.DriverConfig) + state.Put("temporaryDevices", []string{}) // Devices (in .vmx) created by packer during building // Build the steps. steps := []multistep.Step{