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