@@ -2,10 +2,12 @@ package google
2
2
3
3
import (
4
4
"fmt"
5
- "github.com/hashicorp/terraform/helper/schema"
6
- "google.golang.org/api/cloudresourcemanager/v1"
7
5
"log"
8
6
"time"
7
+
8
+ "github.com/hashicorp/terraform/helper/schema"
9
+ "google.golang.org/api/cloudresourcemanager/v1"
10
+ "google.golang.org/api/googleapi"
9
11
)
10
12
11
13
// The ResourceIamUpdater interface is implemented for each GCP resource supporting IAM policy.
@@ -47,11 +49,14 @@ func iamPolicyReadModifyWrite(updater ResourceIamUpdater, modify iamPolicyModify
47
49
mutexKV .Lock (mutexKey )
48
50
defer mutexKV .Unlock (mutexKey )
49
51
52
+ backoff := time .Second
50
53
for {
51
- backoff := time .Second
52
54
log .Printf ("[DEBUG]: Retrieving policy for %s\n " , updater .DescribeResource ())
53
55
p , err := updater .GetResourceIamPolicy ()
54
- if err != nil {
56
+ if e , ok := err .(* googleapi.Error ); ok && e .Code == 429 {
57
+ time .Sleep (backoff )
58
+ continue
59
+ } else if err != nil {
55
60
return err
56
61
}
57
62
log .Printf ("[DEBUG]: Retrieved policy for %s: %+v\n " , updater .DescribeResource (), p )
@@ -64,6 +69,36 @@ func iamPolicyReadModifyWrite(updater ResourceIamUpdater, modify iamPolicyModify
64
69
log .Printf ("[DEBUG]: Setting policy for %s to %+v\n " , updater .DescribeResource (), p )
65
70
err = updater .SetResourceIamPolicy (p )
66
71
if err == nil {
72
+ fetchBackoff := 1 * time .Second
73
+ for successfulFetches := 0 ; successfulFetches < 3 ; {
74
+ time .Sleep (fetchBackoff )
75
+ new_p , err := updater .GetResourceIamPolicy ()
76
+ if err != nil {
77
+ // Quota for Read is pretty limited, so watch out for running out of quota.
78
+ if e , ok := err .(* googleapi.Error ); ok && e .Code == 429 {
79
+ fetchBackoff = fetchBackoff * 2
80
+ } else {
81
+ return err
82
+ }
83
+ }
84
+ modified_p := new_p
85
+ // This relies on the fact that `modify` is idempotent: since other changes might have
86
+ // happened between the call to set the policy and now, we just need to make sure that
87
+ // our change has been made. 'modify(p) == p' is our check for whether this has been
88
+ // correctly applied.
89
+ err = modify (modified_p )
90
+ if err != nil {
91
+ return err
92
+ }
93
+ if modified_p == new_p {
94
+ successfulFetches += 1
95
+ } else {
96
+ fetchBackoff = fetchBackoff * 2
97
+ if fetchBackoff > 30 * time .Second {
98
+ return fmt .Errorf ("Error applying IAM policy to %s: Waited too long for propagation.\n " , updater .DescribeResource ())
99
+ }
100
+ }
101
+ }
67
102
break
68
103
}
69
104
if isConflictError (err ) {
0 commit comments