mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-04 17:51:11 +00:00
Create an iam policy read/modify/write helper.
We were repeating that logic a lot, so this helper just reads a policy, calls the passed modify function on the policy, then writes the policy back and takes care of the optimistic concurrency logic for the caller. So now all the caller has to do is the unique part, which is the modify function.
This commit is contained in:
parent
9c1c0bbc52
commit
729e9fc501
@ -3,7 +3,6 @@ package google
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
"google.golang.org/api/cloudresourcemanager/v1"
|
"google.golang.org/api/cloudresourcemanager/v1"
|
||||||
@ -55,35 +54,14 @@ func resourceGoogleProjectIamBindingCreate(d *schema.ResourceData, meta interfac
|
|||||||
mutexKV.Lock(projectIamBindingMutexKey(pid, p.Role))
|
mutexKV.Lock(projectIamBindingMutexKey(pid, p.Role))
|
||||||
defer mutexKV.Unlock(projectIamBindingMutexKey(pid, p.Role))
|
defer mutexKV.Unlock(projectIamBindingMutexKey(pid, p.Role))
|
||||||
|
|
||||||
for {
|
err = projectIamPolicyReadModifyWrite(d, config, pid, func(ep *cloudresourcemanager.Policy) error {
|
||||||
backoff := time.Second
|
// Merge the bindings together
|
||||||
// Get the existing bindings
|
ep.Bindings = mergeBindings(append(ep.Bindings, p))
|
||||||
log.Println("[DEBUG]: Retrieving policy for project", pid)
|
return nil
|
||||||
ep, err := getProjectIamPolicy(pid, config)
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Printf("[DEBUG]: Retrieved policy for project %q: %+v\n", pid, ep)
|
|
||||||
|
|
||||||
// Merge the bindings together
|
|
||||||
ep.Bindings = mergeBindings(append(ep.Bindings, p))
|
|
||||||
log.Printf("[DEBUG]: Setting policy for project %q to %+v\n", pid, ep)
|
|
||||||
err = setProjectIamPolicy(ep, config, pid)
|
|
||||||
if err == nil {
|
|
||||||
// update was successful, yay
|
|
||||||
break
|
|
||||||
} else if isConflitError(err) {
|
|
||||||
log.Printf("[DEBUG]: Concurrent policy changes, restarting read-modify-write after %s\n", backoff)
|
|
||||||
time.Sleep(backoff)
|
|
||||||
backoff = backoff * 2
|
|
||||||
if backoff > 30*time.Second {
|
|
||||||
return fmt.Errorf("Error applying IAM policy to project %q: too many concurrent policy changes.\n", pid)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return fmt.Errorf("Error applying IAM policy to project: %v", err)
|
|
||||||
}
|
|
||||||
log.Printf("[DEBUG]: Set policy for project %q", pid)
|
|
||||||
d.SetId(pid + ":" + p.Role)
|
d.SetId(pid + ":" + p.Role)
|
||||||
return resourceGoogleProjectIamBindingRead(d, meta)
|
return resourceGoogleProjectIamBindingRead(d, meta)
|
||||||
}
|
}
|
||||||
@ -133,15 +111,7 @@ func resourceGoogleProjectIamBindingUpdate(d *schema.ResourceData, meta interfac
|
|||||||
mutexKV.Lock(projectIamBindingMutexKey(pid, binding.Role))
|
mutexKV.Lock(projectIamBindingMutexKey(pid, binding.Role))
|
||||||
defer mutexKV.Unlock(projectIamBindingMutexKey(pid, binding.Role))
|
defer mutexKV.Unlock(projectIamBindingMutexKey(pid, binding.Role))
|
||||||
|
|
||||||
for {
|
err = projectIamPolicyReadModifyWrite(d, config, pid, func(p *cloudresourcemanager.Policy) error {
|
||||||
backoff := time.Second
|
|
||||||
log.Println("[DEBUG]: Retrieving policy for project", pid)
|
|
||||||
p, err := getProjectIamPolicy(pid, config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("[DEBUG]: Retrieved policy for project %q: %+v\n", pid, p)
|
|
||||||
|
|
||||||
var found bool
|
var found bool
|
||||||
for pos, b := range p.Bindings {
|
for pos, b := range p.Bindings {
|
||||||
if b.Role != binding.Role {
|
if b.Role != binding.Role {
|
||||||
@ -154,23 +124,11 @@ func resourceGoogleProjectIamBindingUpdate(d *schema.ResourceData, meta interfac
|
|||||||
if !found {
|
if !found {
|
||||||
p.Bindings = append(p.Bindings, binding)
|
p.Bindings = append(p.Bindings, binding)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
log.Printf("[DEBUG]: Setting policy for project %q to %+v\n", pid, p)
|
})
|
||||||
err = setProjectIamPolicy(p, config, pid)
|
if err != nil {
|
||||||
if err != nil && isConflictError(err) {
|
return err
|
||||||
log.Printf("[DEBUG]: Concurrent policy changes, restarting read-modify-write after %s\n", backoff)
|
|
||||||
time.Sleep(backoff)
|
|
||||||
backoff = backoff * 2
|
|
||||||
if backoff > 30*time.Second {
|
|
||||||
return fmt.Errorf("Error applying IAM policy to project %q: too many concurrent policy changes.\n", pid)
|
|
||||||
}
|
}
|
||||||
continue
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("Error applying IAM policy to project: %v", err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
log.Printf("[DEBUG]: Set policy for project %q\n", pid)
|
|
||||||
|
|
||||||
return resourceGoogleProjectIamBindingRead(d, meta)
|
return resourceGoogleProjectIamBindingRead(d, meta)
|
||||||
}
|
}
|
||||||
@ -186,15 +144,7 @@ func resourceGoogleProjectIamBindingDelete(d *schema.ResourceData, meta interfac
|
|||||||
mutexKV.Lock(projectIamBindingMutexKey(pid, binding.Role))
|
mutexKV.Lock(projectIamBindingMutexKey(pid, binding.Role))
|
||||||
defer mutexKV.Unlock(projectIamBindingMutexKey(pid, binding.Role))
|
defer mutexKV.Unlock(projectIamBindingMutexKey(pid, binding.Role))
|
||||||
|
|
||||||
for {
|
err = projectIamPolicyReadModifyWrite(d, config, pid, func(p *cloudresourcemanager.Policy) error {
|
||||||
backoff := time.Second
|
|
||||||
log.Println("[DEBUG]: Retrieving policy for project", pid)
|
|
||||||
p, err := getProjectIamPolicy(pid, config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("[DEBUG]: Retrieved policy for project %q: %+v\n", pid, p)
|
|
||||||
|
|
||||||
toRemove := -1
|
toRemove := -1
|
||||||
for pos, b := range p.Bindings {
|
for pos, b := range p.Bindings {
|
||||||
if b.Role != binding.Role {
|
if b.Role != binding.Role {
|
||||||
@ -210,23 +160,11 @@ func resourceGoogleProjectIamBindingDelete(d *schema.ResourceData, meta interfac
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.Bindings = append(p.Bindings[:toRemove], p.Bindings[toRemove+1:]...)
|
p.Bindings = append(p.Bindings[:toRemove], p.Bindings[toRemove+1:]...)
|
||||||
|
return nil
|
||||||
log.Printf("[DEBUG]: Setting policy for project %q to %+v\n", pid, p)
|
})
|
||||||
err = setProjectIamPolicy(p, config, pid)
|
if err != nil {
|
||||||
if err != nil && isConflictError(err) {
|
return err
|
||||||
log.Printf("[DEBUG]: Concurrent policy changes, restarting read-modify-write after %s\n", backoff)
|
|
||||||
time.Sleep(backoff)
|
|
||||||
backoff = backoff * 2
|
|
||||||
if backoff > 30*time.Second {
|
|
||||||
return fmt.Errorf("Error applying IAM policy to project %q: too many concurrent policy changes.\n", pid)
|
|
||||||
}
|
}
|
||||||
continue
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("Error applying IAM policy to project: %v", err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
log.Printf("[DEBUG]: Set policy for project %q\n", pid)
|
|
||||||
|
|
||||||
return resourceGoogleProjectIamBindingRead(d, meta)
|
return resourceGoogleProjectIamBindingRead(d, meta)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"sort"
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/errwrap"
|
"github.com/hashicorp/errwrap"
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
@ -418,3 +419,40 @@ func (b sortableBindings) Swap(i, j int) {
|
|||||||
func (b sortableBindings) Less(i, j int) bool {
|
func (b sortableBindings) Less(i, j int) bool {
|
||||||
return b[i].Role < b[j].Role
|
return b[i].Role < b[j].Role
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type iamPolicyModifyFunc func(p *cloudresourcemanager.Policy) error
|
||||||
|
|
||||||
|
func projectIamPolicyReadModifyWrite(d *schema.ResourceData, config *Config, pid string, modify iamPolicyModifyFunc) error {
|
||||||
|
for {
|
||||||
|
backoff := time.Second
|
||||||
|
log.Printf("[DEBUG]: Retrieving policy for project %q\n", pid)
|
||||||
|
p, err := getProjectIamPolicy(pid, config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG]: Retrieved policy for project %q: %+v\n", pid, p)
|
||||||
|
|
||||||
|
err = modify(p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG]: Setting policy for project %q to %+v\n", pid, p)
|
||||||
|
err = setProjectIamPolicy(p, config, pid)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if isConflictError(err) {
|
||||||
|
log.Printf("[DEBUG]: Concurrent policy changes, restarting read-modify-write after %s\n", backoff)
|
||||||
|
time.Sleep(backoff)
|
||||||
|
backoff = backoff * 2
|
||||||
|
if backoff > 30*time.Second {
|
||||||
|
return fmt.Errorf("Error applying IAM policy to project %q: too many concurrent policy changes.\n", pid)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Error applying IAM policy to project: %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG]: Set policy for project %q\n", pid)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user