builder/virtualbox: StepShutdown
This commit is contained in:
parent
4bd2aa6106
commit
67a87ce3e4
|
@ -0,0 +1,42 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ShutdownConfig struct {
|
||||
ShutdownCommand string `mapstructure:"shutdown_command"`
|
||||
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||
|
||||
ShutdownTimeout time.Duration ``
|
||||
}
|
||||
|
||||
func (c *ShutdownConfig) Prepare(t *packer.ConfigTemplate) []error {
|
||||
if c.RawShutdownTimeout == "" {
|
||||
c.RawShutdownTimeout = "5m"
|
||||
}
|
||||
|
||||
templates := map[string]*string{
|
||||
"shutdown_command": &c.ShutdownCommand,
|
||||
"shutdown_timeout": &c.RawShutdownTimeout,
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
c.ShutdownTimeout, err = time.ParseDuration(c.RawShutdownTimeout)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testShutdownConfig() *ShutdownConfig {
|
||||
return &ShutdownConfig{}
|
||||
}
|
||||
|
||||
func TestShutdownConfigPrepare_ShutdownCommand(t *testing.T) {
|
||||
var c *ShutdownConfig
|
||||
var errs []error
|
||||
|
||||
c = testShutdownConfig()
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShutdownConfigPrepare_ShutdownTimeout(t *testing.T) {
|
||||
var c *ShutdownConfig
|
||||
var errs []error
|
||||
|
||||
// Test with a bad value
|
||||
c = testShutdownConfig()
|
||||
c.RawShutdownTimeout = "this is not good"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) == 0 {
|
||||
t.Fatalf("should have error")
|
||||
}
|
||||
|
||||
// Test with a good one
|
||||
c = testShutdownConfig()
|
||||
c.RawShutdownTimeout = "5s"
|
||||
errs = c.Prepare(testConfigTemplate(t))
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
package iso
|
||||
package common
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
vboxcommon "github.com/mitchellh/packer/builder/virtualbox/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"time"
|
||||
|
@ -15,26 +14,27 @@ import (
|
|||
//
|
||||
// Uses:
|
||||
// communicator packer.Communicator
|
||||
// config *config
|
||||
// driver Driver
|
||||
// ui packer.Ui
|
||||
// vmName string
|
||||
//
|
||||
// Produces:
|
||||
// <nothing>
|
||||
type stepShutdown struct{}
|
||||
type StepShutdown struct {
|
||||
Command string
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
config := state.Get("config").(*config)
|
||||
driver := state.Get("driver").(vboxcommon.Driver)
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
if config.ShutdownCommand != "" {
|
||||
if s.Command != "" {
|
||||
ui.Say("Gracefully halting virtual machine...")
|
||||
log.Printf("Executing shutdown command: %s", config.ShutdownCommand)
|
||||
cmd := &packer.RemoteCmd{Command: config.ShutdownCommand}
|
||||
log.Printf("Executing shutdown command: %s", s.Command)
|
||||
cmd := &packer.RemoteCmd{Command: s.Command}
|
||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||
state.Put("error", err)
|
||||
|
@ -43,8 +43,8 @@ func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
|||
}
|
||||
|
||||
// Wait for the machine to actually shut down
|
||||
log.Printf("Waiting max %s for shutdown to complete", config.shutdownTimeout)
|
||||
shutdownTimer := time.After(config.shutdownTimeout)
|
||||
log.Printf("Waiting max %s for shutdown to complete", s.Timeout)
|
||||
shutdownTimer := time.After(s.Timeout)
|
||||
for {
|
||||
running, _ := driver.IsRunning(vmName)
|
||||
if !running {
|
||||
|
@ -75,4 +75,4 @@ func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
|||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepShutdown) Cleanup(state multistep.StateBag) {}
|
||||
func (s *StepShutdown) Cleanup(state multistep.StateBag) {}
|
|
@ -31,6 +31,7 @@ type config struct {
|
|||
common.PackerConfig `mapstructure:",squash"`
|
||||
vboxcommon.FloppyConfig `mapstructure:",squash"`
|
||||
vboxcommon.OutputConfig `mapstructure:",squash"`
|
||||
vboxcommon.ShutdownConfig `mapstructure:",squash"`
|
||||
vboxcommon.SSHConfig `mapstructure:",squash"`
|
||||
vboxcommon.VBoxManageConfig `mapstructure:",squash"`
|
||||
|
||||
|
@ -50,17 +51,14 @@ type config struct {
|
|||
ISOChecksum string `mapstructure:"iso_checksum"`
|
||||
ISOChecksumType string `mapstructure:"iso_checksum_type"`
|
||||
ISOUrls []string `mapstructure:"iso_urls"`
|
||||
ShutdownCommand string `mapstructure:"shutdown_command"`
|
||||
VBoxVersionFile string `mapstructure:"virtualbox_version_file"`
|
||||
VMName string `mapstructure:"vm_name"`
|
||||
|
||||
RawBootWait string `mapstructure:"boot_wait"`
|
||||
RawSingleISOUrl string `mapstructure:"iso_url"`
|
||||
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||
RawBootWait string `mapstructure:"boot_wait"`
|
||||
RawSingleISOUrl string `mapstructure:"iso_url"`
|
||||
|
||||
bootWait time.Duration ``
|
||||
shutdownTimeout time.Duration ``
|
||||
tpl *packer.ConfigTemplate
|
||||
bootWait time.Duration ``
|
||||
tpl *packer.ConfigTemplate
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
|
@ -138,12 +136,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
"iso_checksum": &b.config.ISOChecksum,
|
||||
"iso_checksum_type": &b.config.ISOChecksumType,
|
||||
"iso_url": &b.config.RawSingleISOUrl,
|
||||
"shutdown_command": &b.config.ShutdownCommand,
|
||||
"virtualbox_version_file": &b.config.VBoxVersionFile,
|
||||
"vm_name": &b.config.VMName,
|
||||
"format": &b.config.Format,
|
||||
"boot_wait": &b.config.RawBootWait,
|
||||
"shutdown_timeout": &b.config.RawShutdownTimeout,
|
||||
}
|
||||
|
||||
for n, ptr := range templates {
|
||||
|
@ -264,16 +260,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
errs, fmt.Errorf("Failed parsing boot_wait: %s", err))
|
||||
}
|
||||
|
||||
if b.config.RawShutdownTimeout == "" {
|
||||
b.config.RawShutdownTimeout = "5m"
|
||||
}
|
||||
|
||||
b.config.shutdownTimeout, err = time.ParseDuration(b.config.RawShutdownTimeout)
|
||||
if err != nil {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
|
||||
}
|
||||
|
||||
// Warnings
|
||||
if b.config.ShutdownCommand == "" {
|
||||
warnings = append(warnings,
|
||||
|
@ -336,7 +322,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
new(stepUploadVersion),
|
||||
new(stepUploadGuestAdditions),
|
||||
new(common.StepProvision),
|
||||
new(stepShutdown),
|
||||
&vboxcommon.StepShutdown{
|
||||
Command: b.config.ShutdownCommand,
|
||||
Timeout: b.config.ShutdownTimeout,
|
||||
},
|
||||
new(stepRemoveDevices),
|
||||
new(stepExport),
|
||||
}
|
||||
|
|
|
@ -532,47 +532,6 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ShutdownCommand(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
delete(config, "shutdown_command")
|
||||
|
||||
warns, err := b.Prepare(config)
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
|
||||
if len(warns) != 1 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
// Test with a bad value
|
||||
config["shutdown_timeout"] = "this is not good"
|
||||
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["shutdown_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_VBoxVersionFile(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
|
|
@ -75,8 +75,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
new(stepUploadGuestAdditions),
|
||||
*/
|
||||
new(common.StepProvision),
|
||||
&vboxcommon.StepShutdown{
|
||||
Command: b.config.ShutdownCommand,
|
||||
Timeout: b.config.ShutdownTimeout,
|
||||
},
|
||||
/*
|
||||
new(stepShutdown),
|
||||
new(stepRemoveDevices),
|
||||
new(stepExport),
|
||||
*/
|
||||
|
|
|
@ -12,6 +12,7 @@ type Config struct {
|
|||
vboxcommon.FloppyConfig `mapstructure:",squash"`
|
||||
vboxcommon.OutputConfig `mapstructure:",squash"`
|
||||
vboxcommon.SSHConfig `mapstructure:",squash"`
|
||||
vboxcommon.ShutdownConfig `mapstructure:",squash"`
|
||||
vboxcommon.VBoxManageConfig `mapstructure:",squash"`
|
||||
|
||||
tpl *packer.ConfigTemplate
|
||||
|
@ -37,10 +38,18 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
errs = packer.MultiErrorAppend(errs, c.SSHConfig.Prepare(c.tpl)...)
|
||||
errs = packer.MultiErrorAppend(errs, c.VBoxManageConfig.Prepare(c.tpl)...)
|
||||
|
||||
// Check for any errors.
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return nil, nil, errs
|
||||
// Warnings
|
||||
var warnings []string
|
||||
if c.ShutdownCommand == "" {
|
||||
warnings = append(warnings,
|
||||
"A shutdown_command was not specified. Without a shutdown command, Packer\n"+
|
||||
"will forcibly halt the virtual machine, which may result in data loss.")
|
||||
}
|
||||
|
||||
return c, nil, nil
|
||||
// Check for any errors.
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return nil, warnings, errs
|
||||
}
|
||||
|
||||
return c, warnings, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue