flatten boot command config and implement for vmware

This commit is contained in:
Matthew Hooker 2018-04-18 14:10:28 -07:00
parent 84894ca459
commit 408eba88ad
No known key found for this signature in database
GPG Key ID: 7B5F933D9CE8C6A1
10 changed files with 154 additions and 103 deletions

View File

@ -2,30 +2,20 @@ package common
import ( import (
"fmt" "fmt"
"time"
"github.com/hashicorp/packer/template/interpolate" "github.com/hashicorp/packer/template/interpolate"
) )
type RunConfig struct { type RunConfig struct {
Headless bool `mapstructure:"headless"` Headless bool `mapstructure:"headless"`
RawBootWait string `mapstructure:"boot_wait"`
DisableVNC bool `mapstructure:"disable_vnc"`
BootCommand []string `mapstructure:"boot_command"`
VNCBindAddress string `mapstructure:"vnc_bind_address"` VNCBindAddress string `mapstructure:"vnc_bind_address"`
VNCPortMin uint `mapstructure:"vnc_port_min"` VNCPortMin uint `mapstructure:"vnc_port_min"`
VNCPortMax uint `mapstructure:"vnc_port_max"` VNCPortMax uint `mapstructure:"vnc_port_max"`
VNCDisablePassword bool `mapstructure:"vnc_disable_password"` VNCDisablePassword bool `mapstructure:"vnc_disable_password"`
BootWait time.Duration ``
}
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
if c.RawBootWait == "" {
c.RawBootWait = "10s"
} }
func (c *RunConfig) Prepare(ctx *interpolate.Context) (errs []error) {
if c.VNCPortMin == 0 { if c.VNCPortMin == 0 {
c.VNCPortMin = 5900 c.VNCPortMin = 5900
} }
@ -38,25 +28,9 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
c.VNCBindAddress = "127.0.0.1" c.VNCBindAddress = "127.0.0.1"
} }
var errs []error
var err error
if len(c.BootCommand) > 0 && c.DisableVNC {
errs = append(errs,
fmt.Errorf("A boot command cannot be used when vnc is disabled."))
}
if c.RawBootWait != "" {
c.BootWait, err = time.ParseDuration(c.RawBootWait)
if err != nil {
errs = append(
errs, fmt.Errorf("Failed parsing boot_wait: %s", err))
}
}
if c.VNCPortMin > c.VNCPortMax { if c.VNCPortMin > c.VNCPortMax {
errs = append( errs = append(errs, fmt.Errorf("vnc_port_min must be less than vnc_port_max"))
errs, fmt.Errorf("vnc_port_min must be less than vnc_port_max"))
} }
return errs return
} }

View File

@ -1,36 +0,0 @@
package common
import (
"testing"
)
func TestRunConfigPrepare(t *testing.T) {
var c *RunConfig
// Test a default boot_wait
c = new(RunConfig)
c.RawBootWait = ""
errs := c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("bad: %#v", errs)
}
if c.RawBootWait != "10s" {
t.Fatalf("bad value: %s", c.RawBootWait)
}
// Test with a bad boot_wait
c = new(RunConfig)
c.RawBootWait = "this is not good"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatal("should error")
}
// Test with a good one
c = new(RunConfig)
c.RawBootWait = "5s"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("bad: %#v", errs)
}
}

View File

@ -25,7 +25,7 @@ import (
// Produces: // Produces:
// <nothing> // <nothing>
type StepTypeBootCommand struct { type StepTypeBootCommand struct {
BootCommand []string BootCommand string
VNCEnabled bool VNCEnabled bool
BootWait time.Duration BootWait time.Duration
VMName string VMName string
@ -118,8 +118,7 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
d := bootcommand.NewVNCDriver(c) d := bootcommand.NewVNCDriver(c)
ui.Say("Typing the boot command over VNC...") ui.Say("Typing the boot command over VNC...")
for i, command := range s.BootCommand { command, err := interpolate.Render(s.BootCommand, &s.Ctx)
command, err := interpolate.Render(command, &s.Ctx)
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)
@ -143,9 +142,8 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
} }
if pauseFn != nil { if pauseFn != nil {
pauseFn(multistep.DebugLocationAfterRun, fmt.Sprintf("boot_command[%d]: %s", i, command), state) pauseFn(multistep.DebugLocationAfterRun,
} fmt.Sprintf("boot_command: %s", command), state)
} }
return multistep.ActionContinue return multistep.ActionContinue

