github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/google/compute_operation.go (about)

     1  package google
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"time"
     8  
     9  	"github.com/hashicorp/terraform/helper/resource"
    10  	"google.golang.org/api/compute/v1"
    11  )
    12  
    13  // OperationWaitType is an enum specifying what type of operation
    14  // we're waiting on.
    15  type ComputeOperationWaitType byte
    16  
    17  const (
    18  	ComputeOperationWaitInvalid ComputeOperationWaitType = iota
    19  	ComputeOperationWaitGlobal
    20  	ComputeOperationWaitRegion
    21  	ComputeOperationWaitZone
    22  )
    23  
    24  type ComputeOperationWaiter struct {
    25  	Service *compute.Service
    26  	Op      *compute.Operation
    27  	Project string
    28  	Region  string
    29  	Type    ComputeOperationWaitType
    30  	Zone    string
    31  }
    32  
    33  func (w *ComputeOperationWaiter) RefreshFunc() resource.StateRefreshFunc {
    34  	return func() (interface{}, string, error) {
    35  		var op *compute.Operation
    36  		var err error
    37  
    38  		switch w.Type {
    39  		case ComputeOperationWaitGlobal:
    40  			op, err = w.Service.GlobalOperations.Get(
    41  				w.Project, w.Op.Name).Do()
    42  		case ComputeOperationWaitRegion:
    43  			op, err = w.Service.RegionOperations.Get(
    44  				w.Project, w.Region, w.Op.Name).Do()
    45  		case ComputeOperationWaitZone:
    46  			op, err = w.Service.ZoneOperations.Get(
    47  				w.Project, w.Zone, w.Op.Name).Do()
    48  		default:
    49  			return nil, "bad-type", fmt.Errorf(
    50  				"Invalid wait type: %#v", w.Type)
    51  		}
    52  
    53  		if err != nil {
    54  			return nil, "", err
    55  		}
    56  
    57  		log.Printf("[DEBUG] Got %q when asking for operation %q", op.Status, w.Op.Name)
    58  
    59  		return op, op.Status, nil
    60  	}
    61  }
    62  
    63  func (w *ComputeOperationWaiter) Conf() *resource.StateChangeConf {
    64  	return &resource.StateChangeConf{
    65  		Pending: []string{"PENDING", "RUNNING"},
    66  		Target:  []string{"DONE"},
    67  		Refresh: w.RefreshFunc(),
    68  	}
    69  }
    70  
    71  // ComputeOperationError wraps compute.OperationError and implements the
    72  // error interface so it can be returned.
    73  type ComputeOperationError compute.OperationError
    74  
    75  func (e ComputeOperationError) Error() string {
    76  	var buf bytes.Buffer
    77  
    78  	for _, err := range e.Errors {
    79  		buf.WriteString(err.Message + "\n")
    80  	}
    81  
    82  	return buf.String()
    83  }
    84  
    85  func computeOperationWaitGlobal(config *Config, op *compute.Operation, project string, activity string) error {
    86  	return computeOperationWaitGlobalTime(config, op, project, activity, 4)
    87  }
    88  
    89  func computeOperationWaitGlobalTime(config *Config, op *compute.Operation, project string, activity string, timeoutMin int) error {
    90  	w := &ComputeOperationWaiter{
    91  		Service: config.clientCompute,
    92  		Op:      op,
    93  		Project: project,
    94  		Type:    ComputeOperationWaitGlobal,
    95  	}
    96  
    97  	state := w.Conf()
    98  	state.Delay = 10 * time.Second
    99  	state.Timeout = time.Duration(timeoutMin) * time.Minute
   100  	state.MinTimeout = 2 * time.Second
   101  	opRaw, err := state.WaitForState()
   102  	if err != nil {
   103  		return fmt.Errorf("Error waiting for %s: %s", activity, err)
   104  	}
   105  
   106  	op = opRaw.(*compute.Operation)
   107  	if op.Error != nil {
   108  		return ComputeOperationError(*op.Error)
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  func computeOperationWaitRegion(config *Config, op *compute.Operation, project string, region, activity string) error {
   115  	w := &ComputeOperationWaiter{
   116  		Service: config.clientCompute,
   117  		Op:      op,
   118  		Project: project,
   119  		Type:    ComputeOperationWaitRegion,
   120  		Region:  region,
   121  	}
   122  
   123  	state := w.Conf()
   124  	state.Delay = 10 * time.Second
   125  	state.Timeout = 4 * time.Minute
   126  	state.MinTimeout = 2 * time.Second
   127  	opRaw, err := state.WaitForState()
   128  	if err != nil {
   129  		return fmt.Errorf("Error waiting for %s: %s", activity, err)
   130  	}
   131  
   132  	op = opRaw.(*compute.Operation)
   133  	if op.Error != nil {
   134  		return ComputeOperationError(*op.Error)
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  func computeOperationWaitZone(config *Config, op *compute.Operation, project string, zone, activity string) error {
   141  	return computeOperationWaitZoneTime(config, op, project, zone, 4, activity)
   142  }
   143  
   144  func computeOperationWaitZoneTime(config *Config, op *compute.Operation, project string, zone string, minutes int, activity string) error {
   145  	w := &ComputeOperationWaiter{
   146  		Service: config.clientCompute,
   147  		Op:      op,
   148  		Project: project,
   149  		Zone:    zone,
   150  		Type:    ComputeOperationWaitZone,
   151  	}
   152  	state := w.Conf()
   153  	state.Delay = 10 * time.Second
   154  	state.Timeout = time.Duration(minutes) * time.Minute
   155  	state.MinTimeout = 2 * time.Second
   156  	opRaw, err := state.WaitForState()
   157  	if err != nil {
   158  		return fmt.Errorf("Error waiting for %s: %s", activity, err)
   159  	}
   160  	op = opRaw.(*compute.Operation)
   161  	if op.Error != nil {
   162  		// Return the error
   163  		return ComputeOperationError(*op.Error)
   164  	}
   165  	return nil
   166  }