Commit a3bd9ecd authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

builder/virtualbox: add "vboxmanage" to run custom commands

parent 53b7b396
......@@ -43,6 +43,7 @@ type config struct {
SSHPort uint `mapstructure:"ssh_port"`
SSHUser string `mapstructure:"ssh_username"`
SSHWaitTimeout time.Duration ``
VBoxManage [][]string `mapstructure:"vboxmanage"`
VMName string `mapstructure:"vm_name"`
PackerDebug bool `mapstructure:"packer_debug"`
......@@ -94,6 +95,10 @@ func (b *Builder) Prepare(raws ...interface{}) error {
b.config.SSHPort = 22
}
if b.config.VBoxManage == nil {
b.config.VBoxManage = make([][]string, 0)
}
if b.config.VMName == "" {
b.config.VMName = "packer"
}
......@@ -204,6 +209,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
new(stepCreateDisk),
new(stepAttachISO),
new(stepForwardSSH),
new(stepVBoxManage),
new(stepRun),
new(stepTypeBootCommand),
new(stepWaitForSSH),
......
......@@ -4,6 +4,7 @@ import (
"github.com/mitchellh/packer/packer"
"io/ioutil"
"os"
"reflect"
"testing"
)
......@@ -279,3 +280,38 @@ func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
t.Fatalf("should not have error: %s", err)
}
}
func TestBuilderPrepare_VBoxManage(t *testing.T) {
var b Builder
config := testConfig()
// Test with empty
delete(config, "vboxmanage")
err := b.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
if !reflect.DeepEqual(b.config.VBoxManage, [][]string{}) {
t.Fatalf("bad: %#v", b.config.VBoxManage)
}
// Test with a good one
config["vboxmanage"] = [][]interface{}{
[]interface{}{"foo", "bar", "baz"},
}
b = Builder{}
err = b.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
expected := [][]string{
[]string{"foo", "bar", "baz"},
}
if !reflect.DeepEqual(b.config.VBoxManage, expected) {
t.Fatalf("bad: %#v", b.config.VBoxManage)
}
}
package virtualbox
import (
"bytes"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"strings"
"text/template"
)
type commandTemplate struct {
Name string
}
// This step executes additional VBoxManage commands as specified by the
// template.
//
// Uses:
//
// Produces:
type stepVBoxManage struct{}
func (s *stepVBoxManage) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(*config)
driver := state["driver"].(Driver)
ui := state["ui"].(packer.Ui)
vmName := state["vmName"].(string)
if len(config.VBoxManage) > 0 {
ui.Say("Executing custom VBoxManage commands...")
}
tplData := &commandTemplate{
Name: vmName,
}
for _, originalCommand := range config.VBoxManage {
command := make([]string, len(originalCommand))
copy(command, originalCommand)
for i, arg := range command {
var buf bytes.Buffer
t := template.Must(template.New("arg").Parse(arg))
t.Execute(&buf, tplData)
command[i] = buf.String()
}
ui.Say(fmt.Sprintf("Executing: %s", strings.Join(command, " ")))
if err := driver.VBoxManage(command...); err != nil {
err := fmt.Errorf("Error executing command: %s", err)
state["error"] = err
ui.Error(err.Error())
return multistep.ActionHalt
}
}
return multistep.ActionContinue
}
func (s *stepVBoxManage) Cleanup(state map[string]interface{}) {}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment