mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-01 16:21:06 +00:00
Make google_storage_default_object_acl authoritative. (#2345)
<!-- This change is generated by MagicModules. --> /cc @rileykarson
This commit is contained in:
parent
12369626c8
commit
bf296e55bf
@ -2,61 +2,69 @@ package google
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
"google.golang.org/api/storage/v1"
|
"google.golang.org/api/storage/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resourceStorageDefaultObjectAcl() *schema.Resource {
|
func resourceStorageDefaultObjectAcl() *schema.Resource {
|
||||||
return &schema.Resource{
|
return &schema.Resource{
|
||||||
Create: resourceStorageDefaultObjectAclCreate,
|
Create: resourceStorageDefaultObjectAclCreateUpdate,
|
||||||
Read: resourceStorageDefaultObjectAclRead,
|
Read: resourceStorageDefaultObjectAclRead,
|
||||||
Update: resourceStorageDefaultObjectAclUpdate,
|
Update: resourceStorageDefaultObjectAclCreateUpdate,
|
||||||
Delete: resourceStorageDefaultObjectAclDelete,
|
Delete: resourceStorageDefaultObjectAclDelete,
|
||||||
CustomizeDiff: resourceStorageRoleEntityCustomizeDiff,
|
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"bucket": &schema.Schema{
|
"bucket": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
"role_entity": &schema.Schema{
|
"role_entity": {
|
||||||
Type: schema.TypeList,
|
Type: schema.TypeSet,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
Elem: &schema.Schema{
|
||||||
MinItems: 1,
|
Type: schema.TypeString,
|
||||||
|
ValidateFunc: validateRoleEntityPair,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceStorageDefaultObjectAclCreate(d *schema.ResourceData, meta interface{}) error {
|
func resourceStorageDefaultObjectAclCreateUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
config := meta.(*Config)
|
config := meta.(*Config)
|
||||||
|
|
||||||
bucket := d.Get("bucket").(string)
|
bucket := d.Get("bucket").(string)
|
||||||
roleEntity := d.Get("role_entity").([]interface{})
|
defaultObjectAcl := []*storage.ObjectAccessControl{}
|
||||||
|
for _, v := range d.Get("role_entity").(*schema.Set).List() {
|
||||||
for _, v := range roleEntity {
|
pair := getValidatedRoleEntityPair(v.(string))
|
||||||
pair, err := getRoleEntityPair(v.(string))
|
defaultObjectAcl = append(defaultObjectAcl, &storage.ObjectAccessControl{
|
||||||
|
|
||||||
ObjectAccessControl := &storage.ObjectAccessControl{
|
|
||||||
Role: pair.Role,
|
Role: pair.Role,
|
||||||
Entity: pair.Entity,
|
Entity: pair.Entity,
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("[DEBUG]: setting role = %s, entity = %s on bucket %s", pair.Role, pair.Entity, bucket)
|
res, err := config.clientStorage.Buckets.Get(bucket).Do()
|
||||||
|
if err != nil {
|
||||||
_, err = config.clientStorage.DefaultObjectAccessControls.Insert(bucket, ObjectAccessControl).Do()
|
return fmt.Errorf("Error reading bucket %s: %v", bucket, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even with ForceSendFields the empty array wasn't working. Luckily, this is the same thing
|
||||||
|
if len(defaultObjectAcl) == 0 {
|
||||||
|
_, err = config.clientStorage.Buckets.Update(bucket, res).IfMetagenerationMatch(res.Metageneration).PredefinedDefaultObjectAcl("private").Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error setting Default Object ACL for %s on bucket %s: %v", pair.Entity, bucket, err)
|
return fmt.Errorf("Error updating default object acl to empty for bucket %s: %v", bucket, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.DefaultObjectAcl = defaultObjectAcl
|
||||||
|
_, err = config.clientStorage.Buckets.Update(bucket, res).IfMetagenerationMatch(res.Metageneration).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating default object acl for bucket %s: %v", bucket, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.SetId(bucket)
|
|
||||||
return resourceStorageDefaultObjectAclRead(d, meta)
|
return resourceStorageDefaultObjectAclRead(d, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,123 +72,39 @@ func resourceStorageDefaultObjectAclRead(d *schema.ResourceData, meta interface{
|
|||||||
config := meta.(*Config)
|
config := meta.(*Config)
|
||||||
|
|
||||||
bucket := d.Get("bucket").(string)
|
bucket := d.Get("bucket").(string)
|
||||||
|
res, err := config.clientStorage.Buckets.Get(bucket).Projection("full").Do()
|
||||||
roleEntities := make([]interface{}, 0)
|
|
||||||
reLocal := d.Get("role_entity").([]interface{})
|
|
||||||
reLocalMap := make(map[string]string)
|
|
||||||
for _, v := range reLocal {
|
|
||||||
res, err := getRoleEntityPair(v.(string))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"Old state has malformed Role/Entity pair: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
reLocalMap[res.Entity] = res.Role
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := config.clientStorage.DefaultObjectAccessControls.List(bucket).Do()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleNotFoundError(err, d, fmt.Sprintf("Storage Default Object ACL for bucket %q", d.Get("bucket").(string)))
|
return handleNotFoundError(err, d, fmt.Sprintf("Default Storage Object ACL for Bucket %q", d.Get("bucket").(string)))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range res.Items {
|
var roleEntities []string
|
||||||
role := v.Role
|
for _, roleEntity := range res.DefaultObjectAcl {
|
||||||
entity := v.Entity
|
role := roleEntity.Role
|
||||||
// We only store updates to the locally defined access controls
|
entity := roleEntity.Entity
|
||||||
if _, in := reLocalMap[entity]; in {
|
roleEntities = append(roleEntities, fmt.Sprintf("%s:%s", role, entity))
|
||||||
roleEntities = append(roleEntities, fmt.Sprintf("%s:%s", role, entity))
|
|
||||||
log.Printf("[DEBUG]: saving re %s-%s", v.Role, v.Entity)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Set("role_entity", roleEntities)
|
err = d.Set("role_entity", roleEntities)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(bucket)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceStorageDefaultObjectAclUpdate(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
config := meta.(*Config)
|
|
||||||
|
|
||||||
bucket := d.Get("bucket").(string)
|
|
||||||
|
|
||||||
if !d.HasChange("role_entity") {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
o, n := d.GetChange("role_entity")
|
|
||||||
oldRe := o.([]interface{})
|
|
||||||
newRe := n.([]interface{})
|
|
||||||
|
|
||||||
oldReMap := make(map[string]string)
|
|
||||||
for _, v := range oldRe {
|
|
||||||
res, err := getRoleEntityPair(v.(string))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"Old state has malformed Role/Entity pair: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
oldReMap[res.Entity] = res.Role
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range newRe {
|
|
||||||
pair, err := getRoleEntityPair(v.(string))
|
|
||||||
|
|
||||||
ObjectAccessControl := &storage.ObjectAccessControl{
|
|
||||||
Role: pair.Role,
|
|
||||||
Entity: pair.Entity,
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the old state is present for the entity, it is updated
|
|
||||||
// If the old state is missing, it is inserted
|
|
||||||
if _, ok := oldReMap[pair.Entity]; ok {
|
|
||||||
_, err = config.clientStorage.DefaultObjectAccessControls.Update(
|
|
||||||
bucket, pair.Entity, ObjectAccessControl).Do()
|
|
||||||
} else {
|
|
||||||
_, err = config.clientStorage.DefaultObjectAccessControls.Insert(
|
|
||||||
bucket, ObjectAccessControl).Do()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we only store the keys that have to be removed
|
|
||||||
delete(oldReMap, pair.Entity)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error updating Storage Default Object ACL for bucket %s: %v", bucket, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for entity := range oldReMap {
|
|
||||||
log.Printf("[DEBUG]: removing entity %s", entity)
|
|
||||||
err := config.clientStorage.DefaultObjectAccessControls.Delete(bucket, entity).Do()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error updating Storage Default Object ACL for bucket %s: %v", bucket, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resourceStorageDefaultObjectAclRead(d, meta)
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceStorageDefaultObjectAclDelete(d *schema.ResourceData, meta interface{}) error {
|
func resourceStorageDefaultObjectAclDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
config := meta.(*Config)
|
config := meta.(*Config)
|
||||||
|
|
||||||
bucket := d.Get("bucket").(string)
|
bucket := d.Get("bucket").(string)
|
||||||
|
res, err := config.clientStorage.Buckets.Get(bucket).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error reading bucket %s: %v", bucket, err)
|
||||||
|
}
|
||||||
|
|
||||||
reLocal := d.Get("role_entity").([]interface{})
|
_, err = config.clientStorage.Buckets.Update(bucket, res).IfMetagenerationMatch(res.Metageneration).PredefinedDefaultObjectAcl("private").Do()
|
||||||
for _, v := range reLocal {
|
if err != nil {
|
||||||
res, err := getRoleEntityPair(v.(string))
|
return fmt.Errorf("Error deleting (updating to private) default object acl for bucket %s: %v", bucket, err)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[DEBUG]: removing entity %s", res.Entity)
|
|
||||||
|
|
||||||
err = config.clientStorage.DefaultObjectAccessControls.Delete(bucket, res.Entity).Do()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error deleting entity %s ACL: %s", res.Entity, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -12,7 +12,6 @@ func TestAccStorageDefaultObjectAcl_basic(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
bucketName := testBucketName()
|
bucketName := testBucketName()
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
resource.Test(t, resource.TestCase{
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
Providers: testAccProviders,
|
Providers: testAccProviders,
|
||||||
@ -29,6 +28,22 @@ func TestAccStorageDefaultObjectAcl_basic(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccStorageDefaultObjectAcl_noRoleEntity(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
bucketName := testBucketName()
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccStorageDefaultObjectAclDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testGoogleStorageDefaultObjectsAclNoRoleEntity(bucketName),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccStorageDefaultObjectAcl_upgrade(t *testing.T) {
|
func TestAccStorageDefaultObjectAcl_upgrade(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@ -178,6 +193,19 @@ func testAccCheckGoogleStorageDefaultObjectAclDelete(bucket, roleEntityS string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testGoogleStorageDefaultObjectsAclBasic(bucketName, roleEntity1, roleEntity2 string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "google_storage_bucket" "bucket" {
|
||||||
|
name = "%s"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_storage_default_object_acl" "acl" {
|
||||||
|
bucket = "${google_storage_bucket.bucket.name}"
|
||||||
|
role_entity = ["%s", "%s"]
|
||||||
|
}
|
||||||
|
`, bucketName, roleEntity1, roleEntity2)
|
||||||
|
}
|
||||||
|
|
||||||
func testGoogleStorageDefaultObjectsAclBasicDelete(bucketName, roleEntity string) string {
|
func testGoogleStorageDefaultObjectsAclBasicDelete(bucketName, roleEntity string) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
resource "google_storage_bucket" "bucket" {
|
resource "google_storage_bucket" "bucket" {
|
||||||
@ -191,7 +219,7 @@ resource "google_storage_default_object_acl" "acl" {
|
|||||||
`, bucketName, roleEntity)
|
`, bucketName, roleEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGoogleStorageDefaultObjectsAclBasic(bucketName, roleEntity1, roleEntity2 string) string {
|
func testGoogleStorageDefaultObjectsAclNoRoleEntity(bucketName string) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
resource "google_storage_bucket" "bucket" {
|
resource "google_storage_bucket" "bucket" {
|
||||||
name = "%s"
|
name = "%s"
|
||||||
@ -199,9 +227,9 @@ resource "google_storage_bucket" "bucket" {
|
|||||||
|
|
||||||
resource "google_storage_default_object_acl" "acl" {
|
resource "google_storage_default_object_acl" "acl" {
|
||||||
bucket = "${google_storage_bucket.bucket.name}"
|
bucket = "${google_storage_bucket.bucket.name}"
|
||||||
role_entity = ["%s", "%s"]
|
role_entity = []
|
||||||
}
|
}
|
||||||
`, bucketName, roleEntity1, roleEntity2)
|
`, bucketName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGoogleStorageDefaultObjectAclUnordered(bucketName string) string {
|
func testGoogleStorageDefaultObjectAclUnordered(bucketName string) string {
|
||||||
|
@ -3,12 +3,19 @@ layout: "google"
|
|||||||
page_title: "Google: google_storage_default_object_acl"
|
page_title: "Google: google_storage_default_object_acl"
|
||||||
sidebar_current: "docs-google-storage-default-object-acl"
|
sidebar_current: "docs-google-storage-default-object-acl"
|
||||||
description: |-
|
description: |-
|
||||||
Creates a new default object ACL in Google Cloud Storage.
|
Authoritatively manages the default object ACLs for a Google Cloud Storage bucket
|
||||||
---
|
---
|
||||||
|
|
||||||
# google\_storage\_default\_object\_acl
|
# google\_storage\_default\_object\_acl
|
||||||
|
|
||||||
Creates a new default object ACL in Google Cloud Storage service (GCS). For more information see
|
Authoritatively manages the default object ACLs for a Google Cloud Storage bucket
|
||||||
|
without managing the bucket itself.
|
||||||
|
|
||||||
|
-> Note that for each object, its creator will have the `"OWNER"` role in addition
|
||||||
|
to the default ACL that has been defined.
|
||||||
|
|
||||||
|
|
||||||
|
For more information see
|
||||||
[the official documentation](https://cloud.google.com/storage/docs/access-control/lists)
|
[the official documentation](https://cloud.google.com/storage/docs/access-control/lists)
|
||||||
and
|
and
|
||||||
[API](https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls).
|
[API](https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls).
|
||||||
@ -36,7 +43,11 @@ resource "google_storage_default_object_acl" "image-store-default-acl" {
|
|||||||
|
|
||||||
* `bucket` - (Required) The name of the bucket it applies to.
|
* `bucket` - (Required) The name of the bucket it applies to.
|
||||||
|
|
||||||
* `role_entity` - (Required) List of role/entity pairs in the form `ROLE:entity`. See [GCS Object ACL documentation](https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls) for more details.
|
---
|
||||||
|
|
||||||
|
* `role_entity` - (Optional) List of role/entity pairs in the form `ROLE:entity`.
|
||||||
|
See [GCS Object ACL documentation](https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls) for more details.
|
||||||
|
Omitting the field is the same as providing an empty list.
|
||||||
|
|
||||||
## Attributes Reference
|
## Attributes Reference
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user