github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/builder/digitalocean/step_shutdown.go (about)

     1  package digitalocean
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"time"
     7  
     8  	"github.com/digitalocean/godo"
     9  	"github.com/mitchellh/multistep"
    10  	"github.com/mitchellh/packer/packer"
    11  )
    12  
    13  type stepShutdown struct{}
    14  
    15  func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
    16  	client := state.Get("client").(*godo.Client)
    17  	c := state.Get("config").(Config)
    18  	ui := state.Get("ui").(packer.Ui)
    19  	dropletId := state.Get("droplet_id").(int)
    20  
    21  	// Gracefully power off the droplet. We have to retry this a number
    22  	// of times because sometimes it says it completed when it actually
    23  	// did absolutely nothing (*ALAKAZAM!* magic!). We give up after
    24  	// a pretty arbitrary amount of time.
    25  	ui.Say("Gracefully shutting down droplet...")
    26  	_, _, err := client.DropletActions.Shutdown(dropletId)
    27  	if err != nil {
    28  		// If we get an error the first time, actually report it
    29  		err := fmt.Errorf("Error shutting down droplet: %s", err)
    30  		state.Put("error", err)
    31  		ui.Error(err.Error())
    32  		return multistep.ActionHalt
    33  	}
    34  
    35  	// A channel we use as a flag to end our goroutines
    36  	done := make(chan struct{})
    37  	shutdownRetryDone := make(chan struct{})
    38  
    39  	// Make sure we wait for the shutdown retry goroutine to end
    40  	// before moving on.
    41  	defer func() {
    42  		close(done)
    43  		<-shutdownRetryDone
    44  	}()
    45  
    46  	// Start a goroutine that just keeps trying to shut down the
    47  	// droplet.
    48  	go func() {
    49  		defer close(shutdownRetryDone)
    50  
    51  		for attempts := 2; attempts > 0; attempts++ {
    52  			log.Printf("ShutdownDroplet attempt #%d...", attempts)
    53  			_, _, err := client.DropletActions.Shutdown(dropletId)
    54  			if err != nil {
    55  				log.Printf("Shutdown retry error: %s", err)
    56  			}
    57  
    58  			select {
    59  			case <-done:
    60  				return
    61  			case <-time.After(20 * time.Second):
    62  				// Retry!
    63  			}
    64  		}
    65  	}()
    66  
    67  	err = waitForDropletState("off", dropletId, client, c.StateTimeout)
    68  	if err != nil {
    69  		// If we get an error the first time, actually report it
    70  		err := fmt.Errorf("Error shutting down droplet: %s", err)
    71  		state.Put("error", err)
    72  		ui.Error(err.Error())
    73  		return multistep.ActionHalt
    74  	}
    75  
    76  	if err := waitForDropletUnlocked(client, dropletId, c.StateTimeout); err != nil {
    77  		// If we get an error the first time, actually report it
    78  		err := fmt.Errorf("Error shutting down droplet: %s", err)
    79  		state.Put("error", err)
    80  		ui.Error(err.Error())
    81  		return multistep.ActionHalt
    82  	}
    83  
    84  	return multistep.ActionContinue
    85  }
    86  
    87  func (s *stepShutdown) Cleanup(state multistep.StateBag) {
    88  	// no cleanup
    89  }