blob: 426c07897ac3f1147d322a99cbcf7da8eb6f2b2b [file] [log] [blame] [edit]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package container
import (
"context"
"errors"
"fmt"
"log"
"time"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
container "google.golang.org/api/container/v1beta1"
)
type ContainerOperationWaiter struct {
Service *container.Service
Context context.Context
Op *container.Operation
Project string
Location string
UserProjectOverride bool
}
func (w *ContainerOperationWaiter) State() string {
if w == nil || w.Op == nil {
return "<nil>"
}
return w.Op.Status
}
func (w *ContainerOperationWaiter) Error() error {
if w == nil || w.Op == nil {
return nil
}
// Error gets called during operation polling to see if there is an error.
// Since container's operation doesn't have an "error" field, we must wait
// until it's done and check the status message
for _, pending := range w.PendingStates() {
if w.Op.Status == pending {
return nil
}
}
if w.Op.StatusMessage != "" {
return fmt.Errorf(w.Op.StatusMessage)
}
return nil
}
func (w *ContainerOperationWaiter) IsRetryable(error) bool {
return false
}
func (w *ContainerOperationWaiter) SetOp(op interface{}) error {
var ok bool
w.Op, ok = op.(*container.Operation)
if !ok {
return fmt.Errorf("Unable to set operation. Bad type!")
}
return nil
}
func (w *ContainerOperationWaiter) QueryOp() (interface{}, error) {
if w == nil || w.Op == nil {
return nil, fmt.Errorf("Cannot query operation, it's unset or nil.")
}
name := fmt.Sprintf("projects/%s/locations/%s/operations/%s",
w.Project, w.Location, w.Op.Name)
var op *container.Operation
select {
case <-w.Context.Done():
log.Println("[WARN] request has been cancelled early")
return op, errors.New("unable to finish polling, context has been cancelled")
default:
// default must be here to keep the previous case from blocking
}
err := transport_tpg.Retry(transport_tpg.RetryOptions{
RetryFunc: func() (opErr error) {
opGetCall := w.Service.Projects.Locations.Operations.Get(name)
if w.UserProjectOverride {
opGetCall.Header().Add("X-Goog-User-Project", w.Project)
}
op, opErr = opGetCall.Do()
return opErr
},
Timeout: transport_tpg.DefaultRequestTimeout,
})
return op, err
}
func (w *ContainerOperationWaiter) OpName() string {
if w == nil || w.Op == nil {
return "<nil>"
}
return w.Op.Name
}
func (w *ContainerOperationWaiter) PendingStates() []string {
return []string{"PENDING", "RUNNING"}
}
func (w *ContainerOperationWaiter) TargetStates() []string {
return []string{"DONE"}
}
func ContainerOperationWait(config *transport_tpg.Config, op *container.Operation, project, location, activity, userAgent string, timeout time.Duration) error {
w := &ContainerOperationWaiter{
Service: config.NewContainerClient(userAgent),
Context: config.Context,
Op: op,
Project: project,
Location: location,
UserProjectOverride: config.UserProjectOverride,
}
if err := w.SetOp(op); err != nil {
return err
}
return tpgresource.OperationWait(w, activity, timeout, config.PollInterval)
}