builder/virtualbox/common: Export

This commit is contained in:
Mitchell Hashimoto 2013-12-22 10:40:39 -08:00
parent 026bcd33fe
commit 5feb7bce18
8 changed files with 135 additions and 60 deletions

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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) {}

View File

@ -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")
}
}

View File

@ -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

View File

@ -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()

View File

@ -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.

View File

@ -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)...)