mirror of
https://github.com/hashicorp/packer.git
synced 2026-06-09 08:42:33 -04:00
Adds acpi_shutdown to virtualbox builder (#8587)
This commit is contained in:
parent
d9a128a375
commit
baa203bb53
13 changed files with 77 additions and 3 deletions
|
|
@ -40,6 +40,9 @@ type Driver interface {
|
|||
// Stop stops a running machine, forcefully.
|
||||
Stop(string) error
|
||||
|
||||
// ACPIStop stops a running machine via ACPI power button.
|
||||
StopViaACPI(string) error
|
||||
|
||||
// SuppressMessages should do what needs to be done in order to
|
||||
// suppress any annoying popups from VirtualBox.
|
||||
SuppressMessages() error
|
||||
|
|
|
|||
|
|
@ -161,6 +161,14 @@ func (d *VBox42Driver) Stop(name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *VBox42Driver) StopViaACPI(name string) error {
|
||||
if err := d.VBoxManage("controlvm", name, "acpipowerbutton"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *VBox42Driver) SuppressMessages() error {
|
||||
extraData := map[string]string{
|
||||
"GUI/RegistrationData": "triesLeft=0",
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ type DriverMock struct {
|
|||
IsRunningReturn bool
|
||||
IsRunningErr error
|
||||
|
||||
StopName string
|
||||
StopErr error
|
||||
StopViaACPIName string
|
||||
StopName string
|
||||
StopErr error
|
||||
|
||||
SuppressMessagesCalled bool
|
||||
SuppressMessagesErr error
|
||||
|
|
@ -112,6 +113,11 @@ func (d *DriverMock) Stop(name string) error {
|
|||
return d.StopErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) StopViaACPI(name string) error {
|
||||
d.StopViaACPIName = name
|
||||
return d.StopErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) SuppressMessages() error {
|
||||
d.SuppressMessagesCalled = true
|
||||
return d.SuppressMessagesErr
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ type ShutdownConfig struct {
|
|||
// 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"`
|
||||
// If it's set to true, it will shutdown the VM via power button. It could be a good option
|
||||
// when keeping the machine state is necessary after shutting it down.
|
||||
ACPIShutdown bool `mapstructure:"acpi_shutdown" required:"false"`
|
||||
}
|
||||
|
||||
func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ type StepShutdown struct {
|
|||
Timeout time.Duration
|
||||
Delay time.Duration
|
||||
DisableShutdown bool
|
||||
ACPIShutdown bool
|
||||
}
|
||||
|
||||
func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
|
|
@ -35,7 +36,15 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
|
|||
ui := state.Get("ui").(packer.Ui)
|
||||
vmName := state.Get("vmName").(string)
|
||||
|
||||
if !s.DisableShutdown {
|
||||
if s.ACPIShutdown {
|
||||
ui.Say("Shuting down the virtual machine via ACPI power button...")
|
||||
if err := driver.StopViaACPI(vmName); err != nil {
|
||||
err := fmt.Errorf("Error stopping VM: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
} else if !s.DisableShutdown {
|
||||
if s.Command != "" {
|
||||
ui.Say("Gracefully halting virtual machine...")
|
||||
log.Printf("Executing shutdown command: %s", s.Command)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ func TestStepShutdown_noShutdownCommand(t *testing.T) {
|
|||
state := testState(t)
|
||||
step := new(StepShutdown)
|
||||
step.DisableShutdown = false
|
||||
step.ACPIShutdown = false
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
state.Put("communicator", comm)
|
||||
|
|
@ -47,6 +48,7 @@ func TestStepShutdown_shutdownCommand(t *testing.T) {
|
|||
step.Command = "poweroff"
|
||||
step.Timeout = 1 * time.Second
|
||||
step.DisableShutdown = false
|
||||
step.ACPIShutdown = false
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
state.Put("communicator", comm)
|
||||
|
|
@ -85,6 +87,7 @@ func TestStepShutdown_shutdownTimeout(t *testing.T) {
|
|||
step.Command = "poweroff"
|
||||
step.Timeout = 1 * time.Second
|
||||
step.DisableShutdown = false
|
||||
step.ACPIShutdown = false
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
state.Put("communicator", comm)
|
||||
|
|
@ -113,6 +116,7 @@ func TestStepShutdown_DisableShutdown(t *testing.T) {
|
|||
state := testState(t)
|
||||
step := new(StepShutdown)
|
||||
step.DisableShutdown = true
|
||||
step.ACPIShutdown = false
|
||||
step.Timeout = 2 * time.Second
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
|
|
@ -137,3 +141,32 @@ func TestStepShutdown_DisableShutdown(t *testing.T) {
|
|||
t.Fatal("should NOT have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepShutdown_ACPIShutdown(t *testing.T) {
|
||||
state := testState(t)
|
||||
step := new(StepShutdown)
|
||||
step.ACPIShutdown = true
|
||||
step.Timeout = 2 * time.Second
|
||||
|
||||
comm := new(packer.MockCommunicator)
|
||||
state.Put("communicator", comm)
|
||||
state.Put("vmName", "foo")
|
||||
|
||||
driver := state.Get("driver").(*DriverMock)
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
// Test that Stop was just called
|
||||
if driver.StopViaACPIName != "foo" {
|
||||
t.Fatal("should call stop via ACPI")
|
||||
}
|
||||
if comm.StartCalled {
|
||||
t.Fatal("comm start should not be called")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,6 +377,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
Timeout: b.config.ShutdownTimeout,
|
||||
Delay: b.config.PostShutdownDelay,
|
||||
DisableShutdown: b.config.DisableShutdown,
|
||||
ACPIShutdown: b.config.ACPIShutdown,
|
||||
},
|
||||
&vboxcommon.StepRemoveDevices{
|
||||
Bundling: b.config.VBoxBundleConfig,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ type FlatConfig struct {
|
|||
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"`
|
||||
ACPIShutdown *bool `mapstructure:"acpi_shutdown" required:"false" cty:"acpi_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"`
|
||||
|
|
@ -159,6 +160,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"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},
|
||||
"acpi_shutdown": &hcldec.AttrSpec{Name: "acpi_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},
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
Timeout: b.config.ShutdownTimeout,
|
||||
Delay: b.config.PostShutdownDelay,
|
||||
DisableShutdown: b.config.DisableShutdown,
|
||||
ACPIShutdown: b.config.ACPIShutdown,
|
||||
},
|
||||
&vboxcommon.StepRemoveDevices{
|
||||
GuestAdditionsInterface: b.config.GuestAdditionsInterface,
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ type FlatConfig struct {
|
|||
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"`
|
||||
ACPIShutdown *bool `mapstructure:"acpi_shutdown" required:"false" cty:"acpi_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"`
|
||||
|
|
@ -182,6 +183,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"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},
|
||||
"acpi_shutdown": &hcldec.AttrSpec{Name: "acpi_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},
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
Timeout: b.config.ShutdownTimeout,
|
||||
Delay: b.config.PostShutdownDelay,
|
||||
DisableShutdown: b.config.DisableShutdown,
|
||||
ACPIShutdown: b.config.ACPIShutdown,
|
||||
},
|
||||
&vboxcommon.StepVBoxManage{
|
||||
Commands: b.config.VBoxManagePost,
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ type FlatConfig struct {
|
|||
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"`
|
||||
ACPIShutdown *bool `mapstructure:"acpi_shutdown" required:"false" cty:"acpi_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"`
|
||||
|
|
@ -178,6 +179,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"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},
|
||||
"acpi_shutdown": &hcldec.AttrSpec{Name: "acpi_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},
|
||||
|
|
|
|||
|
|
@ -24,4 +24,7 @@
|
|||
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.
|
||||
|
||||
- `acpi_shutdown` (bool) - If it's set to true, it will shutdown the VM via power button. It could be a good option
|
||||
when keeping the machine state is necessary after shutting it down.
|
||||
|
||||
Loading…
Reference in a new issue