diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/helper/resource/wait.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/helper/resource/wait.go | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/wait.go b/vendor/github.com/hashicorp/terraform/helper/resource/wait.go new file mode 100644 index 0000000..ca50e29 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/helper/resource/wait.go | |||
@@ -0,0 +1,84 @@ | |||
1 | package resource | ||
2 | |||
3 | import ( | ||
4 | "sync" | ||
5 | "time" | ||
6 | ) | ||
7 | |||
8 | // Retry is a basic wrapper around StateChangeConf that will just retry | ||
9 | // a function until it no longer returns an error. | ||
10 | func Retry(timeout time.Duration, f RetryFunc) error { | ||
11 | // These are used to pull the error out of the function; need a mutex to | ||
12 | // avoid a data race. | ||
13 | var resultErr error | ||
14 | var resultErrMu sync.Mutex | ||
15 | |||
16 | c := &StateChangeConf{ | ||
17 | Pending: []string{"retryableerror"}, | ||
18 | Target: []string{"success"}, | ||
19 | Timeout: timeout, | ||
20 | MinTimeout: 500 * time.Millisecond, | ||
21 | Refresh: func() (interface{}, string, error) { | ||
22 | rerr := f() | ||
23 | |||
24 | resultErrMu.Lock() | ||
25 | defer resultErrMu.Unlock() | ||
26 | |||
27 | if rerr == nil { | ||
28 | resultErr = nil | ||
29 | return 42, "success", nil | ||
30 | } | ||
31 | |||
32 | resultErr = rerr.Err | ||
33 | |||
34 | if rerr.Retryable { | ||
35 | return 42, "retryableerror", nil | ||
36 | } | ||
37 | return nil, "quit", rerr.Err | ||
38 | }, | ||
39 | } | ||
40 | |||
41 | _, waitErr := c.WaitForState() | ||
42 | |||
43 | // Need to acquire the lock here to be able to avoid race using resultErr as | ||
44 | // the return value | ||
45 | resultErrMu.Lock() | ||
46 | defer resultErrMu.Unlock() | ||
47 | |||
48 | // resultErr may be nil because the wait timed out and resultErr was never | ||
49 | // set; this is still an error | ||
50 | if resultErr == nil { | ||
51 | return waitErr | ||
52 | } | ||
53 | // resultErr takes precedence over waitErr if both are set because it is | ||
54 | // more likely to be useful | ||
55 | return resultErr | ||
56 | } | ||
57 | |||
58 | // RetryFunc is the function retried until it succeeds. | ||
59 | type RetryFunc func() *RetryError | ||
60 | |||
61 | // RetryError is the required return type of RetryFunc. It forces client code | ||
62 | // to choose whether or not a given error is retryable. | ||
63 | type RetryError struct { | ||
64 | Err error | ||
65 | Retryable bool | ||
66 | } | ||
67 | |||
68 | // RetryableError is a helper to create a RetryError that's retryable from a | ||
69 | // given error. | ||
70 | func RetryableError(err error) *RetryError { | ||
71 | if err == nil { | ||
72 | return nil | ||
73 | } | ||
74 | return &RetryError{Err: err, Retryable: true} | ||
75 | } | ||
76 | |||
77 | // NonRetryableError is a helper to create a RetryError that's _not)_ retryable | ||
78 | // from a given error. | ||
79 | func NonRetryableError(err error) *RetryError { | ||
80 | if err == nil { | ||
81 | return nil | ||
82 | } | ||
83 | return &RetryError{Err: err, Retryable: false} | ||
84 | } | ||