3
3
package acctest
4
4
5
5
import (
6
- "fmt"
7
- "log"
8
6
"strconv"
9
7
"strings"
10
8
"testing"
11
9
"time"
12
10
13
11
"github.com/hashicorp/terraform-provider-google/google/envvar"
14
12
"github.com/hashicorp/terraform-provider-google/google/tpgiamresource"
13
+ "github.com/hashicorp/terraform-provider-google/google/tpgresource"
14
+ transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
15
15
cloudresourcemanager "google.golang.org/api/cloudresourcemanager/v1"
16
16
)
17
17
@@ -36,12 +36,6 @@ func BootstrapIamMembers(t *testing.T, members []IamMember) {
36
36
t .Fatalf ("Error getting project with id %q: %s" , project .ProjectId , err )
37
37
}
38
38
39
- getPolicyRequest := & cloudresourcemanager.GetIamPolicyRequest {}
40
- policy , err := client .Projects .GetIamPolicy (project .ProjectId , getPolicyRequest ).Do ()
41
- if err != nil {
42
- t .Fatalf ("Error getting project iam policy: %v" , err )
43
- }
44
-
45
39
// Create the bindings we need to add to the policy.
46
40
var newBindings []* cloudresourcemanager.Binding
47
41
for _ , member := range members {
@@ -51,26 +45,43 @@ func BootstrapIamMembers(t *testing.T, members []IamMember) {
51
45
})
52
46
}
53
47
54
- mergedBindings := tpgiamresource .MergeBindings (append (policy .Bindings , newBindings ... ))
48
+ // Retry bootstrapping with exponential backoff for concurrent writes
49
+ backoff := time .Second
50
+ for {
51
+ getPolicyRequest := & cloudresourcemanager.GetIamPolicyRequest {}
52
+ policy , err := client .Projects .GetIamPolicy (project .ProjectId , getPolicyRequest ).Do ()
53
+ if transport_tpg .IsGoogleApiErrorWithCode (err , 429 ) {
54
+ t .Logf ("[DEBUG] 429 while attempting to read policy for project %s, waiting %v before attempting again" , project .ProjectId , backoff )
55
+ time .Sleep (backoff )
56
+ continue
57
+ } else if err != nil {
58
+ t .Fatalf ("Error getting iam policy for project %s: %v\n " , project .ProjectId , err )
59
+ }
60
+
61
+ mergedBindings := tpgiamresource .MergeBindings (append (policy .Bindings , newBindings ... ))
55
62
56
- if ! tpgiamresource .CompareBindings (policy .Bindings , mergedBindings ) {
57
- addedBindings := tpgiamresource .MissingBindings (policy .Bindings , mergedBindings )
58
- for _ , missingBinding := range addedBindings {
59
- log .Printf ("[DEBUG] Adding binding: %+v" , missingBinding )
63
+ if tpgiamresource .CompareBindings (policy .Bindings , mergedBindings ) {
64
+ t .Logf ("[DEBUG] All bindings already present for project %s" , project .ProjectId )
65
+ break
60
66
}
61
67
// The policy must change.
62
68
policy .Bindings = mergedBindings
63
69
setPolicyRequest := & cloudresourcemanager.SetIamPolicyRequest {Policy : policy }
64
70
policy , err = client .Projects .SetIamPolicy (project .ProjectId , setPolicyRequest ).Do ()
65
- if err != nil {
66
- t .Fatalf ("Error setting project iam policy: %v" , err )
71
+ if err == nil {
72
+ t .Logf ("[DEBUG] Waiting for IAM bootstrapping to propagate for project %s." , project .ProjectId )
73
+ time .Sleep (3 * time .Minute )
74
+ break
67
75
}
68
- msg := "Added the following bindings to the test project's IAM policy:\n "
69
- for _ , binding := range addedBindings {
70
- msg += fmt .Sprintf ("Members: %q, Role: %q\n " , binding .Members , binding .Role )
76
+ if tpgresource .IsConflictError (err ) {
77
+ t .Logf ("[DEBUG]: Concurrent policy changes, restarting read-modify-write after %s" , backoff )
78
+ time .Sleep (backoff )
79
+ backoff = backoff * 2
80
+ if backoff > 30 * time .Second {
81
+ t .Fatalf ("Error applying IAM policy to %s: Too many conflicts. Latest error: %s" , project .ProjectId , err )
82
+ }
83
+ continue
71
84
}
72
- msg += "Waiting for IAM to propagate."
73
- t .Log (msg )
74
- time .Sleep (3 * time .Minute )
85
+ t .Fatalf ("Error setting project iam policy: %v" , err )
75
86
}
76
87
}
0 commit comments