diff --git a/builder/virtualbox/builder.go b/builder/virtualbox/builder.go index d0860331e..e45286a77 100644 --- a/builder/virtualbox/builder.go +++ b/builder/virtualbox/builder.go @@ -28,6 +28,7 @@ type config struct { BootCommand []string `mapstructure:"boot_command"` BootWait time.Duration `` DiskSize uint `mapstructure:"disk_size"` + FloppyFiles []string `mapstructure:"floppy_files"` GuestAdditionsPath string `mapstructure:"guest_additions_path"` GuestAdditionsURL string `mapstructure:"guest_additions_url"` GuestAdditionsSHA256 string `mapstructure:"guest_additions_sha256"` @@ -73,6 +74,10 @@ func (b *Builder) Prepare(raws ...interface{}) error { b.config.DiskSize = 40000 } + if b.config.FloppyFiles == nil { + b.config.FloppyFiles = make([]string, 0) + } + if b.config.GuestAdditionsPath == "" { b.config.GuestAdditionsPath = "VBoxGuestAdditions.iso" } @@ -265,11 +270,15 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe new(stepDownloadGuestAdditions), new(stepDownloadISO), new(stepPrepareOutputDir), + &common.StepCreateFloppy{ + Files: b.config.FloppyFiles, + }, new(stepHTTPServer), new(stepSuppressMessages), new(stepCreateVM), new(stepCreateDisk), new(stepAttachISO), + new(stepAttachFloppy), new(stepForwardSSH), new(stepVBoxManage), new(stepRun), diff --git a/builder/virtualbox/builder_test.go b/builder/virtualbox/builder_test.go index 655ce57ad..46f9c8997 100644 --- a/builder/virtualbox/builder_test.go +++ b/builder/virtualbox/builder_test.go @@ -115,6 +115,33 @@ func TestBuilderPrepare_DiskSize(t *testing.T) { } } +func TestBuilderPrepare_FloppyFiles(t *testing.T) { + var b Builder + config := testConfig() + + delete(config, "floppy_files") + err := b.Prepare(config) + if err != nil { + t.Fatalf("bad err: %s", err) + } + + if len(b.config.FloppyFiles) != 0 { + t.Fatalf("bad: %#v", b.config.FloppyFiles) + } + + config["floppy_files"] = []string{"foo", "bar"} + b = Builder{} + err = b.Prepare(config) + if err != nil { + t.Fatalf("should not have error: %s", err) + } + + expected := []string{"foo", "bar"} + if !reflect.DeepEqual(b.config.FloppyFiles, expected) { + t.Fatalf("bad: %#v", b.config.FloppyFiles) + } +} + func TestBuilderPrepare_GuestAdditionsPath(t *testing.T) { var b Builder config := testConfig() diff --git a/builder/virtualbox/step_attach_floppy.go b/builder/virtualbox/step_attach_floppy.go new file mode 100644 index 000000000..be7394160 --- /dev/null +++ b/builder/virtualbox/step_attach_floppy.go @@ -0,0 +1,129 @@ +package virtualbox + +import ( + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "io" + "io/ioutil" + "log" + "os" + "path/filepath" +) + +// This step attaches the ISO to the virtual machine. +// +// Uses: +// +// Produces: +type stepAttachFloppy struct { + floppyPath string +} + +func (s *stepAttachFloppy) Run(state map[string]interface{}) multistep.StepAction { + // Determine if we even have a floppy disk to attach + var floppyPath string + if floppyPathRaw, ok := state["floppy_path"]; ok { + floppyPath = floppyPathRaw.(string) + } else { + log.Println("No floppy disk, not attaching.") + return multistep.ActionContinue + } + + // VirtualBox is really dumb and can't figure out the format of the file + // without an extension, so we need to add the "vfd" extension to the + // floppy. + floppyPath, err := s.copyFloppy(floppyPath) + if err != nil { + state["error"] = fmt.Errorf("Error preparing floppy: %s", err) + return multistep.ActionHalt + } + + driver := state["driver"].(Driver) + ui := state["ui"].(packer.Ui) + vmName := state["vmName"].(string) + + ui.Say("Attaching floppy disk...") + + // Create the floppy disk controller + command := []string{ + "storagectl", vmName, + "--name", "Floppy Controller", + "--add", "floppy", + } + if err := driver.VBoxManage(command...); err != nil { + state["error"] = fmt.Errorf("Error creating floppy controller: %s", err) + return multistep.ActionHalt + } + + // Attach the floppy to the controller + command = []string{ + "storageattach", vmName, + "--storagectl", "Floppy Controller", + "--port", "0", + "--device", "0", + "--type", "fdd", + "--medium", floppyPath, + } + if err := driver.VBoxManage(command...); err != nil { + state["error"] = fmt.Errorf("Error attaching floppy: %s", err) + return multistep.ActionHalt + } + + // Track the path so that we can unregister it from VirtualBox later + s.floppyPath = floppyPath + + return multistep.ActionContinue +} + +func (s *stepAttachFloppy) Cleanup(state map[string]interface{}) { + if s.floppyPath == "" { + return + } + + // Delete the floppy disk + defer os.Remove(s.floppyPath) + + driver := state["driver"].(Driver) + ui := state["ui"].(packer.Ui) + vmName := state["vmName"].(string) + + command := []string{ + "storageattach", vmName, + "--storagectl", "Floppy Controller", + "--port", "0", + "--device", "0", + "--medium", "none", + } + + if err := driver.VBoxManage(command...); err != nil { + ui.Error(fmt.Sprintf("Error unregistering floppy: %s", err)) + } +} + +func (s *stepAttachFloppy) copyFloppy(path string) (string, error) { + tempdir, err := ioutil.TempDir("", "packer") + if err != nil { + return "", err + } + + floppyPath := filepath.Join(tempdir, "floppy.vfd") + f, err := os.Create(floppyPath) + if err != nil { + return "", err + } + defer f.Close() + + sourceF, err := os.Open(path) + if err != nil { + return "", err + } + defer sourceF.Close() + + log.Printf("Copying floppy to temp location: %s", floppyPath) + if _, err := io.Copy(f, sourceF); err != nil { + return "", err + } + + return floppyPath, nil +}