From 1befeb8b1ff8b16b0c24715a4d8aac372ec04d6f Mon Sep 17 00:00:00 2001
From: The Magician <magic-modules@google.com>
Date: Thu, 12 Sep 2019 10:13:22 -0700
Subject: [PATCH] retry on resourceNotReady (#1130)

Signed-off-by: Modular Magician <magic-modules@google.com>
---
 google-beta/common_operation.go       | 11 +++++++++++
 google-beta/compute_operation.go      | 11 +++++++++++
 google-beta/container_operation.go    |  4 ++++
 google-beta/dataproc_job_operation.go |  4 ++++
 google-beta/sqladmin_operation.go     |  4 ++++
 5 files changed, 34 insertions(+)

diff --git a/google-beta/common_operation.go b/google-beta/common_operation.go
index 1c2a7577dfa..c751ece8738 100644
--- a/google-beta/common_operation.go
+++ b/google-beta/common_operation.go
@@ -18,6 +18,9 @@ type Waiter interface {
 	// if the operation has no current error.
 	Error() error
 
+	// IsRetryable returns whether a given error should be retried.
+	IsRetryable(error) bool
+
 	// SetOp sets the operation we're waiting on in a Waiter struct so that it
 	// can be used in other methods.
 	SetOp(interface{}) error
@@ -59,6 +62,10 @@ func (w *CommonOperationWaiter) Error() error {
 	return nil
 }
 
+func (w *CommonOperationWaiter) IsRetryable(error) bool {
+	return false
+}
+
 func (w *CommonOperationWaiter) SetOp(op interface{}) error {
 	if err := Convert(op, &w.Op); err != nil {
 		return err
@@ -110,6 +117,10 @@ func CommonRefreshFunc(w Waiter) resource.StateRefreshFunc {
 		}
 
 		if err = w.Error(); err != nil {
+			if w.IsRetryable(err) {
+				log.Printf("[DEBUG] Retrying operation GET based on retryable err: %s", err)
+				return op, w.State(), nil
+			}
 			return nil, "", err
 		}
 
diff --git a/google-beta/compute_operation.go b/google-beta/compute_operation.go
index 992d5961543..25e26641648 100644
--- a/google-beta/compute_operation.go
+++ b/google-beta/compute_operation.go
@@ -29,6 +29,17 @@ func (w *ComputeOperationWaiter) Error() error {
 	return nil
 }
 
+func (w *ComputeOperationWaiter) IsRetryable(err error) bool {
+	if oe, ok := err.(ComputeOperationError); ok {
+		for _, e := range oe.Errors {
+			if e.Code == "RESOURCE_NOT_READY" {
+				return true
+			}
+		}
+	}
+	return false
+}
+
 func (w *ComputeOperationWaiter) SetOp(op interface{}) error {
 	var ok bool
 	w.Op, ok = op.(*compute.Operation)
diff --git a/google-beta/container_operation.go b/google-beta/container_operation.go
index 9c376ea15f8..99984f0f536 100644
--- a/google-beta/container_operation.go
+++ b/google-beta/container_operation.go
@@ -41,6 +41,10 @@ func (w *ContainerOperationWaiter) Error() error {
 	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)
diff --git a/google-beta/dataproc_job_operation.go b/google-beta/dataproc_job_operation.go
index ce3cab01ee7..1efccf60eda 100644
--- a/google-beta/dataproc_job_operation.go
+++ b/google-beta/dataproc_job_operation.go
@@ -28,6 +28,10 @@ func (w *DataprocJobOperationWaiter) Error() error {
 	return nil
 }
 
+func (w *DataprocJobOperationWaiter) IsRetryable(error) bool {
+	return false
+}
+
 func (w *DataprocJobOperationWaiter) SetOp(job interface{}) error {
 	// The "operation" is just the job. Instead of holding onto the whole job
 	// object, we only care about the state, which gets set in QueryOp, so this
diff --git a/google-beta/sqladmin_operation.go b/google-beta/sqladmin_operation.go
index 5f4094c699d..8ca847eeb8f 100644
--- a/google-beta/sqladmin_operation.go
+++ b/google-beta/sqladmin_operation.go
@@ -33,6 +33,10 @@ func (w *SqlAdminOperationWaiter) Error() error {
 	return nil
 }
 
+func (w *SqlAdminOperationWaiter) IsRetryable(error) bool {
+	return false
+}
+
 func (w *SqlAdminOperationWaiter) SetOp(op interface{}) error {
 	if op == nil {
 		// Starting as a log statement, this may be a useful error in the future