Skip to content

Commit

Permalink
Refactor Compute Operations to work identically & introduce a scope-l…
Browse files Browse the repository at this point in the history
…ess API (hashicorp#191)

* Refactor compute_operation.go to duplicate less code.

* Determine what scope type an Operation is from it's Operation object.

* Inlined operation type switch statement into if/else methods.
  • Loading branch information
rileykarson authored Jul 25, 2017
1 parent 1f3ab55 commit 91d033c
Showing 1 changed file with 44 additions and 70 deletions.
114 changes: 44 additions & 70 deletions google/compute_operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,41 @@ import (
"bytes"
"fmt"
"log"
"strings"
"time"

"github.com/hashicorp/terraform/helper/resource"
"google.golang.org/api/compute/v1"
)

// OperationWaitType is an enum specifying what type of operation
// we're waiting on.
type ComputeOperationWaitType byte

const (
ComputeOperationWaitInvalid ComputeOperationWaitType = iota
ComputeOperationWaitGlobal
ComputeOperationWaitRegion
ComputeOperationWaitZone
"google.golang.org/api/compute/v1"
)

type ComputeOperationWaiter struct {
Service *compute.Service
Op *compute.Operation
Project string
Region string
Type ComputeOperationWaitType
Zone string
}

func (w *ComputeOperationWaiter) RefreshFunc() resource.StateRefreshFunc {
return func() (interface{}, string, error) {
var op *compute.Operation
var err error

switch w.Type {
case ComputeOperationWaitGlobal:
op, err = w.Service.GlobalOperations.Get(
w.Project, w.Op.Name).Do()
case ComputeOperationWaitRegion:
op, err = w.Service.RegionOperations.Get(
w.Project, w.Region, w.Op.Name).Do()
case ComputeOperationWaitZone:
op, err = w.Service.ZoneOperations.Get(
w.Project, w.Zone, w.Op.Name).Do()
default:
return nil, "bad-type", fmt.Errorf(
"Invalid wait type: %#v", w.Type)
if w.Op.Zone != "" {
zoneURLParts := strings.Split(w.Op.Zone, "/")
zone := zoneURLParts[len(zoneURLParts)-1]
op, err = w.Service.ZoneOperations.Get(w.Project, zone, w.Op.Name).Do()
} else if w.Op.Region != "" {
regionURLParts := strings.Split(w.Op.Region, "/")
region := regionURLParts[len(regionURLParts)-1]
op, err = w.Service.RegionOperations.Get(w.Project, region, w.Op.Name).Do()
} else {
op, err = w.Service.GlobalOperations.Get(w.Project, w.Op.Name).Do()
}

if err != nil {
return nil, "", err
}

log.Printf("[DEBUG] Got %q when asking for operation %q", op.Status, w.Op.Name)

return op, op.Status, nil
}
}
Expand All @@ -74,93 +57,84 @@ type ComputeOperationError compute.OperationError

func (e ComputeOperationError) Error() string {
var buf bytes.Buffer

for _, err := range e.Errors {
buf.WriteString(err.Message + "\n")
}

return buf.String()
}

func computeOperationWaitGlobal(config *Config, op *compute.Operation, project string, activity string) error {
return computeOperationWaitGlobalTime(config, op, project, activity, 4)
func computeOperationWait(config *Config, op *compute.Operation, project, activity string) error {
return computeOperationWaitTime(config, op, project, activity, 4)
}

func computeOperationWaitGlobalTime(config *Config, op *compute.Operation, project string, activity string, timeoutMin int) error {
func computeOperationWaitTime(config *Config, op *compute.Operation, project, activity string, timeoutMin int) error {
w := &ComputeOperationWaiter{
Service: config.clientCompute,
Op: op,
Project: project,
Type: ComputeOperationWaitGlobal,
}

state := w.Conf()
state.Delay = 10 * time.Second
state.Timeout = time.Duration(timeoutMin) * time.Minute
state.MinTimeout = 2 * time.Second
opRaw, err := state.WaitForState()
if err != nil {
return fmt.Errorf("Error waiting for %s: %s", activity, err)
}

op = opRaw.(*compute.Operation)
if op.Error != nil {
return ComputeOperationError(*op.Error)
}
return waitComputeOperationWaiter(w, timeoutMin, activity)
}

return nil
func computeOperationWaitGlobal(config *Config, op *compute.Operation, project, activity string) error {
return computeOperationWaitGlobalTime(config, op, project, activity, 4)
}

func computeOperationWaitRegion(config *Config, op *compute.Operation, project string, region, activity string) error {
func computeOperationWaitGlobalTime(config *Config, op *compute.Operation, project, activity string, timeoutMin int) error {
w := &ComputeOperationWaiter{
Service: config.clientCompute,
Op: op,
Project: project,
Type: ComputeOperationWaitRegion,
Region: region,
}

state := w.Conf()
state.Delay = 10 * time.Second
state.Timeout = 4 * time.Minute
state.MinTimeout = 2 * time.Second
opRaw, err := state.WaitForState()
if err != nil {
return fmt.Errorf("Error waiting for %s: %s", activity, err)
}
return waitComputeOperationWaiter(w, timeoutMin, activity)
}

op = opRaw.(*compute.Operation)
if op.Error != nil {
return ComputeOperationError(*op.Error)
func computeOperationWaitRegion(config *Config, op *compute.Operation, project string, region, activity string) error {
return computeOperationWaitRegionTime(config, op, project, region, 4, activity)
}

func computeOperationWaitRegionTime(config *Config, op *compute.Operation, project, region string, timeoutMin int, activity string) error {
w := &ComputeOperationWaiter{
Service: config.clientCompute,
Op: op,
Project: project,
}

return nil
return waitComputeOperationWaiter(w, timeoutMin, activity)
}

func computeOperationWaitZone(config *Config, op *compute.Operation, project string, zone, activity string) error {
func computeOperationWaitZone(config *Config, op *compute.Operation, project, zone, activity string) error {
return computeOperationWaitZoneTime(config, op, project, zone, 4, activity)
}

func computeOperationWaitZoneTime(config *Config, op *compute.Operation, project string, zone string, minutes int, activity string) error {
func computeOperationWaitZoneTime(config *Config, op *compute.Operation, project, zone string, timeoutMin int, activity string) error {
w := &ComputeOperationWaiter{
Service: config.clientCompute,
Op: op,
Project: project,
Zone: zone,
Type: ComputeOperationWaitZone,
}

return waitComputeOperationWaiter(w, timeoutMin, activity)
}

// TODO: Inline this to computeOperationWaitTime when the old wait methods are eliminated.
func waitComputeOperationWaiter(w *ComputeOperationWaiter, timeoutMin int, activity string) error {
state := w.Conf()
state.Delay = 10 * time.Second
state.Timeout = time.Duration(minutes) * time.Minute
state.Timeout = time.Duration(timeoutMin) * time.Minute
state.MinTimeout = 2 * time.Second
opRaw, err := state.WaitForState()
if err != nil {
return fmt.Errorf("Error waiting for %s: %s", activity, err)
}
op = opRaw.(*compute.Operation)

op := opRaw.(*compute.Operation)
if op.Error != nil {
// Return the error
return ComputeOperationError(*op.Error)
}

return nil
}

0 comments on commit 91d033c

Please sign in to comment.