terraform/helper/resource/wait.go

60 lines
1.3 KiB
Go
Raw Normal View History

2014-07-01 03:03:27 +02:00
package resource
import (
"sync"
2014-07-01 03:03:27 +02:00
"time"
)
2014-10-08 06:44:51 +02:00
// RetryFunc is the function retried until it succeeds.
type RetryFunc func() error
// Retry is a basic wrapper around StateChangeConf that will just retry
// a function until it no longer returns an error.
func Retry(timeout time.Duration, f RetryFunc) error {
// These are used to pull the error out of the function; need a mutex to
// avoid a data race.
var resultErr error
var resultErrMu sync.Mutex
2014-10-08 06:44:51 +02:00
c := &StateChangeConf{
Pending: []string{"error"},
Target: []string{"success"},
2014-10-08 06:44:51 +02:00
Timeout: timeout,
MinTimeout: 500 * time.Millisecond,
Refresh: func() (interface{}, string, error) {
helper/resource: Fix data race in resource.Retry The implementation was attempting to capture the error using a scoped variable reference, but the error value is already exposed via the return value of `WaitForState()`. Using that instead fixes the data race. Fixes the following data race: ``` ================== WARNING: DATA RACE Read by goroutine 74: github.com/hashicorp/terraform/helper/resource.Retry() /Users/phinze/go/src/github.com/hashicorp/terraform/helper/resource/wait.go:35 +0x284 github.com/hashicorp/terraform/helper/resource.TestRetry_timeout() /Users/phinze/go/src/github.com/hashicorp/terraform/helper/resource/wait_test.go:35 +0x60 testing.tRunner() /private/var/folders/vd/7l9ys5k57l91x63sh28wl_kc0000gn/T/workdir/go/src/testing/testing.go:456 +0xdc Previous write by goroutine 90: github.com/hashicorp/terraform/helper/resource.Retry.func1() /Users/phinze/go/src/github.com/hashicorp/terraform/helper/resource/wait.go:20 +0x87 github.com/hashicorp/terraform/helper/resource.(*StateChangeConf).WaitForState.func1() /Users/phinze/go/src/github.com/hashicorp/terraform/helper/resource/state.go:83 +0x284 Goroutine 74 (running) created at: testing.RunTests() /private/var/folders/vd/7l9ys5k57l91x63sh28wl_kc0000gn/T/workdir/go/src/testing/testing.go:561 +0xaa3 testing.(*M).Run() /private/var/folders/vd/7l9ys5k57l91x63sh28wl_kc0000gn/T/workdir/go/src/testing/testing.go:494 +0xe4 main.main() github.com/hashicorp/terraform/helper/resource/_test/_testmain.go:84 +0x20f Goroutine 90 (running) created at: github.com/hashicorp/terraform/helper/resource.(*StateChangeConf).WaitForState() /Users/phinze/go/src/github.com/hashicorp/terraform/helper/resource/state.go:127 +0x283 github.com/hashicorp/terraform/helper/resource.Retry() /Users/phinze/go/src/github.com/hashicorp/terraform/helper/resource/wait.go:34 +0x276 github.com/hashicorp/terraform/helper/resource.TestRetry_timeout() /Users/phinze/go/src/github.com/hashicorp/terraform/helper/resource/wait_test.go:35 +0x60 testing.tRunner() /private/var/folders/vd/7l9ys5k57l91x63sh28wl_kc0000gn/T/workdir/go/src/testing/testing.go:456 +0xdc ================== ```
2016-01-16 19:09:01 +01:00
err := f()
if err == nil {
return 42, "success", nil
}
resultErrMu.Lock()
defer resultErrMu.Unlock()
resultErr = err
if rerr, ok := err.(RetryError); ok {
resultErr = rerr.Err
return nil, "quit", rerr.Err
}
return 42, "error", nil
2014-10-08 06:44:51 +02:00
},
2014-07-01 03:03:27 +02:00
}
2014-10-08 06:44:51 +02:00
c.WaitForState()
// Need to acquire the lock here to be able to avoid race using resultErr as
// the return value
resultErrMu.Lock()
defer resultErrMu.Unlock()
return resultErr
2014-07-01 03:03:27 +02:00
}
// RetryError, if returned, will quit the retry immediately with the
// Err.
type RetryError struct {
Err error
}
func (e RetryError) Error() string {
return e.Err.Error()
}