View File

@ -11,6 +11,7 @@ import (
vmwcommon "github.com/hashicorp/packer/builder/vmware/common" vmwcommon "github.com/hashicorp/packer/builder/vmware/common"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/boot_command"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
@ -30,6 +31,7 @@ type Config struct {
common.HTTPConfig `mapstructure:",squash"` common.HTTPConfig `mapstructure:",squash"`
common.ISOConfig `mapstructure:",squash"` common.ISOConfig `mapstructure:",squash"`
common.FloppyConfig `mapstructure:",squash"` common.FloppyConfig `mapstructure:",squash"`
bootcommand.VNCConfig `mapstructure:",squash"`
vmwcommon.DriverConfig `mapstructure:",squash"` vmwcommon.DriverConfig `mapstructure:",squash"`
vmwcommon.OutputConfig `mapstructure:",squash"` vmwcommon.OutputConfig `mapstructure:",squash"`
vmwcommon.RunConfig `mapstructure:",squash"` vmwcommon.RunConfig `mapstructure:",squash"`
@ -122,6 +124,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(errs, b.config.ToolsConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.ToolsConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.VMXConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.VMXConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.FloppyConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, b.config.FloppyConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.VNCConfig.Prepare(&b.config.ctx)...)
if b.config.DiskName == "" { if b.config.DiskName == "" {
b.config.DiskName = "disk" b.config.DiskName = "disk"
@ -325,7 +328,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
&vmwcommon.StepTypeBootCommand{ &vmwcommon.StepTypeBootCommand{
BootWait: b.config.BootWait, BootWait: b.config.BootWait,
VNCEnabled: !b.config.DisableVNC, VNCEnabled: !b.config.DisableVNC,
BootCommand: b.config.BootCommand, BootCommand: b.config.FlatBootCommand(),
VMName: b.config.VMName, VMName: b.config.VMName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
}, },

View File

@ -93,7 +93,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
&vmwcommon.StepTypeBootCommand{ &vmwcommon.StepTypeBootCommand{
BootWait: b.config.BootWait, BootWait: b.config.BootWait,
VNCEnabled: !b.config.DisableVNC, VNCEnabled: !b.config.DisableVNC,
BootCommand: b.config.BootCommand, BootCommand: b.config.FlatBootCommand(),
VMName: b.config.VMName, VMName: b.config.VMName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
}, },

View File

@ -6,6 +6,7 @@ import (
vmwcommon "github.com/hashicorp/packer/builder/vmware/common" vmwcommon "github.com/hashicorp/packer/builder/vmware/common"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/boot_command"
"github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate" "github.com/hashicorp/packer/template/interpolate"
@ -16,6 +17,7 @@ type Config struct {
common.PackerConfig `mapstructure:",squash"` common.PackerConfig `mapstructure:",squash"`
common.HTTPConfig `mapstructure:",squash"` common.HTTPConfig `mapstructure:",squash"`
common.FloppyConfig `mapstructure:",squash"` common.FloppyConfig `mapstructure:",squash"`
bootcommand.VNCConfig `mapstructure:",squash"`
vmwcommon.DriverConfig `mapstructure:",squash"` vmwcommon.DriverConfig `mapstructure:",squash"`
vmwcommon.OutputConfig `mapstructure:",squash"` vmwcommon.OutputConfig `mapstructure:",squash"`
vmwcommon.RunConfig `mapstructure:",squash"` vmwcommon.RunConfig `mapstructure:",squash"`
@ -65,6 +67,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
errs = packer.MultiErrorAppend(errs, c.ToolsConfig.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.ToolsConfig.Prepare(&c.ctx)...)
errs = packer.MultiErrorAppend(errs, c.VMXConfig.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.VMXConfig.Prepare(&c.ctx)...)
errs = packer.MultiErrorAppend(errs, c.FloppyConfig.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.FloppyConfig.Prepare(&c.ctx)...)
errs = packer.MultiErrorAppend(errs, c.VNCConfig.Prepare(&c.ctx)...)
if c.SourcePath == "" { if c.SourcePath == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is blank, but is required")) errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is blank, but is required"))

View File

@ -84,12 +84,6 @@ type waitExpression struct {
// Do waits the amount of time described by the expression. It is cancellable // Do waits the amount of time described by the expression. It is cancellable
// through the context. // through the context.
func (w *waitExpression) Do(ctx context.Context, _ BCDriver) error { func (w *waitExpression) Do(ctx context.Context, _ BCDriver) error {
/*
// do I want this to not parse or to error?
if w.d < 0 {
panic("Was not expecting negative wait duration.")
}
*/
log.Printf("[INFO] Waiting %s", w.d) log.Printf("[INFO] Waiting %s", w.d)
select { select {
case <-time.After(w.d): case <-time.After(w.d):

View File

@ -0,0 +1,50 @@
package bootcommand
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/packer/template/interpolate"
)
type Config struct {
RawBootWait string `mapstructure:"boot_wait"`
BootCommand []string `mapstructure:"boot_command"`
BootWait time.Duration ``
}
type VNCConfig struct {
Config
DisableVNC bool `mapstructure:"disable_vnc"`
}
func (c *Config) Prepare(ctx *interpolate.Context) (errs []error) {
if c.RawBootWait == "" {
c.RawBootWait = "10s"
}
if c.RawBootWait != "" {
bw, err := time.ParseDuration(c.RawBootWait)
if err != nil {
errs = append(
errs, fmt.Errorf("Failed parsing boot_wait: %s", err))
} else {
c.BootWait = bw
}
}
return
}
func (c *Config) FlatBootCommand() string {
return strings.Join(c.BootCommand, "")
}
func (c *VNCConfig) Prepare(ctx *interpolate.Context) (errs []error) {
if len(c.BootCommand) > 0 && c.DisableVNC {
errs = append(errs,
fmt.Errorf("A boot command cannot be used when vnc is disabled."))
}
errs = append(errs, c.Config.Prepare(ctx)...)
return
}

View File

@ -0,0 +1,65 @@
package bootcommand
import (
"testing"
"github.com/hashicorp/packer/template/interpolate"
)
func TestConfigPrepare(t *testing.T) {
var c *Config
// Test a default boot_wait
c = new(Config)
c.RawBootWait = ""
errs := c.Prepare(&interpolate.Context{})
if len(errs) > 0 {
t.Fatalf("bad: %#v", errs)
}
if c.RawBootWait != "10s" {
t.Fatalf("bad value: %s", c.RawBootWait)
}
// Test with a bad boot_wait
c = new(Config)
c.RawBootWait = "this is not good"
errs = c.Prepare(&interpolate.Context{})
if len(errs) == 0 {
t.Fatal("should error")
}
// Test with a good one
c = new(Config)
c.RawBootWait = "5s"
errs = c.Prepare(&interpolate.Context{})
if len(errs) > 0 {
t.Fatalf("bad: %#v", errs)
}
}
func TestVNCConfigPrepare(t *testing.T) {
var c *VNCConfig
// Test with a boot command
c = new(VNCConfig)
c.BootCommand = []string{"a", "b"}
errs := c.Prepare(&interpolate.Context{})
if len(errs) > 0 {
t.Fatalf("bad: %#v", errs)
}
// Test with disabled vnc
c.DisableVNC = true
errs = c.Prepare(&interpolate.Context{})
if len(errs) == 0 {
t.Fatal("should error")
}
// Test no boot command with no vnc
c = new(VNCConfig)
c.DisableVNC = true
errs = c.Prepare(&interpolate.Context{})
if len(errs) > 0 {
t.Fatalf("bad: %#v", errs)
}
}