-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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 google_project_iam_binding and google_project_iam_member resources. #171
Changes from all commits
8e70487
eed8487
11abe24
65a4a36
a84b22d
f9236ab
8a880fd
d3f901b
9c1c0bb
729e9fc
5282ad7
f9eeb36
52d552d
b0e3790
91d227c
655435f
fa2d54f
199ff5d
adc206a
f94c387
7854535
f88e042
ac5df40
d3426d5
6f98217
4b9432d
c89429c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the purpose of the final read? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updates the state file with the state according to the API. In this case, confirms the API no longer has the binding in it, and removes it. If for whatever reason the delete function silently failed and didn't actually delete the binding, Terraform wouldn't lose it. |
||
} | ||
|
||
// 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) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to set the id to "" here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The read call does that. :)