diff --git a/builder/virtualbox/common/driver.go b/builder/virtualbox/common/driver.go index 986443e66..dcb036a26 100644 --- a/builder/virtualbox/common/driver.go +++ b/builder/virtualbox/common/driver.go @@ -25,6 +25,9 @@ type Driver interface { // Create an NVME controller CreateNVMeController(vm string, controller string, portcount int) error + // Delete all floppy controllers + RemoveFloppyControllers(vm string) error + // Delete a VM by name Delete(string) error diff --git a/builder/virtualbox/common/driver_4_2.go b/builder/virtualbox/common/driver_4_2.go index 302820c04..b710720dc 100644 --- a/builder/virtualbox/common/driver_4_2.go +++ b/builder/virtualbox/common/driver_4_2.go @@ -75,6 +75,55 @@ func (d *VBox42Driver) CreateSCSIController(vmName string, name string) error { return d.VBoxManage(command...) } +func (d *VBox42Driver) RemoveFloppyControllers(vmName string) error { + var stdout bytes.Buffer + + cmd := exec.Command(d.VBoxManagePath, "showvminfo", vmName, "--machinereadable") + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + return err + } + + StorageControllerTypeRe := regexp.MustCompile("^storagecontrollertype([0-9]+)=\"(.+)\"$") + StorageControllerNameRe := regexp.MustCompile("^storagecontrollername([0-9]+)=\"(.+)\"$") + + storageControllerNames := make(map[string]string) + storageControllerIdx := "" + + for _, line := range strings.Split(stdout.String(), "\n") { + // Need to trim off CR character when running in windows + // Trimming whitespaces at this point helps to filter out empty value + line = strings.TrimRight(line, " \r") + + matches := StorageControllerTypeRe.FindStringSubmatch(line) + if matches != nil { + // Floppy controllers are of a type I82078 + if matches[2] == "I82078" { + // VirtualBox supports only one floppy controller per VM + storageControllerIdx = matches[1] + } + continue + } + + matches = StorageControllerNameRe.FindStringSubmatch(line) + if matches != nil { + storageControllerNames[matches[1]] = matches[2] + } + } + + if storageControllerIdx == "" { + return nil + } + + command := []string{ + "storagectl", vmName, + "--name", storageControllerNames[storageControllerIdx], + "--remove", + } + + return d.VBoxManage(command...) +} + func (d *VBox42Driver) Delete(name string) error { return d.VBoxManage("unregistervm", name, "--delete") } diff --git a/builder/virtualbox/common/driver_mock.go b/builder/virtualbox/common/driver_mock.go index 775fca430..58dc5f749 100644 --- a/builder/virtualbox/common/driver_mock.go +++ b/builder/virtualbox/common/driver_mock.go @@ -17,6 +17,9 @@ type DriverMock struct { CreateNVMeControllerController string CreateNVMeControllerErr error + RemoveFloppyControllersVM string + RemoveFloppyControllersErr error + DeleteCalled bool DeleteName string DeleteErr error @@ -81,6 +84,11 @@ func (d *DriverMock) CreateNVMeController(vm string, controller string, portcoun return d.CreateNVMeControllerErr } +func (d *DriverMock) RemoveFloppyControllers(vm string) error { + d.RemoveFloppyControllersVM = vm + return d.RemoveFloppyControllersErr +} + func (d *DriverMock) Delete(name string) error { d.DeleteCalled = true d.DeleteName = name diff --git a/builder/virtualbox/common/step_attach_floppy.go b/builder/virtualbox/common/step_attach_floppy.go index df32fd6e8..3af76e0cf 100644 --- a/builder/virtualbox/common/step_attach_floppy.go +++ b/builder/virtualbox/common/step_attach_floppy.go @@ -48,6 +48,12 @@ func (s *StepAttachFloppy) Run(ctx context.Context, state multistep.StateBag) mu ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) + ui.Say("Deleting any current floppy disk...") + if err := driver.RemoveFloppyControllers(vmName); err != nil { + state.Put("error", fmt.Errorf("Error deleting existing floppy controllers: %s", err)) + return multistep.ActionHalt + } + ui.Say("Attaching floppy disk...") // Create the floppy disk controller diff --git a/builder/virtualbox/common/step_attach_floppy_test.go b/builder/virtualbox/common/step_attach_floppy_test.go index 32ad4a962..75d51c333 100644 --- a/builder/virtualbox/common/step_attach_floppy_test.go +++ b/builder/virtualbox/common/step_attach_floppy_test.go @@ -38,6 +38,10 @@ func TestStepAttachFloppy(t *testing.T) { t.Fatal("should NOT have error") } + if driver.RemoveFloppyControllersVM == "" { + t.Fatal("RemoveFloppyControllers was not called") + } + if len(driver.VBoxManageCalls) != 2 { t.Fatal("not enough calls to VBoxManage") }