Merge branch 'rasa-1082-add-boot-commands-to-vmx-and-ovf-builders'

This commit is contained in:
Mitchell Hashimoto 2014-09-05 11:42:11 -07:00
commit 118e0b8afd
15 changed files with 92 additions and 32 deletions

View File

@ -1,9 +1,8 @@
package iso package common
import ( import (
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
vboxcommon "github.com/mitchellh/packer/builder/virtualbox/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
"strings" "strings"
@ -23,7 +22,6 @@ type bootCommandTemplateData struct {
// This step "types" the boot command into the VM over VNC. // This step "types" the boot command into the VM over VNC.
// //
// Uses: // Uses:
// config *config
// driver Driver // driver Driver
// http_port int // http_port int
// ui packer.Ui // ui packer.Ui
@ -31,11 +29,14 @@ type bootCommandTemplateData struct {
// //
// Produces: // Produces:
// <nothing> // <nothing>
type stepTypeBootCommand struct{} type StepTypeBootCommand struct {
BootCommand []string
VMName string
Tpl *packer.ConfigTemplate
}
func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction { func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*config) driver := state.Get("driver").(Driver)
driver := state.Get("driver").(vboxcommon.Driver)
httpPort := state.Get("http_port").(uint) httpPort := state.Get("http_port").(uint)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
vmName := state.Get("vmName").(string) vmName := state.Get("vmName").(string)
@ -43,12 +44,12 @@ func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
tplData := &bootCommandTemplateData{ tplData := &bootCommandTemplateData{
"10.0.2.2", "10.0.2.2",
httpPort, httpPort,
config.VMName, s.VMName,
} }
ui.Say("Typing the boot command...") ui.Say("Typing the boot command...")
for _, command := range config.BootCommand { for _, command := range s.BootCommand {
command, err := config.tpl.Process(command, tplData) command, err := s.Tpl.Process(command, tplData)
if err != nil { if err != nil {
err := fmt.Errorf("Error preparing boot command: %s", err) err := fmt.Errorf("Error preparing boot command: %s", err)
state.Put("error", err) state.Put("error", err)
@ -90,7 +91,7 @@ func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
return multistep.ActionContinue return multistep.ActionContinue
} }
func (*stepTypeBootCommand) Cleanup(multistep.StateBag) {} func (*StepTypeBootCommand) Cleanup(multistep.StateBag) {}
func scancodes(message string) []string { func scancodes(message string) []string {
// Scancodes reference: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html // Scancodes reference: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html

View File

@ -320,7 +320,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
BootWait: b.config.BootWait, BootWait: b.config.BootWait,
Headless: b.config.Headless, Headless: b.config.Headless,
}, },
new(stepTypeBootCommand), &vboxcommon.StepTypeBootCommand{
BootCommand: b.config.BootCommand,
VMName: b.config.VMName,
Tpl: b.config.tpl,
},
&common.StepConnectSSH{ &common.StepConnectSSH{
SSHAddress: vboxcommon.SSHAddress, SSHAddress: vboxcommon.SSHAddress,
SSHConfig: vboxcommon.SSHConfigFunc(b.config.SSHConfig), SSHConfig: vboxcommon.SSHConfigFunc(b.config.SSHConfig),

View File

@ -89,6 +89,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
BootWait: b.config.BootWait, BootWait: b.config.BootWait,
Headless: b.config.Headless, Headless: b.config.Headless,
}, },
&vboxcommon.StepTypeBootCommand{
BootCommand: b.config.BootCommand,
VMName: b.config.VMName,
Tpl: b.config.tpl,
},
&common.StepConnectSSH{ &common.StepConnectSSH{
SSHAddress: vboxcommon.SSHAddress, SSHAddress: vboxcommon.SSHAddress,
SSHConfig: vboxcommon.SSHConfigFunc(b.config.SSHConfig), SSHConfig: vboxcommon.SSHConfigFunc(b.config.SSHConfig),

View File

@ -24,6 +24,7 @@ type Config struct {
vboxcommon.VBoxManagePostConfig `mapstructure:",squash"` vboxcommon.VBoxManagePostConfig `mapstructure:",squash"`
vboxcommon.VBoxVersionConfig `mapstructure:",squash"` vboxcommon.VBoxVersionConfig `mapstructure:",squash"`
BootCommand []string `mapstructure:"boot_command"`
SourcePath string `mapstructure:"source_path"` SourcePath string `mapstructure:"source_path"`
GuestAdditionsMode string `mapstructure:"guest_additions_mode"` GuestAdditionsMode string `mapstructure:"guest_additions_mode"`
GuestAdditionsPath string `mapstructure:"guest_additions_path"` GuestAdditionsPath string `mapstructure:"guest_additions_path"`
@ -115,6 +116,13 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
} }
} }
for i, command := range c.BootCommand {
if err := c.tpl.Validate(command); err != nil {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Error processing boot_command[%d]: %s", i, err))
}
}
validates := map[string]*string{ validates := map[string]*string{
"guest_additions_path": &c.GuestAdditionsPath, "guest_additions_path": &c.GuestAdditionsPath,
"guest_additions_url": &c.GuestAdditionsURL, "guest_additions_url": &c.GuestAdditionsURL,

View File

@ -1,4 +1,4 @@
package iso package common
// Interface to help find the host IP that is available from within // Interface to help find the host IP that is available from within
// the VMware virtual machines. // the VMware virtual machines.

View File

@ -1,4 +1,4 @@
package iso package common
import ( import (
"bytes" "bytes"

View File

@ -1,4 +1,4 @@
package iso package common
import "testing" import "testing"

View File

@ -1,4 +1,4 @@
package iso package common
import ( import (
"bufio" "bufio"
@ -8,8 +8,6 @@ import (
"os" "os"
"regexp" "regexp"
"strings" "strings"
vmwcommon "github.com/mitchellh/packer/builder/vmware/common"
) )
// VMnetNatConfIPFinder finds the IP address of the host machine by // VMnetNatConfIPFinder finds the IP address of the host machine by
@ -18,7 +16,7 @@ import (
type VMnetNatConfIPFinder struct{} type VMnetNatConfIPFinder struct{}
func (*VMnetNatConfIPFinder) HostIP() (string, error) { func (*VMnetNatConfIPFinder) HostIP() (string, error) {
driver := &vmwcommon.Workstation9Driver{} driver := &Workstation9Driver{}
vmnetnat := driver.VmnetnatConfPath() vmnetnat := driver.VmnetnatConfPath()
if vmnetnat == "" { if vmnetnat == "" {

View File

@ -1,4 +1,4 @@
package iso package common
import "testing" import "testing"

View File

@ -1,10 +1,9 @@
package iso package common
import ( import (
"fmt" "fmt"
"github.com/mitchellh/go-vnc" "github.com/mitchellh/go-vnc"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
vmwcommon "github.com/mitchellh/packer/builder/vmware/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
"net" "net"
@ -26,18 +25,20 @@ type bootCommandTemplateData struct {
// This step "types" the boot command into the VM over VNC. // This step "types" the boot command into the VM over VNC.
// //
// Uses: // Uses:
// config *config
// http_port int // http_port int
// ui packer.Ui // ui packer.Ui
// vnc_port uint // vnc_port uint
// //
// Produces: // Produces:
// <nothing> // <nothing>
type stepTypeBootCommand struct{} type StepTypeBootCommand struct {
BootCommand []string
VMName string
Tpl *packer.ConfigTemplate
}
func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction { func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*config) driver := state.Get("driver").(Driver)
driver := state.Get("driver").(vmwcommon.Driver)
httpPort := state.Get("http_port").(uint) httpPort := state.Get("http_port").(uint)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
vncIp := state.Get("vnc_ip").(string) vncIp := state.Get("vnc_ip").(string)
@ -88,12 +89,12 @@ func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
tplData := &bootCommandTemplateData{ tplData := &bootCommandTemplateData{
hostIp, hostIp,
httpPort, httpPort,
config.VMName, s.VMName,
} }
ui.Say("Typing the boot command over VNC...") ui.Say("Typing the boot command over VNC...")
for _, command := range config.BootCommand { for _, command := range s.BootCommand {
command, err := config.tpl.Process(command, tplData) command, err := s.Tpl.Process(command, tplData)
if err != nil { if err != nil {
err := fmt.Errorf("Error preparing boot command: %s", err) err := fmt.Errorf("Error preparing boot command: %s", err)
state.Put("error", err) state.Put("error", err)
@ -113,7 +114,7 @@ func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
return multistep.ActionContinue return multistep.ActionContinue
} }
func (*stepTypeBootCommand) Cleanup(multistep.StateBag) {} func (*StepTypeBootCommand) Cleanup(multistep.StateBag) {}
func vncSendString(c *vnc.ClientConn, original string) { func vncSendString(c *vnc.ClientConn, original string) {
// Scancodes reference: https://github.com/qemu/qemu/blob/master/ui/vnc_keysym.h // Scancodes reference: https://github.com/qemu/qemu/blob/master/ui/vnc_keysym.h

View File

@ -348,7 +348,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
DurationBeforeStop: 5 * time.Second, DurationBeforeStop: 5 * time.Second,
Headless: b.config.Headless, Headless: b.config.Headless,
}, },
&stepTypeBootCommand{}, &vmwcommon.StepTypeBootCommand{
BootCommand: b.config.BootCommand,
VMName: b.config.VMName,
Tpl: b.config.tpl,
},
&common.StepConnectSSH{ &common.StepConnectSSH{
SSHAddress: driver.SSHAddress, SSHAddress: driver.SSHAddress,
SSHConfig: vmwcommon.SSHConfigFunc(&b.config.SSHConfig), SSHConfig: vmwcommon.SSHConfigFunc(&b.config.SSHConfig),

View File

@ -76,6 +76,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
DurationBeforeStop: 5 * time.Second, DurationBeforeStop: 5 * time.Second,
Headless: b.config.Headless, Headless: b.config.Headless,
}, },
&vmwcommon.StepTypeBootCommand{
BootCommand: b.config.BootCommand,
VMName: b.config.VMName,
Tpl: b.config.tpl,
},
&common.StepConnectSSH{ &common.StepConnectSSH{
SSHAddress: driver.SSHAddress, SSHAddress: driver.SSHAddress,
SSHConfig: vmwcommon.SSHConfigFunc(&b.config.SSHConfig), SSHConfig: vmwcommon.SSHConfigFunc(&b.config.SSHConfig),

View File

@ -20,6 +20,7 @@ type Config struct {
vmwcommon.ToolsConfig `mapstructure:",squash"` vmwcommon.ToolsConfig `mapstructure:",squash"`
vmwcommon.VMXConfig `mapstructure:",squash"` vmwcommon.VMXConfig `mapstructure:",squash"`
BootCommand []string `mapstructure:"boot_command"`
FloppyFiles []string `mapstructure:"floppy_files"` FloppyFiles []string `mapstructure:"floppy_files"`
RemoteType string `mapstructure:"remote_type"` RemoteType string `mapstructure:"remote_type"`
SkipCompaction bool `mapstructure:"skip_compaction"` SkipCompaction bool `mapstructure:"skip_compaction"`
@ -82,6 +83,13 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
} }
} }
for i, command := range c.BootCommand {
if err := c.tpl.Validate(command); err != nil {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Error processing boot_command[%d]: %s", i, err))
}
}
if c.SourcePath == "" { if c.SourcePath == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is required")) errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is required"))
} else { } else {

View File

@ -52,6 +52,19 @@ each category, the available options are alphabetized and described.
### Optional: ### Optional:
* `boot_command` (array of strings) - This is an array of commands to type
when the virtual machine is first booted. The goal of these commands should
be to type just enough to initialize the operating system installer. Special
keys can be typed as well, and are covered in the section below on the boot
command. If this is not specified, it is assumed the installer will start
itself.
* `boot_wait` (string) - The time to wait after booting the initial virtual
machine before typing the `boot_command`. The value of this should be
a duration. Examples are "5s" and "1m30s" which will cause Packer to wait
five seconds and one minute 30 seconds, respectively. If this isn't specified,
the default is 10 seconds.
* `export_opts` (array of strings) - Additional options to pass to the `VBoxManage export`. * `export_opts` (array of strings) - Additional options to pass to the `VBoxManage export`.
This can be useful for passing product information to include in the resulting This can be useful for passing product information to include in the resulting
appliance file. appliance file.

View File

@ -51,6 +51,19 @@ each category, the available options are alphabetized and described.
### Optional: ### Optional:
* `boot_command` (array of strings) - This is an array of commands to type
when the virtual machine is firsted booted. The goal of these commands should
be to type just enough to initialize the operating system installer. Special
keys can be typed as well, and are covered in the section below on the boot
command. If this is not specified, it is assumed the installer will start
itself.
* `boot_wait` (string) - The time to wait after booting the initial virtual
machine before typing the `boot_command`. The value of this should be
a duration. Examples are "5s" and "1m30s" which will cause Packer to wait
five seconds and one minute 30 seconds, respectively. If this isn't specified,
the default is 10 seconds.
* `floppy_files` (array of strings) - A list of files to place onto a floppy * `floppy_files` (array of strings) - A list of files to place onto a floppy
disk that is attached when the VM is booted. This is most useful disk that is attached when the VM is booted. This is most useful
for unattended Windows installs, which look for an `Autounattend.xml` file for unattended Windows installs, which look for an `Autounattend.xml` file