forked from hashicorp/terraform-provider-google-beta
/
sqladmin_operation.go
153 lines (123 loc) · 3.52 KB
/
sqladmin_operation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package sql
import (
"bytes"
"fmt"
"log"
"time"
"github.com/lorioux/google-beta/google-beta/tpgresource"
transport_tpg "github.com/lorioux/google-beta/google-beta/transport"
sqladmin "google.golang.org/api/sqladmin/v1beta4"
)
type SqlAdminOperationWaiter struct {
Service *sqladmin.Service
Op *sqladmin.Operation
Project string
}
func (w *SqlAdminOperationWaiter) State() string {
if w == nil {
return "Operation Waiter is nil!"
}
if w.Op == nil {
return "Operation is nil!"
}
return w.Op.Status
}
func (w *SqlAdminOperationWaiter) Error() error {
if w != nil && w.Op != nil && w.Op.Error != nil {
return SqlAdminOperationError(*w.Op.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
log.Printf("[DEBUG] attempted to set nil op")
}
sqlOp, ok := op.(*sqladmin.Operation)
w.Op = sqlOp
if !ok {
return fmt.Errorf("Unable to set operation. Bad type!")
}
return nil
}
func (w *SqlAdminOperationWaiter) QueryOp() (interface{}, error) {
if w == nil {
return nil, fmt.Errorf("Cannot query operation, waiter is unset or nil.")
}
if w.Op == nil {
return nil, fmt.Errorf("Cannot query operation, it's unset or nil.")
}
if w.Service == nil {
return nil, fmt.Errorf("Cannot query operation, service is nil.")
}
var op interface{}
var err error
err = transport_tpg.Retry(transport_tpg.RetryOptions{
RetryFunc: func() error {
op, err = w.Service.Operations.Get(w.Project, w.Op.Name).Do()
return err
},
Timeout: transport_tpg.DefaultRequestTimeout,
})
return op, err
}
func (w *SqlAdminOperationWaiter) OpName() string {
if w == nil {
return "<nil waiter>"
}
if w.Op == nil {
return "<nil op>"
}
return w.Op.Name
}
func (w *SqlAdminOperationWaiter) PendingStates() []string {
return []string{"PENDING", "RUNNING"}
}
func (w *SqlAdminOperationWaiter) TargetStates() []string {
return []string{"DONE"}
}
func SqlAdminOperationWaitTime(config *transport_tpg.Config, res interface{}, project, activity, userAgent string, timeout time.Duration) error {
op := &sqladmin.Operation{}
err := tpgresource.Convert(res, op)
if err != nil {
return err
}
w := &SqlAdminOperationWaiter{
Service: config.NewSqlAdminClient(userAgent),
Op: op,
Project: project,
}
if err := w.SetOp(op); err != nil {
return err
}
return tpgresource.OperationWait(w, activity, timeout, config.PollInterval)
}
// SqlAdminOperationError wraps sqladmin.OperationError and implements the
// error interface so it can be returned.
type SqlAdminOperationError sqladmin.OperationErrors
func (e SqlAdminOperationError) Error() string {
var buf bytes.Buffer
for _, err := range e.Errors {
buf.WriteString(err.Message + "\n")
}
return buf.String()
}
// Retry if Cloud SQL operation returns a 429 with a specific message for
// concurrent operations.
func IsSqlInternalError(err error) (bool, string) {
if gerr, ok := err.(*SqlAdminOperationError); ok {
// SqlAdminOperationError is a non-interface type so we need to cast it through
// a layer of interface{}. :)
var ierr interface{}
ierr = gerr
if serr, ok := ierr.(*sqladmin.OperationErrors); ok && serr.Errors[0].Code == "INTERNAL_ERROR" {
return true, "Received an internal error, which is sometimes retryable for some SQL resources. Optimistically retrying."
}
}
return false, ""
}