Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add retries/backoff when (only) reading IAM policies #3455

Merged
merged 1 commit into from
Apr 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion google/iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"google.golang.org/api/cloudresourcemanager/v1"
)

const maxBackoffSeconds = 30

// The ResourceIamUpdater interface is implemented for each GCP resource supporting IAM policy.
//
// Implementations should keep track of the resource identifier.
Expand Down Expand Up @@ -44,6 +46,26 @@ type iamPolicyModifyFunc func(p *cloudresourcemanager.Policy) error

type resourceIdParserFunc func(d *schema.ResourceData, config *Config) error

// Wrapper around updater.GetResourceIamPolicy() to handle retry/backoff
// for just reading policies from IAM
func iamPolicyReadWithRetry(updater ResourceIamUpdater) (*cloudresourcemanager.Policy, error) {
mutexKey := updater.GetMutexKey()
mutexKV.Lock(mutexKey)
defer mutexKV.Unlock(mutexKey)

log.Printf("[DEBUG] Retrieving policy for %s\n", updater.DescribeResource())
var policy *cloudresourcemanager.Policy
err := retryTime(func() (perr error) {
policy, perr = updater.GetResourceIamPolicy()
return perr
}, 10)
if err != nil {
return nil, err
}
log.Printf("[DEBUG] Retrieved policy for %s: %+v\n", updater.DescribeResource(), policy)
return policy, nil
}

func iamPolicyReadModifyWrite(updater ResourceIamUpdater, modify iamPolicyModifyFunc) error {
mutexKey := updater.GetMutexKey()
mutexKV.Lock(mutexKey)
Expand All @@ -54,6 +76,7 @@ func iamPolicyReadModifyWrite(updater ResourceIamUpdater, modify iamPolicyModify
log.Printf("[DEBUG]: Retrieving policy for %s\n", updater.DescribeResource())
p, err := updater.GetResourceIamPolicy()
if isGoogleApiErrorWithCode(err, 429) {
log.Printf("[DEBUG] 429 while attempting to read policy for %s, waiting %v before attempting again", updater.DescribeResource(), backoff)
time.Sleep(backoff)
continue
} else if err != nil {
Expand All @@ -71,7 +94,7 @@ func iamPolicyReadModifyWrite(updater ResourceIamUpdater, modify iamPolicyModify
if err == nil {
fetchBackoff := 1 * time.Second
for successfulFetches := 0; successfulFetches < 3; {
if fetchBackoff > 30*time.Second {
if fetchBackoff > maxBackoffSeconds*time.Second {
return fmt.Errorf("Error applying IAM policy to %s: Waited too long for propagation.\n", updater.DescribeResource())
}
time.Sleep(fetchBackoff)
Expand Down
2 changes: 1 addition & 1 deletion google/resource_iam_audit_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func resourceIamAuditConfigRead(newUpdaterFunc newResourceIamUpdaterFunc) schema
}

eAuditConfig := getResourceIamAuditConfig(d)
p, err := updater.GetResourceIamPolicy()
p, err := iamPolicyReadWithRetry(updater)
if err != nil {
if isGoogleApiErrorWithCode(err, 404) {
log.Printf("[DEBUG]: AuditConfig for service %q not found for non-existent resource %s, removing from state file.", eAuditConfig.Service, updater.DescribeResource())
Expand Down
2 changes: 1 addition & 1 deletion google/resource_iam_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func resourceIamBindingRead(newUpdaterFunc newResourceIamUpdaterFunc) schema.Rea
}

eBinding := getResourceIamBinding(d)
p, err := updater.GetResourceIamPolicy()
p, err := iamPolicyReadWithRetry(updater)
if err != nil {
if isGoogleApiErrorWithCode(err, 404) {
log.Printf("[DEBUG]: Binding for role %q not found for non-existent resource %s, removing from state file.", updater.DescribeResource(), eBinding.Role)
Expand Down
2 changes: 1 addition & 1 deletion google/resource_iam_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func resourceIamMemberRead(newUpdaterFunc newResourceIamUpdaterFunc) schema.Read
}

eMember := getResourceIamMember(d)
p, err := updater.GetResourceIamPolicy()
p, err := iamPolicyReadWithRetry(updater)
if err != nil {
if isGoogleApiErrorWithCode(err, 404) {
log.Printf("[DEBUG]: Binding of member %q with role %q does not exist for non-existent resource %s, removing from state.", eMember.Members[0], eMember.Role, updater.DescribeResource())
Expand Down
2 changes: 1 addition & 1 deletion google/resource_iam_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func ResourceIamPolicyRead(newUpdaterFunc newResourceIamUpdaterFunc) schema.Read
return err
}

policy, err := updater.GetResourceIamPolicy()
policy, err := iamPolicyReadWithRetry(updater)
if err != nil {
if isGoogleApiErrorWithCode(err, 404) {
log.Printf("[DEBUG]: Policy does not exist for non-existent resource %q", updater.GetResourceId())
Expand Down