terraform-provider-google/google/resource_google_project_iam_binding.go
Paddy d3426d5bc6 Don't set IDs in RMW loops.
We don't need to set the ID to "" in read-modify-write helpers, because
once they're done, we read anyways to update state based on the changes.
And that read checks if the binding/member still exists, and does the
SetId("") if it doesn't.

This way, we stick with state only getting set based on the API state,
not by what we think the state will be.
2017-07-27 14:29:25 -07:00

184 lines
4.5 KiB
Go

package google
import (
"fmt"
"log"
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/cloudresourcemanager/v1"
)
func resourceGoogleProjectIamBinding() *schema.Resource {
return &schema.Resource{
Create: resourceGoogleProjectIamBindingCreate,
Read: resourceGoogleProjectIamBindingRead,
Update: resourceGoogleProjectIamBindingUpdate,
Delete: resourceGoogleProjectIamBindingDelete,
Schema: map[string]*schema.Schema{
"project": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"role": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"members": {
Type: schema.TypeSet,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"etag": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
func resourceGoogleProjectIamBindingCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
pid, err := getProject(d, config)
if err != nil {
return err
}
// Get the binding in the template
log.Println("[DEBUG]: Reading google_project_iam_binding")
p := getResourceIamBinding(d)
mutexKV.Lock(projectIamBindingMutexKey(pid, p.Role))
defer mutexKV.Unlock(projectIamBindingMutexKey(pid, p.Role))
err = projectIamPolicyReadModifyWrite(d, config, pid, func(ep *cloudresourcemanager.Policy) error {
// Merge the bindings together
ep.Bindings = mergeBindings(append(ep.Bindings, p))
return nil
})
if err != nil {
return err
}
d.SetId(pid + "/" + p.Role)
return resourceGoogleProjectIamBindingRead(d, meta)
}
func resourceGoogleProjectIamBindingRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
pid, err := getProject(d, config)
if err != nil {
return err
}
eBinding := getResourceIamBinding(d)
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 binding *cloudresourcemanager.Binding
for _, b := range p.Bindings {
if b.Role != eBinding.Role {
continue
}
binding = b
break
}
if binding == nil {
log.Printf("[DEBUG]: Binding for role %q not found in policy for %q, removing from state file.\n", eBinding.Role, pid)
d.SetId("")
return nil
}
d.Set("etag", p.Etag)
d.Set("members", binding.Members)
d.Set("role", binding.Role)
return nil
}
func resourceGoogleProjectIamBindingUpdate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
pid, err := getProject(d, config)
if err != nil {
return err
}
binding := getResourceIamBinding(d)
mutexKV.Lock(projectIamBindingMutexKey(pid, binding.Role))
defer mutexKV.Unlock(projectIamBindingMutexKey(pid, binding.Role))
err = projectIamPolicyReadModifyWrite(d, config, pid, func(p *cloudresourcemanager.Policy) error {
var found bool
for pos, b := range p.Bindings {
if b.Role != binding.Role {
continue
}
found = true
p.Bindings[pos] = binding
break
}
if !found {
p.Bindings = append(p.Bindings, binding)
}
return nil
})
if err != nil {
return err
}
return resourceGoogleProjectIamBindingRead(d, meta)
}
func resourceGoogleProjectIamBindingDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
pid, err := getProject(d, config)
if err != nil {
return err
}
binding := getResourceIamBinding(d)
mutexKV.Lock(projectIamBindingMutexKey(pid, binding.Role))
defer mutexKV.Unlock(projectIamBindingMutexKey(pid, binding.Role))
err = projectIamPolicyReadModifyWrite(d, config, pid, func(p *cloudresourcemanager.Policy) error {
toRemove := -1
for pos, b := range p.Bindings {
if b.Role != binding.Role {
continue
}
toRemove = pos
break
}
if toRemove < 0 {
log.Printf("[DEBUG]: Policy bindings for project %q did not include a binding for role %q", pid, binding.Role)
return nil
}
p.Bindings = append(p.Bindings[:toRemove], p.Bindings[toRemove+1:]...)
return nil
})
if err != nil {
return err
}
return resourceGoogleProjectIamBindingRead(d, meta)
}
// Get a cloudresourcemanager.Binding from a schema.ResourceData
func getResourceIamBinding(d *schema.ResourceData) *cloudresourcemanager.Binding {
members := d.Get("members").(*schema.Set).List()
return &cloudresourcemanager.Binding{
Members: convertStringArr(members),
Role: d.Get("role").(string),
}
}
func projectIamBindingMutexKey(pid, role string) string {
return fmt.Sprintf("google-project-iam-binding-%s-%s", pid, role)
}