From 5b6cbeed1d8fc799ac69eb7c09bbed9a03b89a12 Mon Sep 17 00:00:00 2001 From: Andrew Pennebaker Date: Mon, 26 Feb 2018 10:47:59 -0600 Subject: [PATCH] expose `--iso` option down in `VBoxManage export --iso` up to virtualbox-iso configuration as "bundle_iso"; ensure ISOs are not removed when this is enabled. --- builder/virtualbox/common/step_export.go | 17 +++++++ .../virtualbox/common/step_remove_devices.go | 48 ++++++++++--------- .../virtualbox/common/vboxbundle_config.go | 13 +++++ .../common/vboxbundle_config_test.go | 35 ++++++++++++++ builder/virtualbox/iso/builder.go | 7 ++- .../docs/builders/virtualbox-iso.html.md.erb | 5 ++ 6 files changed, 102 insertions(+), 23 deletions(-) create mode 100644 builder/virtualbox/common/vboxbundle_config.go create mode 100644 builder/virtualbox/common/vboxbundle_config_test.go diff --git a/builder/virtualbox/common/step_export.go b/builder/virtualbox/common/step_export.go index 03b02e8e4..d633ee89e 100644 --- a/builder/virtualbox/common/step_export.go +++ b/builder/virtualbox/common/step_export.go @@ -22,11 +22,28 @@ type StepExport struct { Format string OutputDir string ExportOpts []string + Bundling VBoxBundleConfig SkipNatMapping bool SkipExport bool } func (s *StepExport) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + // If ISO export is configured, ensure this option is propagated to VBoxManage. + if s.Bundling.BundleISO { + foundISOOption := false + + for _, option := range s.ExportOpts { + if option == "--iso" || option == "-I" { + foundISOOption = true + break + } + } + + if !foundISOOption { + s.ExportOpts = append(s.ExportOpts, "--iso") + } + } + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) diff --git a/builder/virtualbox/common/step_remove_devices.go b/builder/virtualbox/common/step_remove_devices.go index 835fd5af8..306243721 100644 --- a/builder/virtualbox/common/step_remove_devices.go +++ b/builder/virtualbox/common/step_remove_devices.go @@ -19,7 +19,9 @@ import ( // vmName string // // Produces: -type StepRemoveDevices struct{} +type StepRemoveDevices struct{ + Bundling VBoxBundleConfig +} func (s *StepRemoveDevices) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(Driver) @@ -68,29 +70,31 @@ func (s *StepRemoveDevices) Run(_ context.Context, state multistep.StateBag) mul } } - if _, ok := state.GetOk("attachedIso"); ok { - controllerName := "IDE Controller" - port := "0" - device := "1" - if _, ok := state.GetOk("attachedIsoOnSata"); ok { - controllerName = "SATA Controller" - port = "1" - device = "0" - } + if !s.Bundling.BundleISO { + if _, ok := state.GetOk("attachedIso"); ok { + controllerName := "IDE Controller" + port := "0" + device := "1" + if _, ok := state.GetOk("attachedIsoOnSata"); ok { + controllerName = "SATA Controller" + port = "1" + device = "0" + } - command := []string{ - "storageattach", vmName, - "--storagectl", controllerName, - "--port", port, - "--device", device, - "--medium", "none", - } + command := []string{ + "storageattach", vmName, + "--storagectl", controllerName, + "--port", port, + "--device", device, + "--medium", "none", + } - if err := driver.VBoxManage(command...); err != nil { - err := fmt.Errorf("Error detaching ISO: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt + if err := driver.VBoxManage(command...); err != nil { + err := fmt.Errorf("Error detaching ISO: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } } } diff --git a/builder/virtualbox/common/vboxbundle_config.go b/builder/virtualbox/common/vboxbundle_config.go new file mode 100644 index 000000000..9b4ad3391 --- /dev/null +++ b/builder/virtualbox/common/vboxbundle_config.go @@ -0,0 +1,13 @@ +package common + +import ( + "github.com/hashicorp/packer/template/interpolate" +) + +type VBoxBundleConfig struct { + BundleISO bool `mapstructure:"bundle_iso"` +} + +func (c *VBoxBundleConfig) Prepare(ctx *interpolate.Context) []error { + return nil +} diff --git a/builder/virtualbox/common/vboxbundle_config_test.go b/builder/virtualbox/common/vboxbundle_config_test.go new file mode 100644 index 000000000..8aa9833fb --- /dev/null +++ b/builder/virtualbox/common/vboxbundle_config_test.go @@ -0,0 +1,35 @@ +package common + +import ( + "reflect" + "testing" +) + +func TestVBoxBundleConfigPrepare_VBoxBundle(t *testing.T) { + // Test with empty + c := new(VBoxBundleConfig) + errs := c.Prepare(testConfigTemplate(t)) + if len(errs) > 0 { + t.Fatalf("err: %#v", errs) + } + + if !reflect.DeepEqual(c, VBoxBundleConfig{BundleISO: false}) { + t.Fatalf("bad: %#v", c.VBoxBundle) + } + + // Test with a good one + c = new(VBoxBundleConfig) + c.BundleISO = true + errs = c.Prepare(testConfigTemplate(t)) + if len(errs) > 0 { + t.Fatalf("err: %#v", errs) + } + + expected := VBoxBundleConfig{ + BundleISO: true, + } + + if !reflect.DeepEqual(c, expected) { + t.Fatalf("bad: %#v", c) + } +} diff --git a/builder/virtualbox/iso/builder.go b/builder/virtualbox/iso/builder.go index cb8813896..603a36aa8 100644 --- a/builder/virtualbox/iso/builder.go +++ b/builder/virtualbox/iso/builder.go @@ -39,6 +39,7 @@ type Config struct { vboxcommon.VBoxManageConfig `mapstructure:",squash"` vboxcommon.VBoxManagePostConfig `mapstructure:",squash"` vboxcommon.VBoxVersionConfig `mapstructure:",squash"` + vboxcommon.VBoxBundleConfig `mapstructure:",squash"` DiskSize uint `mapstructure:"disk_size"` GuestAdditionsMode string `mapstructure:"guest_additions_mode"` @@ -94,6 +95,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.HWConfig.Prepare(&b.config.ctx)...) + errs = packer.MultiErrorAppend(errs, b.config.VBoxBundleConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.VBoxManageConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.VBoxManagePostConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.VBoxVersionConfig.Prepare(&b.config.ctx)...) @@ -277,7 +279,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe Timeout: b.config.ShutdownTimeout, Delay: b.config.PostShutdownDelay, }, - new(vboxcommon.StepRemoveDevices), + &vboxcommon.StepRemoveDevices{ + Bundling: b.config.VBoxBundleConfig, + }, &vboxcommon.StepVBoxManage{ Commands: b.config.VBoxManagePost, Ctx: b.config.ctx, @@ -286,6 +290,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe Format: b.config.Format, OutputDir: b.config.OutputDir, ExportOpts: b.config.ExportOpts.ExportOpts, + Bundling: b.config.VBoxBundleConfig, SkipNatMapping: b.config.SSHSkipNatMapping, SkipExport: b.config.SkipExport, }, diff --git a/website/source/docs/builders/virtualbox-iso.html.md.erb b/website/source/docs/builders/virtualbox-iso.html.md.erb index 9fca33b6f..2de4cd132 100644 --- a/website/source/docs/builders/virtualbox-iso.html.md.erb +++ b/website/source/docs/builders/virtualbox-iso.html.md.erb @@ -316,6 +316,11 @@ builder. except that it is run after the virtual machine is shutdown, and before the virtual machine is exported. +- `bundle_iso` (boolean) - Defaults to `false`. When enabled, Packer includes + any attached ISO disc devices into the final virtual machine. Useful for + some live distributions that require installation media to continue to be + attached after installation. + - `virtualbox_version_file` (string) - The path within the virtual machine to upload a file that contains the VirtualBox version that was used to create the machine. This information can be useful for provisioning. By default