Commit c74f0c7c authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

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

Merge branch '1082-add-boot-commands-to-vmx-and-ovf-builders' of github.com:rasa/packer into rasa-1082-add-boot-commands-to-vmx-and-ovf-builders

Conflicts:
	builder/virtualbox/ovf/config.go
	builder/vmware/vmx/config.go
parents 2ec84931 e082a7e5
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 { ...@@ -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 { ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -320,7 +320,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ...@@ -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),
......
...@@ -89,6 +89,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ...@@ -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),
......
...@@ -24,6 +24,7 @@ type Config struct { ...@@ -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) { ...@@ -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,
......
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.
......
package iso package common
import ( import (
"bufio" "bufio"
...@@ -8,8 +8,6 @@ import ( ...@@ -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 ( ...@@ -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 == "" {
......
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 { ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -348,7 +348,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ...@@ -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),
......
...@@ -76,6 +76,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ...@@ -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),
......
...@@ -20,6 +20,7 @@ type Config struct { ...@@ -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) { ...@@ -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 {
......
...@@ -52,6 +52,19 @@ each category, the available options are alphabetized and described. ...@@ -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.
......
...@@ -51,6 +51,19 @@ each category, the available options are alphabetized and described. ...@@ -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
......
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