diff --git a/builder/virtualbox/builder.go b/builder/virtualbox/builder.go index 10a7dfa57..a53f97de6 100644 --- a/builder/virtualbox/builder.go +++ b/builder/virtualbox/builder.go @@ -1,15 +1,18 @@ package virtualbox import ( + "fmt" "github.com/mitchellh/mapstructure" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" + "log" ) const BuilderId = "mitchellh.virtualbox" type Builder struct { config config + driver Driver runner multistep.Runner } @@ -18,16 +21,63 @@ type config struct { } func (b *Builder) Prepare(raw interface{}) error { + var err error if err := mapstructure.Decode(raw, &b.config); err != nil { return err } + if b.config.OutputDir == "" { + b.config.OutputDir = "virtualbox" + } + + errs := make([]error, 0) + + b.driver, err = b.newDriver() + if err != nil { + errs = append(errs, fmt.Errorf("Failed creating VirtualBox driver: %s", err)) + } + + if len(errs) > 0 { + return &packer.MultiError{errs} + } + return nil } func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) packer.Artifact { + steps := []multistep.Step{ + new(stepPrepareOutputDir), + new(stepSuppressMessages), + } + + // Setup the state bag + state := make(map[string]interface{}) + state["cache"] = cache + state["config"] = &b.config + state["driver"] = b.driver + state["hook"] = hook + state["ui"] = ui + + // Run + b.runner = &multistep.BasicRunner{Steps: steps} + b.runner.Run(state) + return nil } func (b *Builder) Cancel() { + if b.runner != nil { + log.Println("Cancelling the step runner...") + b.runner.Cancel() + } +} + +func (b *Builder) newDriver() (Driver, error) { + vboxmanagePath := "VBoxManage" + driver := &VBox42Driver{vboxmanagePath} + if err := driver.Verify(); err != nil { + return nil, err + } + + return driver, nil } diff --git a/builder/virtualbox/driver.go b/builder/virtualbox/driver.go new file mode 100644 index 000000000..d01a22b32 --- /dev/null +++ b/builder/virtualbox/driver.go @@ -0,0 +1,53 @@ +package virtualbox + +import ( + "log" + "os/exec" +) + +// A driver is able to talk to VirtualBox and perform certain +// operations with it. +type Driver interface { + // SuppressMessages should do what needs to be done in order to + // suppress any annoying popups from VirtualBox. + SuppressMessages() error + + // Verify checks to make sure that this driver should function + // properly. If there is any indication the driver can't function, + // this will return an error. + Verify() error +} + +type VBox42Driver struct { + // This is the path to the "VBoxManage" application. + VBoxManagePath string +} + +func (d *VBox42Driver) SuppressMessages() error { + extraData := map[string]string{ + "GUI/RegistrationData": "triesLeft=0", + "GUI/SuppressMessages": "confirmInputCapture,remindAboutAutoCapture,remindAboutMouseIntegrationOff,remindAboutMouseIntegrationOn,remindAboutWrongColorDepth", + } + + for k, v := range extraData { + if err := d.vboxmanage("setextradata", "global", k, v); err != nil { + return err + } + } + + return nil +} + +func (d *VBox42Driver) Verify() error { + return nil +} + +func (d *VBox42Driver) vboxmanage(args ...string) error { + log.Printf("Executing VBoxManage: %#v", args) + cmd := exec.Command(d.VBoxManagePath, args...) + if err := cmd.Run(); err != nil { + return err + } + + return nil +} diff --git a/builder/virtualbox/step_prepare_output_dir.go b/builder/virtualbox/step_prepare_output_dir.go new file mode 100644 index 000000000..86213cb2d --- /dev/null +++ b/builder/virtualbox/step_prepare_output_dir.go @@ -0,0 +1,20 @@ +package virtualbox + +import ( + "github.com/mitchellh/multistep" + "os" +) + +type stepPrepareOutputDir struct{} + +func (stepPrepareOutputDir) Run(state map[string]interface{}) multistep.StepAction { + config := state["config"].(*config) + + if err := os.MkdirAll(config.OutputDir, 0755); err != nil { + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (stepPrepareOutputDir) Cleanup(map[string]interface{}) {} diff --git a/builder/virtualbox/step_suppress_messages.go b/builder/virtualbox/step_suppress_messages.go new file mode 100644 index 000000000..4197e47d6 --- /dev/null +++ b/builder/virtualbox/step_suppress_messages.go @@ -0,0 +1,27 @@ +package virtualbox + +import ( + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" +) + +// This step sets some variables in VirtualBox so that annoying +// pop-up messages don't exist. +type stepSuppressMessages struct{} + +func (stepSuppressMessages) Run(state map[string]interface{}) multistep.StepAction { + driver := state["driver"].(Driver) + ui := state["ui"].(packer.Ui) + + log.Println("Suppressing annoying messages in VirtualBox") + if err := driver.SuppressMessages(); err != nil { + ui.Error(fmt.Sprintf("Error configuring VirtualBox to suppress messages: %s", err)) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (stepSuppressMessages) Cleanup(map[string]interface{}) {}