github.phpd.cn/hashicorp/packer@v1.3.2/builder/virtualbox/common/step_shutdown.go (about) 1 package common 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "log" 8 "time" 9 10 "github.com/hashicorp/packer/helper/multistep" 11 "github.com/hashicorp/packer/packer" 12 ) 13 14 // This step shuts down the machine. It first attempts to do so gracefully, 15 // but ultimately forcefully shuts it down if that fails. 16 // 17 // Uses: 18 // communicator packer.Communicator 19 // driver Driver 20 // ui packer.Ui 21 // vmName string 22 // 23 // Produces: 24 // <nothing> 25 type StepShutdown struct { 26 Command string 27 Timeout time.Duration 28 Delay time.Duration 29 } 30 31 func (s *StepShutdown) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { 32 comm := state.Get("communicator").(packer.Communicator) 33 driver := state.Get("driver").(Driver) 34 ui := state.Get("ui").(packer.Ui) 35 vmName := state.Get("vmName").(string) 36 37 if s.Command != "" { 38 ui.Say("Gracefully halting virtual machine...") 39 log.Printf("Executing shutdown command: %s", s.Command) 40 cmd := &packer.RemoteCmd{Command: s.Command} 41 if err := cmd.StartWithUi(comm, ui); err != nil { 42 err := fmt.Errorf("Failed to send shutdown command: %s", err) 43 state.Put("error", err) 44 ui.Error(err.Error()) 45 return multistep.ActionHalt 46 } 47 48 // Wait for the machine to actually shut down 49 log.Printf("Waiting max %s for shutdown to complete", s.Timeout) 50 shutdownTimer := time.After(s.Timeout) 51 for { 52 running, _ := driver.IsRunning(vmName) 53 if !running { 54 55 if s.Delay.Nanoseconds() > 0 { 56 log.Printf("Delay for %s after shutdown to allow locks to clear...", s.Delay) 57 time.Sleep(s.Delay) 58 } 59 60 break 61 } 62 63 select { 64 case <-shutdownTimer: 65 err := errors.New("Timeout while waiting for machine to shut down.") 66 state.Put("error", err) 67 ui.Error(err.Error()) 68 return multistep.ActionHalt 69 default: 70 time.Sleep(500 * time.Millisecond) 71 } 72 } 73 } else { 74 ui.Say("Halting the virtual machine...") 75 if err := driver.Stop(vmName); err != nil { 76 err := fmt.Errorf("Error stopping VM: %s", err) 77 state.Put("error", err) 78 ui.Error(err.Error()) 79 return multistep.ActionHalt 80 } 81 } 82 83 log.Println("VM shut down.") 84 return multistep.ActionContinue 85 } 86 87 func (s *StepShutdown) Cleanup(state multistep.StateBag) {}