github.com/kaixiang/packer@v0.5.2-0.20140114230416-1f5786b0d7f1/builder/digitalocean/step_shutdown.go (about)

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