github.com/sneal/packer@v0.5.2/builder/openstack/server.go (about)

     1  package openstack
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"github.com/mitchellh/multistep"
     7  	"github.com/rackspace/gophercloud"
     8  	"log"
     9  	"time"
    10  )
    11  
    12  // StateRefreshFunc is a function type used for StateChangeConf that is
    13  // responsible for refreshing the item being watched for a state change.
    14  //
    15  // It returns three results. `result` is any object that will be returned
    16  // as the final object after waiting for state change. This allows you to
    17  // return the final updated object, for example an openstack instance after
    18  // refreshing it.
    19  //
    20  // `state` is the latest state of that object. And `err` is any error that
    21  // may have happened while refreshing the state.
    22  type StateRefreshFunc func() (result interface{}, state string, progress int, err error)
    23  
    24  // StateChangeConf is the configuration struct used for `WaitForState`.
    25  type StateChangeConf struct {
    26  	Pending   []string
    27  	Refresh   StateRefreshFunc
    28  	StepState multistep.StateBag
    29  	Target    string
    30  }
    31  
    32  // ServerStateRefreshFunc returns a StateRefreshFunc that is used to watch
    33  // an openstacn server.
    34  func ServerStateRefreshFunc(csp gophercloud.CloudServersProvider, s *gophercloud.Server) StateRefreshFunc {
    35  	return func() (interface{}, string, int, error) {
    36  		resp, err := csp.ServerById(s.Id)
    37  		if err != nil {
    38  			log.Printf("Error on ServerStateRefresh: %s", err)
    39  			return nil, "", 0, err
    40  		}
    41  
    42  		return resp, resp.Status, resp.Progress, nil
    43  	}
    44  }
    45  
    46  // WaitForState watches an object and waits for it to achieve a certain
    47  // state.
    48  func WaitForState(conf *StateChangeConf) (i interface{}, err error) {
    49  	log.Printf("Waiting for state to become: %s", conf.Target)
    50  
    51  	for {
    52  		var currentProgress int
    53  		var currentState string
    54  		i, currentState, currentProgress, err = conf.Refresh()
    55  		if err != nil {
    56  			return
    57  		}
    58  
    59  		if currentState == conf.Target {
    60  			return
    61  		}
    62  
    63  		if conf.StepState != nil {
    64  			if _, ok := conf.StepState.GetOk(multistep.StateCancelled); ok {
    65  				return nil, errors.New("interrupted")
    66  			}
    67  		}
    68  
    69  		found := false
    70  		for _, allowed := range conf.Pending {
    71  			if currentState == allowed {
    72  				found = true
    73  				break
    74  			}
    75  		}
    76  
    77  		if !found {
    78  			fmt.Errorf("unexpected state '%s', wanted target '%s'", currentState, conf.Target)
    79  			return
    80  		}
    81  
    82  		log.Printf("Waiting for state to become: %s currently %s (%d%%)", conf.Target, currentState, currentProgress)
    83  		time.Sleep(2 * time.Second)
    84  	}
    85  
    86  	return
    87  }