-
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
Deal with undeletable bucket ACLs in storage. #439
Changes from 3 commits
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 |
---|---|---|
|
@@ -3,6 +3,7 @@ package google | |
import ( | ||
"fmt" | ||
"log" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/hashicorp/terraform/helper/schema" | ||
|
@@ -101,9 +102,26 @@ func resourceStorageBucketAclCreate(d *schema.ResourceData, meta interface{}) er | |
|
||
} | ||
if len(role_entity) > 0 { | ||
current, err := config.clientStorage.BucketAccessControls.List(bucket).Do() | ||
if err != nil { | ||
return fmt.Errorf("Error retrieving current ACLs: %s", err) | ||
} | ||
for _, v := range role_entity { | ||
pair, err := getRoleEntityPair(v.(string)) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
var alreadyInserted bool | ||
for _, cur := range current.Items { | ||
if cur.Entity == pair.Entity && cur.Role == pair.Role { | ||
alreadyInserted = true | ||
break | ||
} | ||
} | ||
if alreadyInserted { | ||
log.Printf("[DEBUG]: pair %s-%s already exists, not trying to insert again\n", pair.Role, pair.Entity) | ||
continue | ||
} | ||
bucketAccessControl := &storage.BucketAccessControl{ | ||
Role: pair.Role, | ||
Entity: pair.Entity, | ||
|
@@ -172,8 +190,16 @@ func resourceStorageBucketAclUpdate(d *schema.ResourceData, meta interface{}) er | |
config := meta.(*Config) | ||
|
||
bucket := d.Get("bucket").(string) | ||
project, err := getProject(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if d.HasChange("role_entity") { | ||
p, err := config.clientResourceManager.Projects.Get(project).Do() | ||
if err != nil { | ||
return fmt.Errorf("Error retrieving project %q: %s", project, err) | ||
} | ||
o, n := d.GetChange("role_entity") | ||
old_re, new_re := o.([]interface{}), n.([]interface{}) | ||
|
||
|
@@ -197,12 +223,8 @@ func resourceStorageBucketAclUpdate(d *schema.ResourceData, meta interface{}) er | |
Entity: pair.Entity, | ||
} | ||
|
||
// If the old state is missing this entity, it needs to | ||
// be created. Otherwise it is updated | ||
if _, ok := old_re_map[pair.Entity]; ok { | ||
_, err = config.clientStorage.BucketAccessControls.Update( | ||
bucket, pair.Entity, bucketAccessControl).Do() | ||
} else { | ||
// If the old state is missing this entity, it needs to be inserted | ||
if _, ok := old_re_map[pair.Entity]; !ok { | ||
_, err = config.clientStorage.BucketAccessControls.Insert( | ||
bucket, bucketAccessControl).Do() | ||
} | ||
|
@@ -215,7 +237,11 @@ func resourceStorageBucketAclUpdate(d *schema.ResourceData, meta interface{}) er | |
} | ||
} | ||
|
||
for entity, _ := range old_re_map { | ||
for entity, role := range old_re_map { | ||
if entity == "project-owners-"+strconv.FormatInt(p.ProjectNumber, 10) && role == "OWNER" { | ||
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. Would it be easier to read to do 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. Fair, I'll do that. Sorry, I'm just used to the non- |
||
log.Printf("Skipping %s-%s; not deleting owner ACL.", role, entity) | ||
continue | ||
} | ||
log.Printf("[DEBUG]: removing entity %s", entity) | ||
err := config.clientStorage.BucketAccessControls.Delete(bucket, entity).Do() | ||
|
||
|
@@ -252,15 +278,30 @@ func resourceStorageBucketAclUpdate(d *schema.ResourceData, meta interface{}) er | |
func resourceStorageBucketAclDelete(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
project, err := getProject(d, config) | ||
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. Same comment as above re: which project owns the bucket |
||
if err != nil { | ||
return err | ||
} | ||
|
||
bucket := d.Get("bucket").(string) | ||
|
||
p, err := config.clientResourceManager.Projects.Get(project).Do() | ||
if err != nil { | ||
return fmt.Errorf("Error retrieving project %q: %s", project, err) | ||
} | ||
|
||
re_local := d.Get("role_entity").([]interface{}) | ||
for _, v := range re_local { | ||
res, err := getRoleEntityPair(v.(string)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if res.Entity == "project-owners-"+strconv.FormatInt(p.ProjectNumber, 10) && res.Role == "OWNER" { | ||
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. Same as above re: string concat |
||
log.Printf("Skipping %s-%s; not deleting owner ACL.", res.Role, res.Entity) | ||
continue | ||
} | ||
|
||
log.Printf("[DEBUG]: removing entity %s", res.Entity) | ||
|
||
err = config.clientStorage.BucketAccessControls.Delete(bucket, res.Entity).Do() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,28 +2,32 @@ package google | |
|
||
import ( | ||
"fmt" | ||
"os" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/acctest" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
//"google.golang.org/api/storage/v1" | ||
) | ||
|
||
var roleEntityBasic1 = "OWNER:[email protected]" | ||
var ( | ||
roleEntityBasic1 = "OWNER:[email protected]" | ||
roleEntityBasic2 = "READER:[email protected]" | ||
roleEntityBasic3_owner = "OWNER:[email protected]" | ||
roleEntityBasic3_reader = "READER:[email protected]" | ||
|
||
var roleEntityBasic2 = "READER:[email protected]" | ||
|
||
var roleEntityBasic3_owner = "OWNER:[email protected]" | ||
|
||
var roleEntityBasic3_reader = "READER:[email protected]" | ||
roleEntityOwners = "OWNER:project-owners-" + os.Getenv("GOOGLE_PROJECT_NUMBER") | ||
roleEntityEditors = "OWNER:project-editors-" + os.Getenv("GOOGLE_PROJECT_NUMBER") | ||
roleEntityViewers = "READER:project-viewers-" + os.Getenv("GOOGLE_PROJECT_NUMBER") | ||
) | ||
|
||
func testBucketName() string { | ||
return fmt.Sprintf("%s-%d", "tf-test-acl-bucket", acctest.RandInt()) | ||
} | ||
|
||
func TestAccGoogleStorageBucketAcl_basic(t *testing.T) { | ||
bucketName := testBucketName() | ||
skipIfEnvNotSet(t, "GOOGLE_PROJECT_NUMBER") | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
|
@@ -42,6 +46,7 @@ func TestAccGoogleStorageBucketAcl_basic(t *testing.T) { | |
|
||
func TestAccGoogleStorageBucketAcl_upgrade(t *testing.T) { | ||
bucketName := testBucketName() | ||
skipIfEnvNotSet(t, "GOOGLE_PROJECT_NUMBER") | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
|
@@ -77,6 +82,7 @@ func TestAccGoogleStorageBucketAcl_upgrade(t *testing.T) { | |
|
||
func TestAccGoogleStorageBucketAcl_downgrade(t *testing.T) { | ||
bucketName := testBucketName() | ||
skipIfEnvNotSet(t, "GOOGLE_PROJECT_NUMBER") | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
|
@@ -186,9 +192,9 @@ resource "google_storage_bucket" "bucket" { | |
|
||
resource "google_storage_bucket_acl" "acl" { | ||
bucket = "${google_storage_bucket.bucket.name}" | ||
role_entity = ["%s", "%s"] | ||
role_entity = ["%s", "%s", "%s", "%s", "%s"] | ||
} | ||
`, bucketName, roleEntityBasic1, roleEntityBasic2) | ||
`, bucketName, roleEntityOwners, roleEntityEditors, roleEntityViewers, roleEntityBasic1, roleEntityBasic2) | ||
} | ||
|
||
func testGoogleStorageBucketsAclBasic2(bucketName string) string { | ||
|
@@ -199,9 +205,9 @@ resource "google_storage_bucket" "bucket" { | |
|
||
resource "google_storage_bucket_acl" "acl" { | ||
bucket = "${google_storage_bucket.bucket.name}" | ||
role_entity = ["%s", "%s"] | ||
role_entity = ["%s", "%s", "%s", "%s", "%s"] | ||
} | ||
`, bucketName, roleEntityBasic2, roleEntityBasic3_owner) | ||
`, bucketName, roleEntityOwners, roleEntityEditors, roleEntityViewers, roleEntityBasic2, roleEntityBasic3_owner) | ||
} | ||
|
||
func testGoogleStorageBucketsAclBasicDelete(bucketName string) string { | ||
|
@@ -225,9 +231,9 @@ resource "google_storage_bucket" "bucket" { | |
|
||
resource "google_storage_bucket_acl" "acl" { | ||
bucket = "${google_storage_bucket.bucket.name}" | ||
role_entity = ["%s", "%s"] | ||
role_entity = ["%s", "%s", "%s", "%s", "%s"] | ||
} | ||
`, bucketName, roleEntityBasic2, roleEntityBasic3_reader) | ||
`, bucketName, roleEntityOwners, roleEntityEditors, roleEntityViewers, roleEntityBasic2, roleEntityBasic3_reader) | ||
} | ||
|
||
func testGoogleStorageBucketsAclPredefined(bucketName string) string { | ||
|
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.
technically this might not match the project that owns the bucket, right? If someone is managing a bucket in terraform that doesn't belong to their provider's configured project this might cause issues...
Fixing this might be too painful right now so if what I said is true, I'm fine with just acknowledging it with a TODO
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.
This is a good point, and is actually easier to implement; we can just read the bucket from the API, and pull the project number off it. Great point, and thanks for pointing it out. I like that solution much better.
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.
I didn't realize the project id is on the bucket resource; that makes this change a lot easier