Skip to content

Commit 1f6c41c

Browse files
Implemented exponential backoff for IAM bootstrapping (#13001) (#21315)
[upstream:0a15a64f4dea8f148ce70cdc25b64ff97a1927b1] Signed-off-by: Modular Magician <[email protected]>
1 parent 8970bb1 commit 1f6c41c

File tree

2 files changed

+35
-21
lines changed

2 files changed

+35
-21
lines changed

.changelog/13001.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:none
2+
3+
```

google/acctest/bootstrap_iam_test_utils.go

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
package acctest
44

55
import (
6-
"fmt"
7-
"log"
86
"strconv"
97
"strings"
108
"testing"
119
"time"
1210

1311
"github.com/hashicorp/terraform-provider-google/google/envvar"
1412
"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"
1515
cloudresourcemanager "google.golang.org/api/cloudresourcemanager/v1"
1616
)
1717

@@ -36,12 +36,6 @@ func BootstrapIamMembers(t *testing.T, members []IamMember) {
3636
t.Fatalf("Error getting project with id %q: %s", project.ProjectId, err)
3737
}
3838

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-
4539
// Create the bindings we need to add to the policy.
4640
var newBindings []*cloudresourcemanager.Binding
4741
for _, member := range members {
@@ -51,26 +45,43 @@ func BootstrapIamMembers(t *testing.T, members []IamMember) {
5145
})
5246
}
5347

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...))
5562

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
6066
}
6167
// The policy must change.
6268
policy.Bindings = mergedBindings
6369
setPolicyRequest := &cloudresourcemanager.SetIamPolicyRequest{Policy: policy}
6470
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
6775
}
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
7184
}
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)
7586
}
7687
}

0 commit comments

Comments
 (0)