Add disable_shutdown option to VirtualBox builder (#8449)
This commit is contained in:
parent
8146b39986
commit
5ff5623433
|
@ -27,6 +27,13 @@ type ShutdownConfig struct {
|
|||
// Error removing floppy controller, you might need to set this to 5m
|
||||
// or so. By default, the delay is 0s or disabled.
|
||||
PostShutdownDelay time.Duration `mapstructure:"post_shutdown_delay" required:"false"`
|
||||
// Packer normally halts the virtual machine after all provisioners have
|
||||
// run when no `shutdown_command` is defined. If this is set to `true`, Packer
|
||||
// *will not* halt the virtual machine but will assume that you will send the stop
|
||||
// signal yourself through the preseed.cfg or your final provisioner.
|
||||
// Packer will wait for a default of 5 minutes until the virtual machine is shutdown.
|
||||
// The timeout can be changed using `shutdown_timeout` option.
|
||||
DisableShutdown bool `mapstructure:"disable_shutdown" required:"false"`
|
||||
}
|
||||
|
||||
func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
@ -64,3 +64,27 @@ func TestShutdownConfigPrepare_PostShutdownDelay(t *testing.T) {
|
|||
t.Fatalf("bad: %s", c.PostShutdownDelay)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShutdownConfigPrepare_DisableShutdown(t *testing.T) {
|
||||
var c *ShutdownConfig
|
||||
var errs []error
|
||||
|
||||
// Test with default value
|
||||
c = testShutdownConfig()
|
||||
c.DisableShutdown = false
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
|
||||
// Test with a good one
|
||||
c = testShutdownConfig()
|
||||
c.DisableShutdown = true
|
||||
errs = c.Prepare(interpolate.NewContext())
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("err: %#v", errs)
|
||||
}
|
||||
if !c.DisableShutdown {
|
||||
t.Fatalf("bad: %t", c.DisableShutdown)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,10 @@ import (
|
|||
// Produces:
|
||||
// <nothing>
|
||||
type StepShutdown struct {
|
||||
Command string
|
||||
Timeout time.Duration
|
||||
Delay time.Duration
|
||||
Command string
|
||||
Timeout time.Duration
|
||||
Delay time.Duration
|
||||
DisableShutdown bool
|
||||
}
|
||||
|
||||
func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
|
@ -34,25 +35,29 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
|||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
if s.Command != "" {
|
||||
ui.Say("Gracefully halting virtual machine...")
|
||||
log.Printf("Executing shutdown command: %s", s.Command)
|
||||
cmd := &packer.RemoteCmd{Command: s.Command}
|
||||
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
if !s.DisableShutdown {
|
||||
if s.Command != "" {
|
||||
ui.Say("Gracefully halting virtual machine...")
|
||||
log.Printf("Executing shutdown command: %s", s.Command)
|
||||
cmd := &packer.RemoteCmd{Command: s.Command}
|
||||
if err := cmd.RunWithUi(ctx, comm, ui); err != nil {
|
||||
err := fmt.Errorf("Failed to send shutdown command: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
} else {
|
||||
ui.Say("Halting the virtual machine...")
|
||||
if err := driver.Stop(vmName); err != nil {
|
||||
err := fmt.Errorf("Error stopping VM: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
} else {
|
||||
ui.Say("Halting the virtual machine...")
|
||||
if err := driver.Stop(vmName); err != nil {
|
||||
err := fmt.Errorf("Error stopping VM: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ui.Say("Automatic shutdown disabled. Please shutdown virtual machine.")
|
||||
}
|
||||
|
||||
// Wait for the machine to actually shut down
|
||||
|
@ -72,7 +77,7 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
|||
|
||||
select {
|
||||
case <-shutdownTimer:
|
||||
err := errors.New("Timeout while waiting for machine to shut down.")
|
||||
err := errors.New("Timeout while waiting for machine to shutdown.")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
|
|
|
@ -16,6 +16,7 @@ func TestStepShutdown_impl(t *testing.T) {
|
|||
func TestStepShutdown_noShutdownCommand(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepShutdown)
|
||||
step.DisableShutdown = false
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
state.Put("communicator", comm)
|
||||
|
@ -45,6 +46,7 @@ func TestStepShutdown_shutdownCommand(t *testing.T) {
|
|||
step := new(StepShutdown)
|
||||
step.Command = "poweroff"
|
||||
step.Timeout = 1 * time.Second
|
||||
step.DisableShutdown = false
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
state.Put("communicator", comm)
|
||||
|
@ -82,6 +84,7 @@ func TestStepShutdown_shutdownTimeout(t *testing.T) {
|
|||
step := new(StepShutdown)
|
||||
step.Command = "poweroff"
|
||||
step.Timeout = 1 * time.Second
|
||||
step.DisableShutdown = false
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
state.Put("communicator", comm)
|
||||
|
@ -112,6 +115,7 @@ func TestStepShutdown_shutdownDelay(t *testing.T) {
|
|||
step.Command = "poweroff"
|
||||
step.Timeout = 5 * time.Second
|
||||
step.Delay = 2 * time.Second
|
||||
step.DisableShutdown = false
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
state.Put("communicator", comm)
|
||||
|
@ -168,3 +172,32 @@ func TestStepShutdown_shutdownDelay(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func TestStepShutdown_DisableShutdown(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepShutdown)
|
||||
step.DisableShutdown = true
|
||||
step.Timeout = 2 * time.Second
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
state.Put("communicator", comm)
|
||||
state.Put("vmName", "foo")
|
||||
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
driver.IsRunningReturn = true
|
||||
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
driver.Lock()
|
||||
defer driver.Unlock()
|
||||
driver.IsRunningReturn = false
|
||||
}()
|
||||
|
||||
// Test the run
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
if _, ok := state.GetOk("error"); ok {
|
||||
t.Fatal("should NOT have error")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -370,9 +370,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
Comm: &b.config.SSHConfig.Comm,
|
||||
},
|
||||
&vboxcommon.StepShutdown{
|
||||
Command: b.config.ShutdownCommand,
|
||||
Timeout: b.config.ShutdownTimeout,
|
||||
Delay: b.config.PostShutdownDelay,
|
||||
Command: b.config.ShutdownCommand,
|
||||
Timeout: b.config.ShutdownTimeout,
|
||||
Delay: b.config.PostShutdownDelay,
|
||||
DisableShutdown: b.config.DisableShutdown,
|
||||
},
|
||||
&vboxcommon.StepRemoveDevices{
|
||||
Bundling: b.config.VBoxBundleConfig,
|
||||
|
|
|
@ -42,6 +42,7 @@ type FlatConfig struct {
|
|||
ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"`
|
||||
ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"`
|
||||
PostShutdownDelay *string `mapstructure:"post_shutdown_delay" required:"false" cty:"post_shutdown_delay"`
|
||||
DisableShutdown *bool `mapstructure:"disable_shutdown" required:"false" cty:"disable_shutdown"`
|
||||
Type *string `mapstructure:"communicator" cty:"communicator"`
|
||||
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"`
|
||||
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"`
|
||||
|
@ -154,6 +155,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false},
|
||||
"shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false},
|
||||
"post_shutdown_delay": &hcldec.AttrSpec{Name: "post_shutdown_delay", Type: cty.String, Required: false},
|
||||
"disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false},
|
||||
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
|
||||
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
|
||||
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
|
||||
|
|
|
@ -139,9 +139,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
Comm: &b.config.SSHConfig.Comm,
|
||||
},
|
||||
&vboxcommon.StepShutdown{
|
||||
Command: b.config.ShutdownCommand,
|
||||
Timeout: b.config.ShutdownTimeout,
|
||||
Delay: b.config.PostShutdownDelay,
|
||||
Command: b.config.ShutdownCommand,
|
||||
Timeout: b.config.ShutdownTimeout,
|
||||
Delay: b.config.PostShutdownDelay,
|
||||
DisableShutdown: b.config.DisableShutdown,
|
||||
},
|
||||
&vboxcommon.StepRemoveDevices{
|
||||
GuestAdditionsInterface: b.config.GuestAdditionsInterface,
|
||||
|
|
|
@ -79,6 +79,7 @@ type FlatConfig struct {
|
|||
ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"`
|
||||
ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"`
|
||||
PostShutdownDelay *string `mapstructure:"post_shutdown_delay" required:"false" cty:"post_shutdown_delay"`
|
||||
DisableShutdown *bool `mapstructure:"disable_shutdown" required:"false" cty:"disable_shutdown"`
|
||||
VBoxManage [][]string `mapstructure:"vboxmanage" required:"false" cty:"vboxmanage"`
|
||||
VBoxManagePost [][]string `mapstructure:"vboxmanage_post" required:"false" cty:"vboxmanage_post"`
|
||||
VBoxVersionFile *string `mapstructure:"virtualbox_version_file" required:"false" cty:"virtualbox_version_file"`
|
||||
|
@ -177,6 +178,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false},
|
||||
"shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false},
|
||||
"post_shutdown_delay": &hcldec.AttrSpec{Name: "post_shutdown_delay", Type: cty.String, Required: false},
|
||||
"disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false},
|
||||
"vboxmanage": &hcldec.BlockListSpec{TypeName: "vboxmanage", Nested: &hcldec.AttrSpec{Name: "vboxmanage", Type: cty.List(cty.String), Required: false}},
|
||||
"vboxmanage_post": &hcldec.BlockListSpec{TypeName: "vboxmanage_post", Nested: &hcldec.AttrSpec{Name: "vboxmanage_post", Type: cty.List(cty.String), Required: false}},
|
||||
"virtualbox_version_file": &hcldec.AttrSpec{Name: "virtualbox_version_file", Type: cty.String, Required: false},
|
||||
|
|
|
@ -123,9 +123,10 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
Comm: &b.config.SSHConfig.Comm,
|
||||
},
|
||||
&vboxcommon.StepShutdown{
|
||||
Command: b.config.ShutdownCommand,
|
||||
Timeout: b.config.ShutdownTimeout,
|
||||
Delay: b.config.PostShutdownDelay,
|
||||
Command: b.config.ShutdownCommand,
|
||||
Timeout: b.config.ShutdownTimeout,
|
||||
Delay: b.config.PostShutdownDelay,
|
||||
DisableShutdown: b.config.DisableShutdown,
|
||||
},
|
||||
&vboxcommon.StepVBoxManage{
|
||||
Commands: b.config.VBoxManagePost,
|
||||
|
|
|
@ -79,6 +79,7 @@ type FlatConfig struct {
|
|||
ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command"`
|
||||
ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout"`
|
||||
PostShutdownDelay *string `mapstructure:"post_shutdown_delay" required:"false" cty:"post_shutdown_delay"`
|
||||
DisableShutdown *bool `mapstructure:"disable_shutdown" required:"false" cty:"disable_shutdown"`
|
||||
VBoxManage [][]string `mapstructure:"vboxmanage" required:"false" cty:"vboxmanage"`
|
||||
VBoxManagePost [][]string `mapstructure:"vboxmanage_post" required:"false" cty:"vboxmanage_post"`
|
||||
VBoxVersionFile *string `mapstructure:"virtualbox_version_file" required:"false" cty:"virtualbox_version_file"`
|
||||
|
@ -173,6 +174,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false},
|
||||
"shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false},
|
||||
"post_shutdown_delay": &hcldec.AttrSpec{Name: "post_shutdown_delay", Type: cty.String, Required: false},
|
||||
"disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false},
|
||||
"vboxmanage": &hcldec.BlockListSpec{TypeName: "vboxmanage", Nested: &hcldec.AttrSpec{Name: "vboxmanage", Type: cty.List(cty.String), Required: false}},
|
||||
"vboxmanage_post": &hcldec.BlockListSpec{TypeName: "vboxmanage_post", Nested: &hcldec.AttrSpec{Name: "vboxmanage_post", Type: cty.List(cty.String), Required: false}},
|
||||
"virtualbox_version_file": &hcldec.AttrSpec{Name: "virtualbox_version_file", Type: cty.String, Required: false},
|
||||
|
|
|
@ -221,24 +221,6 @@ builder.
|
|||
the builder. By default this is `output-BUILDNAME` where "BUILDNAME" is the
|
||||
name of the build.
|
||||
|
||||
- `post_shutdown_delay` (string) - The amount of time to wait after shutting
|
||||
down the virtual machine. Defaults to `2s`. **Hint:** Don't specify a value
|
||||
smaller than `2s` because otherwise the creation of a target snapshot might
|
||||
corrupt the VM because not all locks has been released by VirtualBox.
|
||||
|
||||
- `shutdown_command` (string) - The command to use to gracefully shut down the
|
||||
machine once all the provisioning is done. By default this is an empty
|
||||
string, which tells Packer to just forcefully shut down the machine unless a
|
||||
shutdown command takes place inside script so this may safely be omitted. If
|
||||
one or more scripts require a reboot it is suggested to leave this blank
|
||||
since reboots may fail and specify the final shutdown command in your
|
||||
last script.
|
||||
|
||||
- `shutdown_timeout` (string) - The amount of time to wait after executing the
|
||||
`shutdown_command` for the virtual machine to actually shut down. If it
|
||||
doesn't shut down in this time, it is an error. By default, the timeout is
|
||||
`5m` or five minutes.
|
||||
|
||||
- `skip_export` (boolean) - Defaults to `false`. When enabled, Packer will
|
||||
not export the VM. Useful if the builder should be applied again on the created
|
||||
target snapshot.
|
||||
|
@ -292,6 +274,13 @@ builder.
|
|||
port in this range that appears available. By default this is `5900` to
|
||||
`6000`. The minimum and maximum ports are inclusive.
|
||||
|
||||
|
||||
### Shutdown configuration
|
||||
|
||||
#### Optional:
|
||||
|
||||
<%= partial "partials/builder/virtualbox/common/ShutdownConfig-not-required" %>
|
||||
|
||||
## Boot Command
|
||||
|
||||
The `boot_command` configuration is very important: it specifies the keys to
|
||||
|
|
|
@ -17,4 +17,11 @@
|
|||
down the virtual machine. If you get the error
|
||||
Error removing floppy controller, you might need to set this to 5m
|
||||
or so. By default, the delay is 0s or disabled.
|
||||
|
||||
- `disable_shutdown` (bool) - Packer normally halts the virtual machine after all provisioners have
|
||||
run when no `shutdown_command` is defined. If this is set to `true`, Packer
|
||||
*will not* halt the virtual machine but will assume that you will send the stop
|
||||
signal yourself through the preseed.cfg or your final provisioner.
|
||||
Packer will wait for a default of 5 minutes until the virtual machine is shutdown.
|
||||
The timeout can be changed using `shutdown_timeout` option.
|
||||
|
Loading…
Reference in New Issue