mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-03 01:01:06 +00:00
Add google_storage_default_object_acl resource (#992)
* Storage Default Object ACL resource * Fixed the doc * Renamed the resource id. Log change * Complying with go vet * Changes for review * link to default object acl docs in sidebar
This commit is contained in:
parent
e4ae7bdc19
commit
9f21b56fe5
@ -192,6 +192,7 @@ func Provider() terraform.ResourceProvider {
|
||||
"google_storage_bucket_iam_member": ResourceIamMember(IamStorageBucketSchema, NewStorageBucketIamUpdater),
|
||||
"google_storage_bucket_object": resourceStorageBucketObject(),
|
||||
"google_storage_object_acl": resourceStorageObjectAcl(),
|
||||
"google_storage_default_object_acl": resourceStorageDefaultObjectAcl(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
|
185
google/resource_storage_default_object_acl.go
Normal file
185
google/resource_storage_default_object_acl.go
Normal file
@ -0,0 +1,185 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/storage/v1"
|
||||
)
|
||||
|
||||
func resourceStorageDefaultObjectAcl() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceStorageDefaultObjectAclCreate,
|
||||
Read: resourceStorageDefaultObjectAclRead,
|
||||
Update: resourceStorageDefaultObjectAclUpdate,
|
||||
Delete: resourceStorageDefaultObjectAclDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"bucket": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"role_entity": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Required: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
MinItems: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceStorageDefaultObjectAclCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
bucket := d.Get("bucket").(string)
|
||||
roleEntity := d.Get("role_entity").([]interface{})
|
||||
|
||||
for _, v := range roleEntity {
|
||||
pair, err := getRoleEntityPair(v.(string))
|
||||
|
||||
ObjectAccessControl := &storage.ObjectAccessControl{
|
||||
Role: pair.Role,
|
||||
Entity: pair.Entity,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG]: setting role = %s, entity = %s on bucket %s", pair.Role, pair.Entity, bucket)
|
||||
|
||||
_, err = config.clientStorage.DefaultObjectAccessControls.Insert(bucket, ObjectAccessControl).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error setting Default Object ACL for %s on bucket %s: %v", pair.Entity, bucket, err)
|
||||
}
|
||||
}
|
||||
d.SetId(bucket)
|
||||
return resourceStorageDefaultObjectAclRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceStorageDefaultObjectAclRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
bucket := d.Get("bucket").(string)
|
||||
|
||||
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 {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Storage Default Object ACL for bucket %q", d.Get("bucket").(string)))
|
||||
}
|
||||
|
||||
for _, v := range res.Items {
|
||||
role := v.Role
|
||||
entity := v.Entity
|
||||
// We only store updates to the locally defined access controls
|
||||
if _, in := reLocalMap[entity]; in {
|
||||
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)
|
||||
|
||||
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 {
|
||||
config := meta.(*Config)
|
||||
|
||||
bucket := d.Get("bucket").(string)
|
||||
|
||||
reLocal := d.Get("role_entity").([]interface{})
|
||||
for _, v := range reLocal {
|
||||
res, err := getRoleEntityPair(v.(string))
|
||||
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
|
||||
}
|
187
google/resource_storage_default_object_acl_test.go
Normal file
187
google/resource_storage_default_object_acl_test.go
Normal file
@ -0,0 +1,187 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccGoogleStorageDefaultObjectAcl_basic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
bucketName := testBucketName()
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccGoogleStorageDefaultObjectAclDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testGoogleStorageDefaultObjectsAclBasic(bucketName, roleEntityBasic1, roleEntityBasic2),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic1),
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic2),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccGoogleStorageDefaultObjectAcl_upgrade(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
bucketName := testBucketName()
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccGoogleStorageDefaultObjectAclDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testGoogleStorageDefaultObjectsAclBasic(bucketName, roleEntityBasic1, roleEntityBasic2),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic1),
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic2),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testGoogleStorageDefaultObjectsAclBasic(bucketName, roleEntityBasic2, roleEntityBasic3_owner),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic2),
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic3_owner),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testGoogleStorageDefaultObjectsAclBasicDelete(bucketName, roleEntityBasic1),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic1),
|
||||
testAccCheckGoogleStorageDefaultObjectAclDelete(bucketName, roleEntityBasic2),
|
||||
testAccCheckGoogleStorageDefaultObjectAclDelete(bucketName, roleEntityBasic3_reader),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccGoogleStorageDefaultObjectAcl_downgrade(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
bucketName := testBucketName()
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccGoogleStorageDefaultObjectAclDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testGoogleStorageDefaultObjectsAclBasic(bucketName, roleEntityBasic2, roleEntityBasic3_owner),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic2),
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic3_owner),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testGoogleStorageDefaultObjectsAclBasic(bucketName, roleEntityBasic2, roleEntityBasic3_reader),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic2),
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic3_reader),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testGoogleStorageDefaultObjectsAclBasicDelete(bucketName, roleEntityBasic1),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleStorageDefaultObjectAcl(bucketName, roleEntityBasic1),
|
||||
testAccCheckGoogleStorageDefaultObjectAclDelete(bucketName, roleEntityBasic2),
|
||||
testAccCheckGoogleStorageDefaultObjectAclDelete(bucketName, roleEntityBasic3_reader),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckGoogleStorageDefaultObjectAcl(bucket, roleEntityS string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
roleEntity, _ := getRoleEntityPair(roleEntityS)
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
res, err := config.clientStorage.DefaultObjectAccessControls.Get(bucket,
|
||||
roleEntity.Entity).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error retrieving contents of storage default Acl for bucket %s: %s", bucket, err)
|
||||
}
|
||||
|
||||
if res.Role != roleEntity.Role {
|
||||
return fmt.Errorf("Error, Role mismatch %s != %s", res.Role, roleEntity.Role)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccGoogleStorageDefaultObjectAclDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
|
||||
if rs.Type != "google_storage_default_object_acl" {
|
||||
continue
|
||||
}
|
||||
|
||||
bucket := rs.Primary.Attributes["bucket"]
|
||||
|
||||
_, err := config.clientStorage.DefaultObjectAccessControls.List(bucket).Do()
|
||||
if err == nil {
|
||||
return fmt.Errorf("Default Storage Object Acl for bucket %s still exists", bucket)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckGoogleStorageDefaultObjectAclDelete(bucket, roleEntityS string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
roleEntity, _ := getRoleEntityPair(roleEntityS)
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
_, err := config.clientStorage.DefaultObjectAccessControls.Get(bucket, roleEntity.Entity).Do()
|
||||
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error, Object Default Acl Entity still exists %s for bucket %s",
|
||||
roleEntity.Entity, bucket)
|
||||
}
|
||||
}
|
||||
|
||||
func testGoogleStorageDefaultObjectsAclBasicDelete(bucketName, roleEntity 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"]
|
||||
}
|
||||
`, bucketName, roleEntity)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
43
website/docs/r/storage_default_object_acl.html.markdown
Normal file
43
website/docs/r/storage_default_object_acl.html.markdown
Normal file
@ -0,0 +1,43 @@
|
||||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_storage_default_object_acl"
|
||||
sidebar_current: "docs-google-storage-default-object-acl"
|
||||
description: |-
|
||||
Creates a new default object ACL in Google Cloud Storage.
|
||||
---
|
||||
|
||||
# google\_storage\_default\_object\_acl
|
||||
|
||||
Creates a new default object ACL in Google Cloud Storage service (GCS). For more information see
|
||||
[the official documentation](https://cloud.google.com/storage/docs/access-control/lists)
|
||||
and
|
||||
[API](https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls).
|
||||
|
||||
## Example Usage
|
||||
|
||||
Example creating a default object ACL on a bucket with one owner, and one reader.
|
||||
|
||||
```hcl
|
||||
resource "google_storage_bucket" "image-store" {
|
||||
name = "image-store-bucket"
|
||||
location = "EU"
|
||||
}
|
||||
|
||||
resource "google_storage_default_object_acl" "image-store-default-acl" {
|
||||
bucket = "${google_storage_bucket.image-store.name}"
|
||||
role_entity = [
|
||||
"OWNER:user-my.email@gmail.com",
|
||||
"READER:group-mygroup",
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
* `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.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
Only the arguments listed above are exposed as attributes.
|
@ -522,6 +522,10 @@
|
||||
<a href="/docs/providers/google/r/storage_bucket_object.html">google_storage_bucket_object</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-storage-default-object-acl") %>>
|
||||
<a href="/docs/providers/google/r/storage_default_object_acl.html">google_storage_default_object_acl</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-storage-object-acl") %>>
|
||||
<a href="/docs/providers/google/r/storage_object_acl.html">google_storage_object_acl</a>
|
||||
</li>
|
||||
|
Loading…
Reference in New Issue
Block a user