github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/builder/hyperv/common/step_shutdown.go (about)

     1  package common
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"github.com/mitchellh/multistep"
     8  	"github.com/mitchellh/packer/packer"
     9  	"log"
    10  	"time"
    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  //   dir OutputDir
    19  //   driver Driver
    20  //   ui     packer.Ui
    21  //   vmx_path string
    22  //
    23  // Produces:
    24  //   <nothing>
    25  type StepShutdown struct {
    26  	Command string
    27  	Timeout time.Duration
    28  }
    29  
    30  func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
    31  
    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  
    41  		var stdout, stderr bytes.Buffer
    42  		cmd := &packer.RemoteCmd{
    43  			Command: s.Command,
    44  			Stdout:  &stdout,
    45  			Stderr:  &stderr,
    46  		}
    47  		if err := comm.Start(cmd); err != nil {
    48  			err := fmt.Errorf("Failed to send shutdown command: %s", err)
    49  			state.Put("error", err)
    50  			ui.Error(err.Error())
    51  			return multistep.ActionHalt
    52  		}
    53  
    54  		// Wait for the command to run so we can print std{err,out}
    55  		// We don't care if the command errored, since we'll notice
    56  		// if the vm didn't shut down.
    57  		cmd.Wait()
    58  
    59  		log.Printf("Shutdown stdout: %s", stdout.String())
    60  		log.Printf("Shutdown stderr: %s", stderr.String())
    61  
    62  		// Wait for the machine to actually shut down
    63  		log.Printf("Waiting max %s for shutdown to complete", s.Timeout)
    64  		shutdownTimer := time.After(s.Timeout)
    65  		for {
    66  			running, _ := driver.IsRunning(vmName)
    67  			if !running {
    68  				break
    69  			}
    70  
    71  			select {
    72  			case <-shutdownTimer:
    73  				err := errors.New("Timeout while waiting for machine to shut down.")
    74  				state.Put("error", err)
    75  				ui.Error(err.Error())
    76  				return multistep.ActionHalt
    77  			default:
    78  				time.Sleep(150 * time.Millisecond)
    79  			}
    80  		}
    81  	} else {
    82  		ui.Say("Forcibly halting virtual machine...")
    83  		if err := driver.Stop(vmName); err != nil {
    84  			err := fmt.Errorf("Error stopping VM: %s", err)
    85  			state.Put("error", err)
    86  			ui.Error(err.Error())
    87  			return multistep.ActionHalt
    88  		}
    89  	}
    90  
    91  	log.Println("VM shut down.")
    92  	return multistep.ActionContinue
    93  }
    94  
    95  func (s *StepShutdown) Cleanup(state multistep.StateBag) {}