diff --git a/builder/xenserver/common/step_shutdown_and_export.go b/builder/xenserver/common/step_export.go similarity index 63% rename from builder/xenserver/common/step_shutdown_and_export.go rename to builder/xenserver/common/step_export.go index 39fe0d6..678514b 100644 --- a/builder/xenserver/common/step_shutdown_and_export.go +++ b/builder/xenserver/common/step_export.go @@ -1,7 +1,5 @@ package common -/* Taken from https://raw.githubusercontent.com/mitchellh/packer/master/builder/qemu/step_prepare_output_dir.go */ - import ( "crypto/tls" "fmt" @@ -10,10 +8,9 @@ import ( "io" "net/http" "os" - "time" ) -type StepShutdownAndExport struct{} +type StepExport struct{} func downloadFile(url, filename string) (err error) { @@ -44,7 +41,7 @@ func downloadFile(url, filename string) (err error) { return nil } -func (StepShutdownAndExport) Run(state multistep.StateBag) multistep.StepAction { +func (StepExport) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("commonconfig").(CommonConfig) ui := state.Get("ui").(packer.Ui) client := state.Get("client").(XenAPIClient) @@ -56,58 +53,7 @@ func (StepShutdownAndExport) Run(state multistep.StateBag) multistep.StepAction return multistep.ActionHalt } - ui.Say("Step: Shutdown and export") - - // Shutdown the VM - success := func() bool { - if config.ShutdownCommand != "" { - ui.Say("Executing shutdown command...") - - _, err := ExecuteGuestSSHCmd(state, config.ShutdownCommand) - if err != nil { - ui.Error(fmt.Sprintf("Shutdown command failed: %s", err.Error())) - return false - } - - ui.Say("Waiting for VM to enter Halted state...") - - err = InterruptibleWait{ - Predicate: func() (bool, error) { - power_state, err := instance.GetPowerState() - return power_state == "Halted", err - }, - PredicateInterval: 5 * time.Second, - Timeout: 300 * time.Second, - }.Wait(state) - - if err != nil { - ui.Error(fmt.Sprintf("Error waiting for VM to halt: %s", err.Error())) - return false - } - - } else { - ui.Say("Attempting to cleanly shutdown the VM...") - - err = instance.CleanShutdown() - if err != nil { - ui.Error(fmt.Sprintf("Could not shut down VM: %s", err.Error())) - return false - } - - } - return true - }() - - if !success { - ui.Say("Forcing hard shutdown of the VM...") - err = instance.HardShutdown() - if err != nil { - ui.Error(fmt.Sprintf("Could not hard shut down VM -- giving up: %s", err.Error())) - return multistep.ActionHalt - } - } - - ui.Say("Successfully shut down VM") + ui.Say("Step: export artifact") switch config.Format { case "xva": @@ -172,4 +118,4 @@ func (StepShutdownAndExport) Run(state multistep.StateBag) multistep.StepAction return multistep.ActionContinue } -func (StepShutdownAndExport) Cleanup(state multistep.StateBag) {} +func (StepExport) Cleanup(state multistep.StateBag) {} diff --git a/builder/xenserver/common/step_shutdown.go b/builder/xenserver/common/step_shutdown.go new file mode 100644 index 0000000..52fabc4 --- /dev/null +++ b/builder/xenserver/common/step_shutdown.go @@ -0,0 +1,79 @@ +package common + +import ( + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "time" +) + +type StepShutdown struct{} + +func (StepShutdown) Run(state multistep.StateBag) multistep.StepAction { + config := state.Get("commonconfig").(CommonConfig) + ui := state.Get("ui").(packer.Ui) + client := state.Get("client").(XenAPIClient) + instance_uuid := state.Get("instance_uuid").(string) + + instance, err := client.GetVMByUuid(instance_uuid) + if err != nil { + ui.Error(fmt.Sprintf("Could not get VM with UUID '%s': %s", instance_uuid, err.Error())) + return multistep.ActionHalt + } + + ui.Say("Step: Shutdown and export") + + // Shutdown the VM + success := func() bool { + if config.ShutdownCommand != "" { + ui.Message("Executing shutdown command...") + + _, err := ExecuteGuestSSHCmd(state, config.ShutdownCommand) + if err != nil { + ui.Error(fmt.Sprintf("Shutdown command failed: %s", err.Error())) + return false + } + + ui.Message("Waiting for VM to enter Halted state...") + + err = InterruptibleWait{ + Predicate: func() (bool, error) { + power_state, err := instance.GetPowerState() + return power_state == "Halted", err + }, + PredicateInterval: 5 * time.Second, + Timeout: 300 * time.Second, + }.Wait(state) + + if err != nil { + ui.Error(fmt.Sprintf("Error waiting for VM to halt: %s", err.Error())) + return false + } + + } else { + ui.Message("Attempting to cleanly shutdown the VM...") + + err = instance.CleanShutdown() + if err != nil { + ui.Error(fmt.Sprintf("Could not shut down VM: %s", err.Error())) + return false + } + + } + return true + }() + + if !success { + ui.Say("WARNING: Forcing hard shutdown of the VM...") + err = instance.HardShutdown() + if err != nil { + ui.Error(fmt.Sprintf("Could not hard shut down VM -- giving up: %s", err.Error())) + return multistep.ActionHalt + } + } + + ui.Message("Successfully shut down VM") + return multistep.ActionContinue +} + +func (StepShutdown) Cleanup(state multistep.StateBag) {} diff --git a/builder/xenserver/iso/builder.go b/builder/xenserver/iso/builder.go index 27577c5..42e7a15 100644 --- a/builder/xenserver/iso/builder.go +++ b/builder/xenserver/iso/builder.go @@ -272,7 +272,17 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa SSHWaitTimeout: self.config.SSHWaitTimeout, }, new(common.StepProvision), - new(xscommon.StepShutdownAndExport), + new(xscommon.StepShutdown), + &xscommon.StepDetachVdi{ + VdiUuidKey: "floppy_vdi_uuid", + }, + &xscommon.StepDetachVdi{ + VdiUuidKey: "iso_vdi_uuid", + }, + &xscommon.StepDetachVdi{ + VdiUuidKey: "tools_vdi_uuid", + }, + new(xscommon.StepExport), } self.runner = &multistep.BasicRunner{Steps: steps} diff --git a/builder/xenserver/xva/builder.go b/builder/xenserver/xva/builder.go index 9c4cbf1..5c90536 100644 --- a/builder/xenserver/xva/builder.go +++ b/builder/xenserver/xva/builder.go @@ -160,13 +160,14 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa SSHWaitTimeout: self.config.SSHWaitTimeout, }, new(common.StepProvision), + new(xscommon.StepShutdown), &xscommon.StepDetachVdi{ VdiUuidKey: "floppy_vdi_uuid", }, &xscommon.StepDetachVdi{ - VdiUuidKey: "iso_vdi_uuid", + VdiUuidKey: "tools_vdi_uuid", }, - new(xscommon.StepShutdownAndExport), + new(xscommon.StepExport), } self.runner = &multistep.BasicRunner{Steps: steps}