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 }