github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/builder/qemu/step_shutdown.go (about) 1 package qemu 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "time" 8 9 "github.com/mitchellh/multistep" 10 "github.com/mitchellh/packer/packer" 11 ) 12 13 // This step shuts down the machine. It first attempts to do so gracefully, 14 // but ultimately forcefully shuts it down if that fails. 15 // 16 // Uses: 17 // communicator packer.Communicator 18 // config *config 19 // driver Driver 20 // ui packer.Ui 21 // 22 // Produces: 23 // <nothing> 24 type stepShutdown struct{} 25 26 func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction { 27 config := state.Get("config").(*Config) 28 driver := state.Get("driver").(Driver) 29 ui := state.Get("ui").(packer.Ui) 30 31 if state.Get("communicator") == nil { 32 cancelCh := make(chan struct{}, 1) 33 go func() { 34 defer close(cancelCh) 35 <-time.After(config.shutdownTimeout) 36 }() 37 ui.Say("Waiting for shutdown...") 38 if ok := driver.WaitForShutdown(cancelCh); ok { 39 log.Println("VM shut down.") 40 return multistep.ActionContinue 41 } else { 42 err := fmt.Errorf("Failed to shutdown") 43 state.Put("error", err) 44 ui.Error(err.Error()) 45 return multistep.ActionHalt 46 } 47 } 48 49 comm := state.Get("communicator").(packer.Communicator) 50 if config.ShutdownCommand != "" { 51 ui.Say("Gracefully halting virtual machine...") 52 log.Printf("Executing shutdown command: %s", config.ShutdownCommand) 53 cmd := &packer.RemoteCmd{Command: config.ShutdownCommand} 54 if err := cmd.StartWithUi(comm, ui); err != nil { 55 err := fmt.Errorf("Failed to send shutdown command: %s", err) 56 state.Put("error", err) 57 ui.Error(err.Error()) 58 return multistep.ActionHalt 59 } 60 61 // Start the goroutine that will time out our graceful attempt 62 cancelCh := make(chan struct{}, 1) 63 go func() { 64 defer close(cancelCh) 65 <-time.After(config.shutdownTimeout) 66 }() 67 68 log.Printf("Waiting max %s for shutdown to complete", config.shutdownTimeout) 69 if ok := driver.WaitForShutdown(cancelCh); !ok { 70 err := errors.New("Timeout while waiting for machine to shut down.") 71 state.Put("error", err) 72 ui.Error(err.Error()) 73 return multistep.ActionHalt 74 } 75 } else { 76 ui.Say("Halting the virtual machine...") 77 if err := driver.Stop(); err != nil { 78 err := fmt.Errorf("Error stopping VM: %s", err) 79 state.Put("error", err) 80 ui.Error(err.Error()) 81 return multistep.ActionHalt 82 } 83 } 84 85 log.Println("VM shut down.") 86 return multistep.ActionContinue 87 } 88 89 func (s *stepShutdown) Cleanup(state multistep.StateBag) {}