Add disable_shutdown option to VSphere builders

Also don't try to shut down VM if it's already off, otherwise VSphere would raise an error: "The attempted operation cannot be performed in the current state (Powered off)."
This commit is contained in:
Vladislav Rassokhin 2020-04-20 20:56:53 +03:00
parent 1155ab8e3c
commit 03c4bebf00
6 changed files with 47 additions and 10 deletions

View File

@ -92,6 +92,7 @@ type FlatConfig struct {
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"`
Command *string `mapstructure:"shutdown_command" cty:"shutdown_command"`
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"`
DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown"`
CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot"`
ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template"`
Export *common.FlatExportConfig `mapstructure:"export" cty:"export"`
@ -191,6 +192,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
"shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false},
"shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false},
"disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false},
"create_snapshot": &hcldec.AttrSpec{Name: "create_snapshot", Type: cty.Bool, Required: false},
"convert_to_template": &hcldec.AttrSpec{Name: "convert_to_template", Type: cty.Bool, Required: false},
"export": &hcldec.BlockSpec{TypeName: "export", Nested: hcldec.ObjectSpec((*common.FlatExportConfig)(nil).HCL2Spec())},

View File

@ -19,9 +19,16 @@ type ShutdownConfig struct {
// Specify a VM guest shutdown command. VMware guest tools are used by
// default.
Command string `mapstructure:"shutdown_command"`
// Amount of time to wait for graceful VM shutdown. Examples 45s and 10m.
// Defaults to 5m(5 minutes).
// Amount of time to wait for graceful VM shutdown.
// Defaults to 5m or five minutes.
Timeout time.Duration `mapstructure:"shutdown_timeout"`
// 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 five minutes until the virtual machine is shutdown.
// The timeout can be changed using `shutdown_timeout` option.
DisableShutdown bool `mapstructure:"disable_shutdown"`
}
func (c *ShutdownConfig) Prepare() []error {
@ -43,7 +50,15 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
comm := state.Get("communicator").(packer.Communicator)
vm := state.Get("vm").(*driver.VirtualMachine)
if s.Config.Command != "" {
if off, _ := vm.IsPoweredOff(); off {
// Probably power off initiated by last provisioner, though disable_shutdown is not set
ui.Say("VM is already powered off")
return multistep.ActionContinue
}
if s.Config.DisableShutdown {
ui.Say("Automatic shutdown disabled. Please shutdown virtual machine.")
} else if s.Config.Command != "" {
ui.Say("Executing shutdown command...")
log.Printf("Shutdown command: %s", s.Config.Command)
@ -59,7 +74,7 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis
return multistep.ActionHalt
}
} else {
ui.Say("Shut down VM...")
ui.Say("Shutting down VM...")
err := vm.StartShutdown()
if err != nil {

View File

@ -9,8 +9,9 @@ import (
// FlatShutdownConfig is an auto-generated flat version of ShutdownConfig.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatShutdownConfig struct {
Command *string `mapstructure:"shutdown_command" cty:"shutdown_command"`
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"`
Command *string `mapstructure:"shutdown_command" cty:"shutdown_command"`
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"`
DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown"`
}
// FlatMapstructure returns a new FlatShutdownConfig.
@ -27,6 +28,7 @@ func (*FlatShutdownConfig) HCL2Spec() map[string]hcldec.Spec {
s := 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},
"disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false},
}
return s
}

View File

@ -454,6 +454,15 @@ func (vm *VirtualMachine) PowerOff() error {
return err
}
func (vm *VirtualMachine) IsPoweredOff() (bool, error) {
state, err := vm.vm.PowerState(vm.driver.ctx)
if err != nil {
return false, err
}
return state == types.VirtualMachinePowerStatePoweredOff, nil
}
func (vm *VirtualMachine) StartShutdown() error {
err := vm.vm.ShutdownGuest(vm.driver.ctx)
return err
@ -462,11 +471,11 @@ func (vm *VirtualMachine) StartShutdown() error {
func (vm *VirtualMachine) WaitForShutdown(ctx context.Context, timeout time.Duration) error {
shutdownTimer := time.After(timeout)
for {
powerState, err := vm.vm.PowerState(vm.driver.ctx)
off, err := vm.IsPoweredOff()
if err != nil {
return err
}
if powerState == "poweredOff" {
if off {
break
}

View File

@ -118,6 +118,7 @@ type FlatConfig struct {
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"`
Command *string `mapstructure:"shutdown_command" cty:"shutdown_command"`
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"`
DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown"`
CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot"`
ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template"`
Export *common.FlatExportConfig `mapstructure:"export" cty:"export"`
@ -243,6 +244,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
"shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false},
"shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false},
"disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false},
"create_snapshot": &hcldec.AttrSpec{Name: "create_snapshot", Type: cty.Bool, Required: false},
"convert_to_template": &hcldec.AttrSpec{Name: "convert_to_template", Type: cty.Bool, Required: false},
"export": &hcldec.BlockSpec{TypeName: "export", Nested: hcldec.ObjectSpec((*common.FlatExportConfig)(nil).HCL2Spec())},

View File

@ -3,6 +3,13 @@
- `shutdown_command` (string) - Specify a VM guest shutdown command. VMware guest tools are used by
default.
- `shutdown_timeout` (duration string | ex: "1h5m2s") - Amount of time to wait for graceful VM shutdown. Examples 45s and 10m.
Defaults to 5m(5 minutes).
- `shutdown_timeout` (duration string | ex: "1h5m2s") - Amount of time to wait for graceful VM shutdown.
Defaults to 5m or five minutes.
- `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 five minutes until the virtual machine is shutdown.
The timeout can be changed using `shutdown_timeout` option.