terraform-provider-google/google/resource_storage_bucket_acl_test.go

291 lines
8.3 KiB
Go
Raw Normal View History

package google
import (
"fmt"
"os"
2015-10-07 20:35:06 +00:00
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
Deal with undeleatable bucket ACLs in storage. When GCS buckets are created, they're created with a set of default ACLs: * `OWNER:project-owners-{project_number}` * `OWNER:project-editors-{project_number}` * `READER:project-viewers-{project_number}` Normally, this would be fine, or a minor inconvenience. Terraform could either delete them itself, or the first apply of a user would overwrite them. However, trying to remove the `OWNER:project-owners-{project_number}` ACL yields an API error that the bucket owner must maintain OWNER access to the bucket. This breaks things like `terraform destroy`, but also means any config without that line in it will fail to apply, not just overwrite the value. To make matters worse, trying to *add* the `OWNER:project-owners-{project_number}` ACL to any bucket that already has it _also_ yields the same error about not being able to remove it. To get around this, the storage_bucket_acl resource has been updated to largely ignore _just this_ ACL. It will not try to add it if it already exists, will not try to remove it at all. This does mean that Terraform is incapable of removing this ACL from a bucket, but I'm not sure it's possible to do that with the API, anyways. Tests were also updated to keep the default ACLs as part of the config, and to change the email addresses to addresses we actually own. I tried changing to non-existant hashicorp.com email addresses, but was rejected; only email addresses that are backed by actual Google accounts can be used, sadly.
2017-09-15 19:03:03 +00:00
var (
roleEntityBasic1 = "OWNER:user-paddy@hashicorp.com"
roleEntityBasic2 = "READER:user-paddy@carvers.co"
roleEntityBasic3_owner = "OWNER:user-paddy@paddy.io"
roleEntityBasic3_reader = "READER:user-foran.paddy@gmail.com"
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 TestAccStorageBucketAcl_basic(t *testing.T) {
t.Parallel()
bucketName := testBucketName()
skipIfEnvNotSet(t, "GOOGLE_PROJECT_NUMBER")
resource.Test(t, resource.TestCase{
2015-10-07 20:35:06 +00:00
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccStorageBucketAclDestroy,
Steps: []resource.TestStep{
{
Config: testGoogleStorageBucketsAclBasic1(bucketName),
2015-10-07 20:35:06 +00:00
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic1),
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic2),
),
},
},
})
}
func TestAccStorageBucketAcl_upgrade(t *testing.T) {
t.Parallel()
bucketName := testBucketName()
skipIfEnvNotSet(t, "GOOGLE_PROJECT_NUMBER")
resource.Test(t, resource.TestCase{
2015-10-07 20:35:06 +00:00
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccStorageBucketAclDestroy,
Steps: []resource.TestStep{
{
Config: testGoogleStorageBucketsAclBasic1(bucketName),
2015-10-07 20:35:06 +00:00
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic1),
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic2),
),
},
{
Config: testGoogleStorageBucketsAclBasic2(bucketName),
2015-10-07 20:35:06 +00:00
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic2),
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic3_owner),
),
},
{
Config: testGoogleStorageBucketsAclBasicDelete(bucketName),
2015-10-07 20:35:06 +00:00
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleStorageBucketAclDelete(bucketName, roleEntityBasic1),
testAccCheckGoogleStorageBucketAclDelete(bucketName, roleEntityBasic2),
testAccCheckGoogleStorageBucketAclDelete(bucketName, roleEntityBasic3_owner),
),
},
},
})
}
func TestAccStorageBucketAcl_downgrade(t *testing.T) {
t.Parallel()
bucketName := testBucketName()
skipIfEnvNotSet(t, "GOOGLE_PROJECT_NUMBER")
resource.Test(t, resource.TestCase{
2015-10-07 20:35:06 +00:00
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccStorageBucketAclDestroy,
Steps: []resource.TestStep{
{
Config: testGoogleStorageBucketsAclBasic2(bucketName),
2015-10-07 20:35:06 +00:00
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic2),
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic3_owner),
),
},
{
Config: testGoogleStorageBucketsAclBasic3(bucketName),
2015-10-07 20:35:06 +00:00
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic2),
testAccCheckGoogleStorageBucketAcl(bucketName, roleEntityBasic3_reader),
),
},
{
Config: testGoogleStorageBucketsAclBasicDelete(bucketName),
2015-10-07 20:35:06 +00:00
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleStorageBucketAclDelete(bucketName, roleEntityBasic1),
testAccCheckGoogleStorageBucketAclDelete(bucketName, roleEntityBasic2),
testAccCheckGoogleStorageBucketAclDelete(bucketName, roleEntityBasic3_owner),
),
},
},
})
}
func TestAccStorageBucketAcl_predefined(t *testing.T) {
t.Parallel()
bucketName := testBucketName()
resource.Test(t, resource.TestCase{
2015-10-07 20:35:06 +00:00
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccStorageBucketAclDestroy,
Steps: []resource.TestStep{
{
Config: testGoogleStorageBucketsAclPredefined(bucketName),
},
},
})
}
// Test that we allow the API to reorder our role entities without perma-diffing.
func TestAccStorageBucketAcl_unordered(t *testing.T) {
t.Parallel()
bucketName := testBucketName()
skipIfEnvNotSet(t, "GOOGLE_PROJECT_NUMBER")
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccStorageBucketAclDestroy,
Steps: []resource.TestStep{
{
Config: testGoogleStorageBucketsAclUnordered(bucketName),
},
},
})
}
func testAccCheckGoogleStorageBucketAclDelete(bucket, roleEntityS string) resource.TestCheckFunc {
return func(s *terraform.State) error {
roleEntity, _ := getRoleEntityPair(roleEntityS)
config := testAccProvider.Meta().(*Config)
_, err := config.clientStorage.BucketAccessControls.Get(bucket, roleEntity.Entity).Do()
if err != nil {
return nil
}
return fmt.Errorf("Error, entity %s still exists", roleEntity.Entity)
}
}
func testAccCheckGoogleStorageBucketAcl(bucket, roleEntityS string) resource.TestCheckFunc {
return func(s *terraform.State) error {
roleEntity, _ := getRoleEntityPair(roleEntityS)
config := testAccProvider.Meta().(*Config)
res, err := config.clientStorage.BucketAccessControls.Get(bucket, roleEntity.Entity).Do()
if err != nil {
return fmt.Errorf("Error retrieving contents of acl for bucket %s: %s", bucket, err)
}
2015-10-07 20:35:06 +00:00
if res.Role != roleEntity.Role {
return fmt.Errorf("Error, Role mismatch %s != %s", res.Role, roleEntity.Role)
}
return nil
}
}
func testAccStorageBucketAclDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_storage_bucket_acl" {
continue
}
bucket := rs.Primary.Attributes["bucket"]
_, err := config.clientStorage.BucketAccessControls.List(bucket).Do()
if err == nil {
return fmt.Errorf("Acl for bucket %s still exists", bucket)
}
}
return nil
}
func testGoogleStorageBucketsAclBasic1(bucketName string) string {
return fmt.Sprintf(`
resource "google_storage_bucket" "bucket" {
name = "%s"
}
resource "google_storage_bucket_acl" "acl" {
bucket = "${google_storage_bucket.bucket.name}"
Deal with undeleatable bucket ACLs in storage. When GCS buckets are created, they're created with a set of default ACLs: * `OWNER:project-owners-{project_number}` * `OWNER:project-editors-{project_number}` * `READER:project-viewers-{project_number}` Normally, this would be fine, or a minor inconvenience. Terraform could either delete them itself, or the first apply of a user would overwrite them. However, trying to remove the `OWNER:project-owners-{project_number}` ACL yields an API error that the bucket owner must maintain OWNER access to the bucket. This breaks things like `terraform destroy`, but also means any config without that line in it will fail to apply, not just overwrite the value. To make matters worse, trying to *add* the `OWNER:project-owners-{project_number}` ACL to any bucket that already has it _also_ yields the same error about not being able to remove it. To get around this, the storage_bucket_acl resource has been updated to largely ignore _just this_ ACL. It will not try to add it if it already exists, will not try to remove it at all. This does mean that Terraform is incapable of removing this ACL from a bucket, but I'm not sure it's possible to do that with the API, anyways. Tests were also updated to keep the default ACLs as part of the config, and to change the email addresses to addresses we actually own. I tried changing to non-existant hashicorp.com email addresses, but was rejected; only email addresses that are backed by actual Google accounts can be used, sadly.
2017-09-15 19:03:03 +00:00
role_entity = ["%s", "%s", "%s", "%s", "%s"]
}
`, bucketName, roleEntityOwners, roleEntityEditors, roleEntityViewers, roleEntityBasic1, roleEntityBasic2)
}
func testGoogleStorageBucketsAclBasic2(bucketName string) string {
return fmt.Sprintf(`
resource "google_storage_bucket" "bucket" {
name = "%s"
}
resource "google_storage_bucket_acl" "acl" {
bucket = "${google_storage_bucket.bucket.name}"
Deal with undeleatable bucket ACLs in storage. When GCS buckets are created, they're created with a set of default ACLs: * `OWNER:project-owners-{project_number}` * `OWNER:project-editors-{project_number}` * `READER:project-viewers-{project_number}` Normally, this would be fine, or a minor inconvenience. Terraform could either delete them itself, or the first apply of a user would overwrite them. However, trying to remove the `OWNER:project-owners-{project_number}` ACL yields an API error that the bucket owner must maintain OWNER access to the bucket. This breaks things like `terraform destroy`, but also means any config without that line in it will fail to apply, not just overwrite the value. To make matters worse, trying to *add* the `OWNER:project-owners-{project_number}` ACL to any bucket that already has it _also_ yields the same error about not being able to remove it. To get around this, the storage_bucket_acl resource has been updated to largely ignore _just this_ ACL. It will not try to add it if it already exists, will not try to remove it at all. This does mean that Terraform is incapable of removing this ACL from a bucket, but I'm not sure it's possible to do that with the API, anyways. Tests were also updated to keep the default ACLs as part of the config, and to change the email addresses to addresses we actually own. I tried changing to non-existant hashicorp.com email addresses, but was rejected; only email addresses that are backed by actual Google accounts can be used, sadly.
2017-09-15 19:03:03 +00:00
role_entity = ["%s", "%s", "%s", "%s", "%s"]
}
`, bucketName, roleEntityOwners, roleEntityEditors, roleEntityViewers, roleEntityBasic2, roleEntityBasic3_owner)
}
func testGoogleStorageBucketsAclBasicDelete(bucketName string) string {
return fmt.Sprintf(`
resource "google_storage_bucket" "bucket" {
name = "%s"
}
resource "google_storage_bucket_acl" "acl" {
bucket = "${google_storage_bucket.bucket.name}"
role_entity = []
}
`, bucketName)
}
func testGoogleStorageBucketsAclBasic3(bucketName string) string {
return fmt.Sprintf(`
resource "google_storage_bucket" "bucket" {
name = "%s"
}
resource "google_storage_bucket_acl" "acl" {
bucket = "${google_storage_bucket.bucket.name}"
Deal with undeleatable bucket ACLs in storage. When GCS buckets are created, they're created with a set of default ACLs: * `OWNER:project-owners-{project_number}` * `OWNER:project-editors-{project_number}` * `READER:project-viewers-{project_number}` Normally, this would be fine, or a minor inconvenience. Terraform could either delete them itself, or the first apply of a user would overwrite them. However, trying to remove the `OWNER:project-owners-{project_number}` ACL yields an API error that the bucket owner must maintain OWNER access to the bucket. This breaks things like `terraform destroy`, but also means any config without that line in it will fail to apply, not just overwrite the value. To make matters worse, trying to *add* the `OWNER:project-owners-{project_number}` ACL to any bucket that already has it _also_ yields the same error about not being able to remove it. To get around this, the storage_bucket_acl resource has been updated to largely ignore _just this_ ACL. It will not try to add it if it already exists, will not try to remove it at all. This does mean that Terraform is incapable of removing this ACL from a bucket, but I'm not sure it's possible to do that with the API, anyways. Tests were also updated to keep the default ACLs as part of the config, and to change the email addresses to addresses we actually own. I tried changing to non-existant hashicorp.com email addresses, but was rejected; only email addresses that are backed by actual Google accounts can be used, sadly.
2017-09-15 19:03:03 +00:00
role_entity = ["%s", "%s", "%s", "%s", "%s"]
}
`, bucketName, roleEntityOwners, roleEntityEditors, roleEntityViewers, roleEntityBasic2, roleEntityBasic3_reader)
}
func testGoogleStorageBucketsAclUnordered(bucketName string) string {
return fmt.Sprintf(`
resource "google_storage_bucket" "bucket" {
name = "%s"
}
resource "google_storage_bucket_acl" "acl" {
bucket = "${google_storage_bucket.bucket.name}"
role_entity = ["%s", "%s", "%s", "%s", "%s"]
}
`, bucketName, roleEntityBasic1, roleEntityViewers, roleEntityOwners, roleEntityBasic2, roleEntityEditors)
}
func testGoogleStorageBucketsAclPredefined(bucketName string) string {
return fmt.Sprintf(`
resource "google_storage_bucket" "bucket" {
name = "%s"
}
resource "google_storage_bucket_acl" "acl" {
bucket = "${google_storage_bucket.bucket.name}"
predefined_acl = "projectPrivate"
default_acl = "projectPrivate"
}
`, bucketName)
}