diff --git a/builder/virtualbox/common/export_config.go b/builder/virtualbox/common/export_config.go new file mode 100644 index 000000000..364d86a84 --- /dev/null +++ b/builder/virtualbox/common/export_config.go @@ -0,0 +1,37 @@ +package common + +import ( + "errors" + "fmt" + "github.com/mitchellh/packer/packer" +) + +type ExportConfig struct { + Format string `mapstruture:"format"` +} + +func (c *ExportConfig) Prepare(t *packer.ConfigTemplate) []error { + if c.Format == "" { + c.Format = "ovf" + } + + templates := map[string]*string{ + "format": &c.Format, + } + + errs := make([]error, 0) + for n, ptr := range templates { + var err error + *ptr, err = t.Process(*ptr, nil) + if err != nil { + errs = append(errs, fmt.Errorf("Error processing %s: %s", n, err)) + } + } + + if c.Format != "ovf" && c.Format != "ova" { + errs = append(errs, + errors.New("invalid format, only 'ovf' or 'ova' are allowed")) + } + + return errs +} diff --git a/builder/virtualbox/common/export_config_test.go b/builder/virtualbox/common/export_config_test.go new file mode 100644 index 000000000..612bfc01d --- /dev/null +++ b/builder/virtualbox/common/export_config_test.go @@ -0,0 +1,34 @@ +package common + +import ( + "testing" +) + +func TestExportConfigPrepare_BootWait(t *testing.T) { + var c *ExportConfig + var errs []error + + // Bad + c = new(ExportConfig) + c.Format = "illega" + errs = c.Prepare(testConfigTemplate(t)) + if len(errs) == 0 { + t.Fatalf("bad: %#v", errs) + } + + // Good + c = new(ExportConfig) + c.Format = "ova" + errs = c.Prepare(testConfigTemplate(t)) + if len(errs) > 0 { + t.Fatalf("should not have error: %s", errs) + } + + // Good + c = new(ExportConfig) + c.Format = "ovf" + errs = c.Prepare(testConfigTemplate(t)) + if len(errs) > 0 { + t.Fatalf("should not have error: %s", errs) + } +} diff --git a/builder/virtualbox/iso/step_export.go b/builder/virtualbox/common/step_export.go similarity index 78% rename from builder/virtualbox/iso/step_export.go rename to builder/virtualbox/common/step_export.go index 5e5f5e8f6..c5dc208b2 100644 --- a/builder/virtualbox/iso/step_export.go +++ b/builder/virtualbox/common/step_export.go @@ -1,9 +1,8 @@ -package iso +package common import ( "fmt" "github.com/mitchellh/multistep" - vboxcommon "github.com/mitchellh/packer/builder/virtualbox/common" "github.com/mitchellh/packer/packer" "log" "path/filepath" @@ -16,11 +15,13 @@ import ( // // Produces: // exportPath string - The path to the resulting export. -type stepExport struct{} +type StepExport struct { + Format string + OutputDir string +} -func (s *stepExport) Run(state multistep.StateBag) multistep.StepAction { - config := state.Get("config").(*config) - driver := state.Get("driver").(vboxcommon.Driver) +func (s *StepExport) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) @@ -42,7 +43,7 @@ func (s *stepExport) Run(state multistep.StateBag) multistep.StepAction { } // Export the VM to an OVF - outputPath := filepath.Join(config.OutputDir, vmName+"."+config.Format) + outputPath := filepath.Join(s.OutputDir, vmName+"."+s.Format) command = []string{ "export", @@ -65,4 +66,4 @@ func (s *stepExport) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } -func (s *stepExport) Cleanup(state multistep.StateBag) {} +func (s *StepExport) Cleanup(state multistep.StateBag) {} diff --git a/builder/virtualbox/common/step_export_test.go b/builder/virtualbox/common/step_export_test.go new file mode 100644 index 000000000..0a939d331 --- /dev/null +++ b/builder/virtualbox/common/step_export_test.go @@ -0,0 +1,43 @@ +package common + +import ( + "github.com/mitchellh/multistep" + "testing" +) + +func TestStepExport_impl(t *testing.T) { + var _ multistep.Step = new(StepExport) +} + +func TestStepExport(t *testing.T) { + state := testState(t) + step := new(StepExport) + + state.Put("vmName", "foo") + + driver := state.Get("driver").(*DriverMock) + + // Test the run + if action := step.Run(state); action != multistep.ActionContinue { + t.Fatalf("bad action: %#v", action) + } + if _, ok := state.GetOk("error"); ok { + t.Fatal("should NOT have error") + } + + // Test output state + if _, ok := state.GetOk("exportPath"); !ok { + t.Fatal("should set exportPath") + } + + // Test driver + if len(driver.VBoxManageCalls) != 2 { + t.Fatal("should call vboxmanage") + } + if driver.VBoxManageCalls[0][0] != "modifyvm" { + t.Fatal("bad") + } + if driver.VBoxManageCalls[1][0] != "export" { + t.Fatal("bad") + } +} diff --git a/builder/virtualbox/iso/builder.go b/builder/virtualbox/iso/builder.go index 86a351ae6..8ea630695 100644 --- a/builder/virtualbox/iso/builder.go +++ b/builder/virtualbox/iso/builder.go @@ -28,6 +28,7 @@ type Builder struct { type config struct { common.PackerConfig `mapstructure:",squash"` + vboxcommon.ExportConfig `mapstructure:",squash"` vboxcommon.FloppyConfig `mapstructure:",squash"` vboxcommon.OutputConfig `mapstructure:",squash"` vboxcommon.RunConfig `mapstructure:",squash"` @@ -37,7 +38,6 @@ type config struct { BootCommand []string `mapstructure:"boot_command"` DiskSize uint `mapstructure:"disk_size"` - Format string `mapstructure:"format"` GuestAdditionsMode string `mapstructure:"guest_additions_mode"` GuestAdditionsPath string `mapstructure:"guest_additions_path"` GuestAdditionsURL string `mapstructure:"guest_additions_url"` @@ -72,6 +72,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { // Accumulate any errors and warnings errs := common.CheckUnusedConfig(md) + errs = packer.MultiErrorAppend(errs, b.config.ExportConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.FloppyConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend( errs, b.config.OutputConfig.Prepare(b.config.tpl, &b.config.PackerConfig)...) @@ -116,10 +117,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { b.config.VMName = fmt.Sprintf("packer-%s", b.config.PackerBuildName) } - if b.config.Format == "" { - b.config.Format = "ovf" - } - // Errors templates := map[string]*string{ "guest_additions_mode": &b.config.GuestAdditionsMode, @@ -132,7 +129,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { "iso_url": &b.config.RawSingleISOUrl, "virtualbox_version_file": &b.config.VBoxVersionFile, "vm_name": &b.config.VMName, - "format": &b.config.Format, } for n, ptr := range templates { @@ -172,11 +168,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { } } - if !(b.config.Format == "ovf" || b.config.Format == "ova") { - errs = packer.MultiErrorAppend( - errs, errors.New("invalid format, only 'ovf' or 'ova' are allowed")) - } - if b.config.HardDriveInterface != "ide" && b.config.HardDriveInterface != "sata" { errs = packer.MultiErrorAppend( errs, errors.New("hard_drive_interface can only be ide or sata")) @@ -317,7 +308,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe Timeout: b.config.ShutdownTimeout, }, new(vboxcommon.StepRemoveDevices), - new(stepExport), + &vboxcommon.StepExport{ + Format: b.config.Format, + OutputDir: b.config.OutputDir, + }, } // Setup the state bag diff --git a/builder/virtualbox/iso/builder_test.go b/builder/virtualbox/iso/builder_test.go index fa60e482b..50d075999 100644 --- a/builder/virtualbox/iso/builder_test.go +++ b/builder/virtualbox/iso/builder_test.go @@ -299,43 +299,6 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) { } } -func TestBuilderPrepare_Format(t *testing.T) { - var b Builder - config := testConfig() - - // Bad - config["format"] = "illegal value" - warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } - - // Good - config["format"] = "ova" - b = Builder{} - warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - // Good - config["format"] = "ovf" - b = Builder{} - warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } -} - func TestBuilderPrepare_InvalidKey(t *testing.T) { var b Builder config := testConfig() diff --git a/builder/virtualbox/ovf/builder.go b/builder/virtualbox/ovf/builder.go index 2317a4601..a8cb3b903 100644 --- a/builder/virtualbox/ovf/builder.go +++ b/builder/virtualbox/ovf/builder.go @@ -81,9 +81,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe Timeout: b.config.ShutdownTimeout, }, new(vboxcommon.StepRemoveDevices), - /* - new(stepExport), - */ + &vboxcommon.StepExport{ + Format: b.config.Format, + OutputDir: b.config.OutputDir, + }, } // Run the steps. diff --git a/builder/virtualbox/ovf/config.go b/builder/virtualbox/ovf/config.go index 929bb24a5..2c2442bc8 100644 --- a/builder/virtualbox/ovf/config.go +++ b/builder/virtualbox/ovf/config.go @@ -9,6 +9,7 @@ import ( // Config is the configuration structure for the builder. type Config struct { common.PackerConfig `mapstructure:",squash"` + vboxcommon.ExportConfig `mapstructure:",squash"` vboxcommon.FloppyConfig `mapstructure:",squash"` vboxcommon.OutputConfig `mapstructure:",squash"` vboxcommon.RunConfig `mapstructure:",squash"` @@ -34,6 +35,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { // Prepare the errors errs := common.CheckUnusedConfig(md) + errs = packer.MultiErrorAppend(errs, c.ExportConfig.Prepare(c.tpl)...) errs = packer.MultiErrorAppend(errs, c.FloppyConfig.Prepare(c.tpl)...) errs = packer.MultiErrorAppend(errs, c.OutputConfig.Prepare(c.tpl, &c.PackerConfig)...) errs = packer.MultiErrorAppend(errs, c.RunConfig.Prepare(c.tpl)...)