github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/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  	w := &ComputeOperationWaiter{
    87  		Service: config.clientCompute,
    88  		Op:      op,
    89  		Project: project,
    90  		Type:    ComputeOperationWaitGlobal,
    91  	}
    92  
    93  	state := w.Conf()
    94  	state.Delay = 10 * time.Second
    95  	state.Timeout = 4 * time.Minute
    96  	state.MinTimeout = 2 * time.Second
    97  	opRaw, err := state.WaitForState()
    98  	if err != nil {
    99  		return fmt.Errorf("Error waiting for %s: %s", activity, err)
   100  	}
   101  
   102  	op = opRaw.(*compute.Operation)
   103  	if op.Error != nil {
   104  		return ComputeOperationError(*op.Error)
   105  	}
   106  
   107  	return nil
   108  }
   109  
   110  func computeOperationWaitRegion(config *Config, op *compute.Operation, project string, region, activity string) error {
   111  	w := &ComputeOperationWaiter{
   112  		Service: config.clientCompute,
   113  		Op:      op,
   114  		Project: project,
   115  		Type:    ComputeOperationWaitRegion,
   116  		Region:  region,
   117  	}
   118  
   119  	state := w.Conf()
   120  	state.Delay = 10 * time.Second
   121  	state.Timeout = 4 * time.Minute
   122  	state.MinTimeout = 2 * time.Second
   123  	opRaw, err := state.WaitForState()
   124  	if err != nil {
   125  		return fmt.Errorf("Error waiting for %s: %s", activity, err)
   126  	}
   127  
   128  	op = opRaw.(*compute.Operation)
   129  	if op.Error != nil {
   130  		return ComputeOperationError(*op.Error)
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  func computeOperationWaitZone(config *Config, op *compute.Operation, project string, zone, activity string) error {
   137  	return computeOperationWaitZoneTime(config, op, project, zone, 4, activity)
   138  }
   139  
   140  func computeOperationWaitZoneTime(config *Config, op *compute.Operation, project string, zone string, minutes int, activity string) error {
   141  	w := &ComputeOperationWaiter{
   142  		Service: config.clientCompute,
   143  		Op:      op,
   144  		Project: project,
   145  		Zone:    zone,
   146  		Type:    ComputeOperationWaitZone,
   147  	}
   148  	state := w.Conf()
   149  	state.Delay = 10 * time.Second
   150  	state.Timeout = time.Duration(minutes) * time.Minute
   151  	state.MinTimeout = 2 * time.Second
   152  	opRaw, err := state.WaitForState()
   153  	if err != nil {
   154  		return fmt.Errorf("Error waiting for %s: %s", activity, err)
   155  	}
   156  	op = opRaw.(*compute.Operation)
   157  	if op.Error != nil {
   158  		// Return the error
   159  		return ComputeOperationError(*op.Error)
   160  	}
   161  	return nil
   162  }