Commit 7a4ff3f2 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

builder/virtualbox: generic SSHConfig

parent 79c0c6b5
package iso package common
import ( import (
gossh "code.google.com/p/go.crypto/ssh" gossh "code.google.com/p/go.crypto/ssh"
...@@ -9,33 +9,33 @@ import ( ...@@ -9,33 +9,33 @@ import (
"os" "os"
) )
func sshAddress(state multistep.StateBag) (string, error) { func SSHAddress(state multistep.StateBag) (string, error) {
sshHostPort := state.Get("sshHostPort").(uint) sshHostPort := state.Get("sshHostPort").(uint)
return fmt.Sprintf("127.0.0.1:%d", sshHostPort), nil return fmt.Sprintf("127.0.0.1:%d", sshHostPort), nil
} }
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*gossh.ClientConfig, error) {
config := state.Get("config").(*config) return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
auth := []gossh.ClientAuth{
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)),
gossh.ClientAuthKeyboardInteractive(
ssh.PasswordKeyboardInteractive(config.SSHPassword)),
}
auth := []gossh.ClientAuth{ if config.SSHKeyPath != "" {
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)), keyring, err := sshKeyToKeyring(config.SSHKeyPath)
gossh.ClientAuthKeyboardInteractive( if err != nil {
ssh.PasswordKeyboardInteractive(config.SSHPassword)), return nil, err
} }
if config.SSHKeyPath != "" { auth = append(auth, gossh.ClientAuthKeyring(keyring))
keyring, err := sshKeyToKeyring(config.SSHKeyPath)
if err != nil {
return nil, err
} }
auth = append(auth, gossh.ClientAuthKeyring(keyring)) return &gossh.ClientConfig{
User: config.SSHUser,
Auth: auth,
}, nil
} }
return &gossh.ClientConfig{
User: config.SSHUser,
Auth: auth,
}, nil
} }
func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) { func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
......
package common
import (
"errors"
"fmt"
"github.com/mitchellh/packer/packer"
"os"
"time"
)
type SSHConfig struct {
SSHHostPortMin uint `mapstructure:"ssh_host_port_min"`
SSHHostPortMax uint `mapstructure:"ssh_host_port_max"`
SSHKeyPath string `mapstructure:"ssh_key_path"`
SSHPassword string `mapstructure:"ssh_password"`
SSHPort uint `mapstructure:"ssh_port"`
SSHUser string `mapstructure:"ssh_username"`
RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"`
SSHWaitTimeout time.Duration
}
func (c *SSHConfig) Prepare(t *packer.ConfigTemplate) []error {
if c.SSHHostPortMin == 0 {
c.SSHHostPortMin = 2222
}
if c.SSHHostPortMax == 0 {
c.SSHHostPortMax = 4444
}
if c.SSHPort == 0 {
c.SSHPort = 22
}
if c.RawSSHWaitTimeout == "" {
c.RawSSHWaitTimeout = "20m"
}
templates := map[string]*string{
"ssh_key_path": &c.SSHKeyPath,
"ssh_password": &c.SSHPassword,
"ssh_username": &c.SSHUser,
"ssh_wait_timeout": &c.RawSSHWaitTimeout,
}
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.SSHKeyPath != "" {
if _, err := os.Stat(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
} else if _, err := sshKeyToKeyring(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
}
}
if c.SSHHostPortMin > c.SSHHostPortMax {
errs = append(errs,
errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
}
if c.SSHUser == "" {
errs = append(errs, errors.New("An ssh_username must be specified."))
}
var err error
c.SSHWaitTimeout, err = time.ParseDuration(c.RawSSHWaitTimeout)
if err != nil {
errs = append(errs, fmt.Errorf("Failed parsing ssh_wait_timeout: %s", err))
}
return errs
}
package common
import (
"io/ioutil"
"os"
"testing"
)
func testSSHConfig() *SSHConfig {
return &SSHConfig{
SSHUser: "foo",
}
}
func TestSSHConfigPrepare(t *testing.T) {
c := testSSHConfig()
errs := c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if c.SSHHostPortMin != 2222 {
t.Errorf("bad min ssh host port: %d", c.SSHHostPortMin)
}
if c.SSHHostPortMax != 4444 {
t.Errorf("bad max ssh host port: %d", c.SSHHostPortMax)
}
if c.SSHPort != 22 {
t.Errorf("bad ssh port: %d", c.SSHPort)
}
}
func TestSSHConfigPrepare_SSHHostPort(t *testing.T) {
var c *SSHConfig
var errs []error
// Bad
c = testSSHConfig()
c.SSHHostPortMin = 1000
c.SSHHostPortMax = 500
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatalf("bad: %#v", errs)
}
// Good
c = testSSHConfig()
c.SSHHostPortMin = 50
c.SSHHostPortMax = 500
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %s", errs)
}
}
func TestSSHConfigPrepare_SSHKeyPath(t *testing.T) {
var c *SSHConfig
var errs []error
c = testSSHConfig()
c.SSHKeyPath = ""
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %#v", errs)
}
c = testSSHConfig()
c.SSHKeyPath = "/i/dont/exist"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatal("should have error")
}
// Test bad contents
tf, err := ioutil.TempFile("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.Remove(tf.Name())
defer tf.Close()
if _, err := tf.Write([]byte("HELLO!")); err != nil {
t.Fatalf("err: %s", err)
}
c = testSSHConfig()
c.SSHKeyPath = tf.Name()
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatal("should have error")
}
// Test good contents
tf.Seek(0, 0)
tf.Truncate(0)
tf.Write([]byte(testPem))
c = testSSHConfig()
c.SSHKeyPath = tf.Name()
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %#v", errs)
}
}
func TestSSHConfigPrepare_SSHUser(t *testing.T) {
var c *SSHConfig
var errs []error
c = testSSHConfig()
c.SSHUser = ""
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatalf("should have error")
}
c = testSSHConfig()
c.SSHUser = "exists"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %#v", errs)
}
}
func TestSSHConfigPrepare_SSHWaitTimeout(t *testing.T) {
var c *SSHConfig
var errs []error
// Defaults
c = testSSHConfig()
c.RawSSHWaitTimeout = ""
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %#v", errs)
}
if c.RawSSHWaitTimeout != "20m" {
t.Fatalf("bad value: %s", c.RawSSHWaitTimeout)
}
// Test with a bad value
c = testSSHConfig()
c.RawSSHWaitTimeout = "this is not good"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatal("should have error")
}
// Test with a good one
c = testSSHConfig()
c.RawSSHWaitTimeout = "5s"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %#v", errs)
}
}
const testPem = `
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAxd4iamvrwRJvtNDGQSIbNvvIQN8imXTRWlRY62EvKov60vqu
hh+rDzFYAIIzlmrJopvOe0clqmi3mIP9dtkjPFrYflq52a2CF5q+BdwsJXuRHbJW
LmStZUwW1khSz93DhvhmK50nIaczW63u4EO/jJb3xj+wxR1Nkk9bxi3DDsYFt8SN
AzYx9kjlEYQ/+sI4/ATfmdV9h78SVotjScupd9KFzzi76gWq9gwyCBLRynTUWlyD
2UOfJRkOvhN6/jKzvYfVVwjPSfA9IMuooHdScmC4F6KBKJl/zf/zETM0XyzIDNmH
uOPbCiljq2WoRM+rY6ET84EO0kVXbfx8uxUsqQIDAQABAoIBAQCkPj9TF0IagbM3
5BSs/CKbAWS4dH/D4bPlxx4IRCNirc8GUg+MRb04Xz0tLuajdQDqeWpr6iLZ0RKV
BvreLF+TOdV7DNQ4XE4gSdJyCtCaTHeort/aordL3l0WgfI7mVk0L/yfN1PEG4YG
E9q1TYcyrB3/8d5JwIkjabxERLglCcP+geOEJp+QijbvFIaZR/n2irlKW4gSy6ko
9B0fgUnhkHysSg49ChHQBPQ+o5BbpuLrPDFMiTPTPhdfsvGGcyCGeqfBA56oHcSF
K02Fg8OM+Bd1lb48LAN9nWWY4WbwV+9bkN3Ym8hO4c3a/Dxf2N7LtAQqWZzFjvM3
/AaDvAgBAoGBAPLD+Xn1IYQPMB2XXCXfOuJewRY7RzoVWvMffJPDfm16O7wOiW5+
2FmvxUDayk4PZy6wQMzGeGKnhcMMZTyaq2g/QtGfrvy7q1Lw2fB1VFlVblvqhoJa
nMJojjC4zgjBkXMHsRLeTmgUKyGs+fdFbfI6uejBnnf+eMVUMIdJ+6I9AoGBANCn
kWO9640dttyXURxNJ3lBr2H3dJOkmD6XS+u+LWqCSKQe691Y/fZ/ZL0Oc4Mhy7I6
hsy3kDQ5k2V0fkaNODQIFJvUqXw2pMewUk8hHc9403f4fe9cPrL12rQ8WlQw4yoC
v2B61vNczCCUDtGxlAaw8jzSRaSI5s6ax3K7enbdAoGBAJB1WYDfA2CoAQO6y9Sl
b07A/7kQ8SN5DbPaqrDrBdJziBQxukoMJQXJeGFNUFD/DXFU5Fp2R7C86vXT7HIR
v6m66zH+CYzOx/YE6EsUJms6UP9VIVF0Rg/RU7teXQwM01ZV32LQ8mswhTH20o/3
uqMHmxUMEhZpUMhrfq0isyApAoGAe1UxGTXfj9AqkIVYylPIq2HqGww7+jFmVEj1
9Wi6S6Sq72ffnzzFEPkIQL/UA4TsdHMnzsYKFPSbbXLIWUeMGyVTmTDA5c0e5XIR
lPhMOKCAzv8w4VUzMnEkTzkFY5JqFCD/ojW57KvDdNZPVB+VEcdxyAW6aKELXMAc
eHLc1nkCgYEApm/motCTPN32nINZ+Vvywbv64ZD+gtpeMNP3CLrbe1X9O+H52AXa
1jCoOldWR8i2bs2NVPcKZgdo6fFULqE4dBX7Te/uYEIuuZhYLNzRO1IKU/YaqsXG
3bfQ8hKYcSnTfE0gPtLDnqCIxTocaGLSHeG3TH9fTw+dA8FvWpUztI4=
-----END RSA PRIVATE KEY-----
`
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"
"math/rand" "math/rand"
...@@ -14,30 +13,37 @@ import ( ...@@ -14,30 +13,37 @@ import (
// on the guest machine. // on the guest machine.
// //
// Uses: // Uses:
// driver Driver
// ui packer.Ui
// vmName string
// //
// Produces: // Produces:
type stepForwardSSH struct{} type StepForwardSSH struct {
GuestPort uint
HostPortMin uint
HostPortMax uint
}
func (s *stepForwardSSH) Run(state multistep.StateBag) multistep.StepAction { func (s *StepForwardSSH) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*config) driver := state.Get("driver").(Driver)
driver := state.Get("driver").(vboxcommon.Driver)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
vmName := state.Get("vmName").(string) vmName := state.Get("vmName").(string)
log.Printf("Looking for available SSH port between %d and %d", config.SSHHostPortMin, config.SSHHostPortMax) log.Printf("Looking for available SSH port between %d and %d",
s.HostPortMin, s.HostPortMax)
var sshHostPort uint var sshHostPort uint
var offset uint = 0 var offset uint = 0
portRange := int(config.SSHHostPortMax - config.SSHHostPortMin) portRange := int(s.HostPortMax - s.HostPortMin)
if portRange > 0 { if portRange > 0 {
// Have to check if > 0 to avoid a panic // Have to check if > 0 to avoid a panic
offset = uint(rand.Intn(portRange)) offset = uint(rand.Intn(portRange))
} }
for { for {
sshHostPort = offset + config.SSHHostPortMin sshHostPort = offset + s.HostPortMin
log.Printf("Trying port: %d", sshHostPort) log.Printf("Trying port: %d", sshHostPort)
l, err := net.Listen("tcp", fmt.Sprintf(":%d", sshHostPort)) l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", sshHostPort))
if err == nil { if err == nil {
defer l.Close() defer l.Close()
break break
...@@ -49,7 +55,7 @@ func (s *stepForwardSSH) Run(state multistep.StateBag) multistep.StepAction { ...@@ -49,7 +55,7 @@ func (s *stepForwardSSH) Run(state multistep.StateBag) multistep.StepAction {
command := []string{ command := []string{
"modifyvm", vmName, "modifyvm", vmName,
"--natpf1", "--natpf1",
fmt.Sprintf("packerssh,tcp,127.0.0.1,%d,,%d", sshHostPort, config.SSHPort), fmt.Sprintf("packerssh,tcp,127.0.0.1,%d,,%d", sshHostPort, s.GuestPort),
} }
if err := driver.VBoxManage(command...); err != nil { if err := driver.VBoxManage(command...); err != nil {
err := fmt.Errorf("Error creating port forwarding rule: %s", err) err := fmt.Errorf("Error creating port forwarding rule: %s", err)
...@@ -64,4 +70,4 @@ func (s *stepForwardSSH) Run(state multistep.StateBag) multistep.StepAction { ...@@ -64,4 +70,4 @@ func (s *stepForwardSSH) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
func (s *stepForwardSSH) Cleanup(state multistep.StateBag) {} func (s *StepForwardSSH) Cleanup(state multistep.StateBag) {}
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"github.com/mitchellh/packer/common" "github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
"os"
"strings" "strings"
"time" "time"
) )
...@@ -32,6 +31,7 @@ type config struct { ...@@ -32,6 +31,7 @@ type config struct {
common.PackerConfig `mapstructure:",squash"` common.PackerConfig `mapstructure:",squash"`
vboxcommon.FloppyConfig `mapstructure:",squash"` vboxcommon.FloppyConfig `mapstructure:",squash"`
vboxcommon.OutputConfig `mapstructure:",squash"` vboxcommon.OutputConfig `mapstructure:",squash"`
vboxcommon.SSHConfig `mapstructure:",squash"`
BootCommand []string `mapstructure:"boot_command"` BootCommand []string `mapstructure:"boot_command"`
DiskSize uint `mapstructure:"disk_size"` DiskSize uint `mapstructure:"disk_size"`
...@@ -50,12 +50,6 @@ type config struct { ...@@ -50,12 +50,6 @@ type config struct {
ISOChecksumType string `mapstructure:"iso_checksum_type"` ISOChecksumType string `mapstructure:"iso_checksum_type"`
ISOUrls []string `mapstructure:"iso_urls"` ISOUrls []string `mapstructure:"iso_urls"`
ShutdownCommand string `mapstructure:"shutdown_command"` ShutdownCommand string `mapstructure:"shutdown_command"`
SSHHostPortMin uint `mapstructure:"ssh_host_port_min"`
SSHHostPortMax uint `mapstructure:"ssh_host_port_max"`
SSHKeyPath string `mapstructure:"ssh_key_path"`
SSHPassword string `mapstructure:"ssh_password"`
SSHPort uint `mapstructure:"ssh_port"`
SSHUser string `mapstructure:"ssh_username"`
VBoxVersionFile string `mapstructure:"virtualbox_version_file"` VBoxVersionFile string `mapstructure:"virtualbox_version_file"`
VBoxManage [][]string `mapstructure:"vboxmanage"` VBoxManage [][]string `mapstructure:"vboxmanage"`
VMName string `mapstructure:"vm_name"` VMName string `mapstructure:"vm_name"`
...@@ -63,11 +57,9 @@ type config struct { ...@@ -63,11 +57,9 @@ type config struct {
RawBootWait string `mapstructure:"boot_wait"` RawBootWait string `mapstructure:"boot_wait"`
RawSingleISOUrl string `mapstructure:"iso_url"` RawSingleISOUrl string `mapstructure:"iso_url"`
RawShutdownTimeout string `mapstructure:"shutdown_timeout"` RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"`
bootWait time.Duration `` bootWait time.Duration ``
shutdownTimeout time.Duration `` shutdownTimeout time.Duration ``
sshWaitTimeout time.Duration ``
tpl *packer.ConfigTemplate tpl *packer.ConfigTemplate
} }
...@@ -85,8 +77,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { ...@@ -85,8 +77,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
// Accumulate any errors and warnings // Accumulate any errors and warnings
errs := common.CheckUnusedConfig(md) errs := common.CheckUnusedConfig(md)
errs = packer.MultiErrorAppend(errs, b.config.FloppyConfig.Prepare(b.config.tpl)...)
errs = packer.MultiErrorAppend( errs = packer.MultiErrorAppend(
errs, b.config.OutputConfig.Prepare(b.config.tpl, &b.config.PackerConfig)...) errs, b.config.OutputConfig.Prepare(b.config.tpl, &b.config.PackerConfig)...)
errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(b.config.tpl)...)
warnings := make([]string, 0) warnings := make([]string, 0)
if b.config.DiskSize == 0 { if b.config.DiskSize == 0 {
...@@ -121,18 +115,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { ...@@ -121,18 +115,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b.config.RawBootWait = "10s" b.config.RawBootWait = "10s"
} }
if b.config.SSHHostPortMin == 0 {
b.config.SSHHostPortMin = 2222
}
if b.config.SSHHostPortMax == 0 {
b.config.SSHHostPortMax = 4444
}
if b.config.SSHPort == 0 {
b.config.SSHPort = 22
}
if b.config.VBoxManage == nil { if b.config.VBoxManage == nil {
b.config.VBoxManage = make([][]string, 0) b.config.VBoxManage = make([][]string, 0)
} }
...@@ -160,15 +142,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { ...@@ -160,15 +142,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
"iso_checksum_type": &b.config.ISOChecksumType, "iso_checksum_type": &b.config.ISOChecksumType,
"iso_url": &b.config.RawSingleISOUrl, "iso_url": &b.config.RawSingleISOUrl,
"shutdown_command": &b.config.ShutdownCommand, "shutdown_command": &b.config.ShutdownCommand,
"ssh_key_path": &b.config.SSHKeyPath,
"ssh_password": &b.config.SSHPassword,
"ssh_username": &b.config.SSHUser,
"virtualbox_version_file": &b.config.VBoxVersionFile, "virtualbox_version_file": &b.config.VBoxVersionFile,
"vm_name": &b.config.VMName, "vm_name": &b.config.VMName,
"format": &b.config.Format, "format": &b.config.Format,
"boot_wait": &b.config.RawBootWait, "boot_wait": &b.config.RawBootWait,
"shutdown_timeout": &b.config.RawShutdownTimeout, "shutdown_timeout": &b.config.RawShutdownTimeout,
"ssh_wait_timeout": &b.config.RawSSHWaitTimeout,
} }
for n, ptr := range templates { for n, ptr := range templates {
...@@ -293,42 +271,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { ...@@ -293,42 +271,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b.config.RawShutdownTimeout = "5m" b.config.RawShutdownTimeout = "5m"
} }
if b.config.RawSSHWaitTimeout == "" {
b.config.RawSSHWaitTimeout = "20m"
}
b.config.shutdownTimeout, err = time.ParseDuration(b.config.RawShutdownTimeout) b.config.shutdownTimeout, err = time.ParseDuration(b.config.RawShutdownTimeout)
if err != nil { if err != nil {
errs = packer.MultiErrorAppend( errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err)) errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
} }
if b.config.SSHKeyPath != "" {
if _, err := os.Stat(b.config.SSHKeyPath); err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
} else if _, err := sshKeyToKeyring(b.config.SSHKeyPath); err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
}
}
if b.config.SSHHostPortMin > b.config.SSHHostPortMax {
errs = packer.MultiErrorAppend(
errs, errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
}
if b.config.SSHUser == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("An ssh_username must be specified."))
}
b.config.sshWaitTimeout, err = time.ParseDuration(b.config.RawSSHWaitTimeout)
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Failed parsing ssh_wait_timeout: %s", err))
}
for i, args := range b.config.VBoxManage { for i, args := range b.config.VBoxManage {
for j, arg := range args { for j, arg := range args {
if err := b.config.tpl.Validate(arg); err != nil { if err := b.config.tpl.Validate(arg); err != nil {
...@@ -382,14 +330,18 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ...@@ -382,14 +330,18 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
new(stepAttachISO), new(stepAttachISO),
new(stepAttachGuestAdditions), new(stepAttachGuestAdditions),
new(vboxcommon.StepAttachFloppy), new(vboxcommon.StepAttachFloppy),
new(stepForwardSSH), &vboxcommon.StepForwardSSH{
GuestPort: b.config.SSHPort,
HostPortMin: b.config.SSHHostPortMin,
HostPortMax: b.config.SSHHostPortMax,
},
new(stepVBoxManage), new(stepVBoxManage),
new(stepRun), new(stepRun),
new(stepTypeBootCommand), new(stepTypeBootCommand),
&common.StepConnectSSH{ &common.StepConnectSSH{
SSHAddress: sshAddress, SSHAddress: vboxcommon.SSHAddress,
SSHConfig: sshConfig, SSHConfig: vboxcommon.SSHConfigFunc(b.config.SSHConfig),
SSHWaitTimeout: b.config.sshWaitTimeout, SSHWaitTimeout: b.config.SSHWaitTimeout,
}, },
new(stepUploadVersion), new(stepUploadVersion),
new(stepUploadGuestAdditions), new(stepUploadGuestAdditions),
......
...@@ -8,36 +8,6 @@ import ( ...@@ -8,36 +8,6 @@ import (
"testing" "testing"
) )
var testPem = `
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAxd4iamvrwRJvtNDGQSIbNvvIQN8imXTRWlRY62EvKov60vqu
hh+rDzFYAIIzlmrJopvOe0clqmi3mIP9dtkjPFrYflq52a2CF5q+BdwsJXuRHbJW
LmStZUwW1khSz93DhvhmK50nIaczW63u4EO/jJb3xj+wxR1Nkk9bxi3DDsYFt8SN
AzYx9kjlEYQ/+sI4/ATfmdV9h78SVotjScupd9KFzzi76gWq9gwyCBLRynTUWlyD
2UOfJRkOvhN6/jKzvYfVVwjPSfA9IMuooHdScmC4F6KBKJl/zf/zETM0XyzIDNmH
uOPbCiljq2WoRM+rY6ET84EO0kVXbfx8uxUsqQIDAQABAoIBAQCkPj9TF0IagbM3
5BSs/CKbAWS4dH/D4bPlxx4IRCNirc8GUg+MRb04Xz0tLuajdQDqeWpr6iLZ0RKV
BvreLF+TOdV7DNQ4XE4gSdJyCtCaTHeort/aordL3l0WgfI7mVk0L/yfN1PEG4YG
E9q1TYcyrB3/8d5JwIkjabxERLglCcP+geOEJp+QijbvFIaZR/n2irlKW4gSy6ko
9B0fgUnhkHysSg49ChHQBPQ+o5BbpuLrPDFMiTPTPhdfsvGGcyCGeqfBA56oHcSF
K02Fg8OM+Bd1lb48LAN9nWWY4WbwV+9bkN3Ym8hO4c3a/Dxf2N7LtAQqWZzFjvM3
/AaDvAgBAoGBAPLD+Xn1IYQPMB2XXCXfOuJewRY7RzoVWvMffJPDfm16O7wOiW5+
2FmvxUDayk4PZy6wQMzGeGKnhcMMZTyaq2g/QtGfrvy7q1Lw2fB1VFlVblvqhoJa
nMJojjC4zgjBkXMHsRLeTmgUKyGs+fdFbfI6uejBnnf+eMVUMIdJ+6I9AoGBANCn
kWO9640dttyXURxNJ3lBr2H3dJOkmD6XS+u+LWqCSKQe691Y/fZ/ZL0Oc4Mhy7I6
hsy3kDQ5k2V0fkaNODQIFJvUqXw2pMewUk8hHc9403f4fe9cPrL12rQ8WlQw4yoC
v2B61vNczCCUDtGxlAaw8jzSRaSI5s6ax3K7enbdAoGBAJB1WYDfA2CoAQO6y9Sl
b07A/7kQ8SN5DbPaqrDrBdJziBQxukoMJQXJeGFNUFD/DXFU5Fp2R7C86vXT7HIR
v6m66zH+CYzOx/YE6EsUJms6UP9VIVF0Rg/RU7teXQwM01ZV32LQ8mswhTH20o/3
uqMHmxUMEhZpUMhrfq0isyApAoGAe1UxGTXfj9AqkIVYylPIq2HqGww7+jFmVEj1
9Wi6S6Sq72ffnzzFEPkIQL/UA4TsdHMnzsYKFPSbbXLIWUeMGyVTmTDA5c0e5XIR
lPhMOKCAzv8w4VUzMnEkTzkFY5JqFCD/ojW57KvDdNZPVB+VEcdxyAW6aKELXMAc
eHLc1nkCgYEApm/motCTPN32nINZ+Vvywbv64ZD+gtpeMNP3CLrbe1X9O+H52AXa
1jCoOldWR8i2bs2NVPcKZgdo6fFULqE4dBX7Te/uYEIuuZhYLNzRO1IKU/YaqsXG
3bfQ8hKYcSnTfE0gPtLDnqCIxTocaGLSHeG3TH9fTw+dA8FvWpUztI4=
-----END RSA PRIVATE KEY-----
`
func testConfig() map[string]interface{} { func testConfig() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"iso_checksum": "foo", "iso_checksum": "foo",
...@@ -77,22 +47,6 @@ func TestBuilderPrepare_Defaults(t *testing.T) { ...@@ -77,22 +47,6 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
t.Errorf("bad guest OS type: %s", b.config.GuestOSType) t.Errorf("bad guest OS type: %s", b.config.GuestOSType)
} }
if b.config.OutputDir != "output-foo" {
t.Errorf("bad output dir: %s", b.config.OutputDir)
}
if b.config.SSHHostPortMin != 2222 {
t.Errorf("bad min ssh host port: %d", b.config.SSHHostPortMin)
}
if b.config.SSHHostPortMax != 4444 {
t.Errorf("bad max ssh host port: %d", b.config.SSHHostPortMax)
}
if b.config.SSHPort != 22 {
t.Errorf("bad ssh port: %d", b.config.SSHPort)
}
if b.config.VMName != "packer-foo" { if b.config.VMName != "packer-foo" {
t.Errorf("bad vm name: %s", b.config.VMName) t.Errorf("bad vm name: %s", b.config.VMName)
} }
...@@ -174,39 +128,6 @@ func TestBuilderPrepare_DiskSize(t *testing.T) { ...@@ -174,39 +128,6 @@ func TestBuilderPrepare_DiskSize(t *testing.T) {
} }
} }
func TestBuilderPrepare_FloppyFiles(t *testing.T) {
var b Builder
config := testConfig()
delete(config, "floppy_files")
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("bad err: %s", err)
}
if len(b.config.FloppyFiles) != 0 {
t.Fatalf("bad: %#v", b.config.FloppyFiles)
}
config["floppy_files"] = []string{"foo", "bar"}
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)
}
expected := []string{"foo", "bar"}
if !reflect.DeepEqual(b.config.FloppyFiles, expected) {
t.Fatalf("bad: %#v", b.config.FloppyFiles)
}
}
func TestBuilderPrepare_GuestAdditionsMode(t *testing.T) { func TestBuilderPrepare_GuestAdditionsMode(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()
...@@ -613,39 +534,6 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) { ...@@ -613,39 +534,6 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
} }
} }
func TestBuilderPrepare_OutputDir(t *testing.T) {
var b Builder
config := testConfig()
// Test with existing dir
dir, err := ioutil.TempDir("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(dir)
config["output_directory"] = dir
b = Builder{}
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should have error")
}
// Test with a good one
config["output_directory"] = "i-hope-i-dont-exist"
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_ShutdownCommand(t *testing.T) { func TestBuilderPrepare_ShutdownCommand(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()
...@@ -687,173 +575,6 @@ func TestBuilderPrepare_ShutdownTimeout(t *testing.T) { ...@@ -687,173 +575,6 @@ func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
} }
} }
func TestBuilderPrepare_SSHHostPort(t *testing.T) {
var b Builder
config := testConfig()
// Bad
config["ssh_host_port_min"] = 1000
config["ssh_host_port_max"] = 500
b = Builder{}
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should have error")
}
// Bad
config["ssh_host_port_min"] = -500
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should have error")
}
// Good
config["ssh_host_port_min"] = 500
config["ssh_host_port_max"] = 1000
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_sshKeyPath(t *testing.T) {
var b Builder
config := testConfig()
config["ssh_key_path"] = ""
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)
}
config["ssh_key_path"] = "/i/dont/exist"
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should have error")
}
// Test bad contents
tf, err := ioutil.TempFile("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.Remove(tf.Name())
defer tf.Close()
if _, err := tf.Write([]byte("HELLO!")); err != nil {
t.Fatalf("err: %s", err)
}
config["ssh_key_path"] = tf.Name()
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should have error")
}
// Test good contents
tf.Seek(0, 0)
tf.Truncate(0)
tf.Write([]byte(testPem))
config["ssh_key_path"] = tf.Name()
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("err: %s", err)
}
}
func TestBuilderPrepare_SSHUser(t *testing.T) {
var b Builder
config := testConfig()
config["ssh_username"] = ""
b = Builder{}
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should have error")
}
config["ssh_username"] = "exists"
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_SSHWaitTimeout(t *testing.T) {
var b Builder
config := testConfig()
// Test a default boot_wait
delete(config, "ssh_wait_timeout")
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("err: %s", err)
}
if b.config.RawSSHWaitTimeout != "20m" {
t.Fatalf("bad value: %s", b.config.RawSSHWaitTimeout)
}
// Test with a bad value
config["ssh_wait_timeout"] = "this is not good"
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should have error")
}
// Test with a good one
config["ssh_wait_timeout"] = "5s"
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_VBoxManage(t *testing.T) { func TestBuilderPrepare_VBoxManage(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()
......
...@@ -54,16 +54,21 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ...@@ -54,16 +54,21 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
new(stepAttachGuestAdditions), new(stepAttachGuestAdditions),
*/ */
new(vboxcommon.StepAttachFloppy), new(vboxcommon.StepAttachFloppy),
&vboxcommon.StepForwardSSH{
GuestPort: b.config.SSHPort,
HostPortMin: b.config.SSHHostPortMin,
HostPortMax: b.config.SSHHostPortMax,
},
/* /*
new(stepForwardSSH),
new(stepVBoxManage), new(stepVBoxManage),
new(stepRun), new(stepRun),
new(stepTypeBootCommand), */
&common.StepConnectSSH{ &common.StepConnectSSH{
SSHAddress: sshAddress, SSHAddress: vboxcommon.SSHAddress,
SSHConfig: sshConfig, SSHConfig: vboxcommon.SSHConfigFunc(b.config.SSHConfig),
SSHWaitTimeout: b.config.sshWaitTimeout, SSHWaitTimeout: b.config.SSHWaitTimeout,
}, },
/*
new(stepUploadVersion), new(stepUploadVersion),
new(stepUploadGuestAdditions), new(stepUploadGuestAdditions),
new(common.StepProvision), new(common.StepProvision),
......
...@@ -11,6 +11,7 @@ type Config struct { ...@@ -11,6 +11,7 @@ type Config struct {
common.PackerConfig `mapstructure:",squash"` common.PackerConfig `mapstructure:",squash"`
vboxcommon.FloppyConfig `mapstructure:",squash"` vboxcommon.FloppyConfig `mapstructure:",squash"`
vboxcommon.OutputConfig `mapstructure:",squash"` vboxcommon.OutputConfig `mapstructure:",squash"`
vboxcommon.SSHConfig `mapstructure:",squash"`
tpl *packer.ConfigTemplate tpl *packer.ConfigTemplate
} }
...@@ -30,7 +31,9 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { ...@@ -30,7 +31,9 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
// Prepare the errors // Prepare the errors
errs := common.CheckUnusedConfig(md) errs := common.CheckUnusedConfig(md)
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.OutputConfig.Prepare(c.tpl, &c.PackerConfig)...)
errs = packer.MultiErrorAppend(errs, c.SSHConfig.Prepare(c.tpl)...)
// Check for any errors. // Check for any errors.
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
......
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