From 30eccf4130b591db23d046d9d1261ad95e34fcc5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 18 Sep 2013 18:15:46 -0700 Subject: [PATCH] builder/virtualbox: support attaching guest additions [GH-405] --- CHANGELOG.md | 2 + builder/virtualbox/builder.go | 2 + .../virtualbox/step_attach_guest_additions.go | 81 +++++++++++++++++++ .../virtualbox/step_upload_guest_additions.go | 7 ++ .../docs/builders/virtualbox.html.markdown | 4 + 5 files changed, 96 insertions(+) create mode 100644 builder/virtualbox/step_attach_guest_additions.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a85c2ce1..c6a02f949 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ FEATURES: +* builders/virtualbox: Guest additions can be attached rather than uploaded, + easier to handle for Windows guests. [GH-405] * provisioner/chef-solo: Ability to specify a custom Chef configuration template. * provisioner/chef-solo: Roles and data bags support. [GH-348] diff --git a/builder/virtualbox/builder.go b/builder/virtualbox/builder.go index 18b16867a..452a7de49 100644 --- a/builder/virtualbox/builder.go +++ b/builder/virtualbox/builder.go @@ -28,6 +28,7 @@ type config struct { DiskSize uint `mapstructure:"disk_size"` FloppyFiles []string `mapstructure:"floppy_files"` Format string `mapstructure:"format"` + GuestAdditionsAttach bool `mapstructure:"guest_additions_attach"` GuestAdditionsPath string `mapstructure:"guest_additions_path"` GuestAdditionsURL string `mapstructure:"guest_additions_url"` GuestAdditionsSHA256 string `mapstructure:"guest_additions_sha256"` @@ -361,6 +362,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe new(stepCreateVM), new(stepCreateDisk), new(stepAttachISO), + new(stepAttachGuestAdditions), new(stepAttachFloppy), new(stepForwardSSH), new(stepVBoxManage), diff --git a/builder/virtualbox/step_attach_guest_additions.go b/builder/virtualbox/step_attach_guest_additions.go new file mode 100644 index 000000000..9bbeb949a --- /dev/null +++ b/builder/virtualbox/step_attach_guest_additions.go @@ -0,0 +1,81 @@ +package virtualbox + +import ( + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" +) + +// This step attaches the VirtualBox guest additions as a inserted CD onto +// the virtual machine. +// +// Uses: +// config *config +// driver Driver +// guest_additions_path string +// ui packer.Ui +// vmName string +// +// Produces: +type stepAttachGuestAdditions struct { + attachedPath string +} + +func (s *stepAttachGuestAdditions) Run(state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(*config) + driver := state.Get("driver").(Driver) + guestAdditionsPath := state.Get("guest_additions_path").(string) + ui := state.Get("ui").(packer.Ui) + vmName := state.Get("vmName").(string) + + // If we're not attaching the guest additions then just return + if !config.GuestAdditionsAttach { + log.Println("Not attaching guest additions since we're uploading.") + return multistep.ActionContinue + } + + // Attach the guest additions to the computer + log.Println("Attaching guest additions ISO onto IDE controller...") + command := []string{ + "storageattach", vmName, + "--storagectl", "IDE Controller", + "--port", "1", + "--device", "0", + "--type", "dvddrive", + "--medium", guestAdditionsPath, + } + if err := driver.VBoxManage(command...); err != nil { + err := fmt.Errorf("Error attaching guest additions: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + // Track the path so that we can unregister it from VirtualBox later + s.attachedPath = guestAdditionsPath + + return multistep.ActionContinue +} + +func (s *stepAttachGuestAdditions) Cleanup(state multistep.StateBag) { + if s.attachedPath == "" { + return + } + + driver := state.Get("driver").(Driver) + ui := state.Get("ui").(packer.Ui) + vmName := state.Get("vmName").(string) + + command := []string{ + "storageattach", vmName, + "--storagectl", "IDE Controller", + "--port", "1", + "--device", "0", + "--medium", "none", + } + + if err := driver.VBoxManage(command...); err != nil { + ui.Error(fmt.Sprintf("Error unregistering guest additions: %s", err)) + } +} diff --git a/builder/virtualbox/step_upload_guest_additions.go b/builder/virtualbox/step_upload_guest_additions.go index 86b83b3c6..ff2252c86 100644 --- a/builder/virtualbox/step_upload_guest_additions.go +++ b/builder/virtualbox/step_upload_guest_additions.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" + "log" "os" ) @@ -21,6 +22,12 @@ func (s *stepUploadGuestAdditions) Run(state multistep.StateBag) multistep.StepA guestAdditionsPath := state.Get("guest_additions_path").(string) ui := state.Get("ui").(packer.Ui) + // If we're attaching then don't do this, since we attached. + if config.GuestAdditionsAttach { + log.Println("Not uploading guest additions since we're attaching.") + return multistep.ActionContinue + } + version, err := driver.Version() if err != nil { state.Put("error", fmt.Errorf("Error reading version for guest additions upload: %s", err)) diff --git a/website/source/docs/builders/virtualbox.html.markdown b/website/source/docs/builders/virtualbox.html.markdown index 75e6b1943..b10cd8cb0 100644 --- a/website/source/docs/builders/virtualbox.html.markdown +++ b/website/source/docs/builders/virtualbox.html.markdown @@ -85,6 +85,10 @@ Optional: * `format` (string) - Either "ovf" or "ova", this specifies the output format of the exported virtual machine. This defaults to "ovf". +* `guest_additions_attach` (bool) - If this is true (defaults to "false"), + the guest additions ISO will be attached to the virtual machine as a CD + rather than uploaded as a raw ISO. + * `guest_additions_path` (string) - The path on the guest virtual machine where the VirtualBox guest additions ISO will be uploaded. By default this is "VBoxGuestAdditions.iso" which should upload into the login directory