github.com/mitchellh/packer@v1.3.2/builder/qemu/step_shutdown.go (about)

     1  package qemu
     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  //   config *config
    20  //   driver Driver
    21  //   ui     packer.Ui
    22  //
    23  // Produces:
    24  //   <nothing>
    25  type stepShutdown struct{}
    26  
    27  func (s *stepShutdown) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
    28  	config := state.Get("config").(*Config)
    29  	driver := state.Get("driver").(Driver)
    30  	ui := state.Get("ui").(packer.Ui)
    31  
    32  	if state.Get("communicator") == nil {
    33  		cancelCh := make(chan struct{}, 1)
    34  		go func() {
    35  			defer close(cancelCh)
    36  			<-time.After(config.shutdownTimeout)
    37  		}()
    38  		ui.Say("Waiting for shutdown...")
    39  		if ok := driver.WaitForShutdown(cancelCh); ok {
    40  			log.Println("VM shut down.")
    41  			return multistep.ActionContinue
    42  		} else {
    43  			err := fmt.Errorf("Failed to shutdown")
    44  			state.Put("error", err)
    45  			ui.Error(err.Error())
    46  			return multistep.ActionHalt
    47  		}
    48  	}
    49  
    50  	comm := state.Get("communicator").(packer.Communicator)
    51  	if config.ShutdownCommand != "" {
    52  		ui.Say("Gracefully halting virtual machine...")
    53  		log.Printf("Executing shutdown command: %s", config.ShutdownCommand)
    54  		cmd := &packer.RemoteCmd{Command: config.ShutdownCommand}
    55  		if err := cmd.StartWithUi(comm, ui); err != nil {
    56  			err := fmt.Errorf("Failed to send shutdown command: %s", err)
    57  			state.Put("error", err)
    58  			ui.Error(err.Error())
    59  			return multistep.ActionHalt
    60  		}
    61  
    62  		// Start the goroutine that will time out our graceful attempt
    63  		cancelCh := make(chan struct{}, 1)
    64  		go func() {
    65  			defer close(cancelCh)
    66  			<-time.After(config.shutdownTimeout)
    67  		}()
    68  
    69  		log.Printf("Waiting max %s for shutdown to complete", config.shutdownTimeout)
    70  		if ok := driver.WaitForShutdown(cancelCh); !ok {
    71  			err := errors.New("Timeout while waiting for machine to shut down.")
    72  			state.Put("error", err)
    73  			ui.Error(err.Error())
    74  			return multistep.ActionHalt
    75  		}
    76  	} else {
    77  		ui.Say("Halting the virtual machine...")
    78  		if err := driver.Stop(); 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  func (s *stepShutdown) Cleanup(state multistep.StateBag) {}