Add support for google_storage_object_access_control (#2256)

This commit is contained in:
The Magician 2018-10-17 15:38:59 -07:00 committed by Nathan McKinley
parent 955b25a8e5
commit 4c20b7eeac
6 changed files with 634 additions and 0 deletions

View File

@ -106,6 +106,7 @@ func Provider() terraform.ResourceProvider {
GeneratedFilestoreResourcesMap,
GeneratedRedisResourcesMap,
GeneratedResourceManagerResourcesMap,
GeneratedStorageResourcesMap,
GeneratedMonitoringResourcesMap,
map[string]*schema.Resource{
"google_app_engine_application": resourceAppEngineApplication(),

View File

@ -0,0 +1,21 @@
// ----------------------------------------------------------------------------
//
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
//
// ----------------------------------------------------------------------------
//
// This file is automatically generated by Magic Modules and manual
// changes will be clobbered when the file is regenerated.
//
// Please read more about how to change this file in
// .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------
package google
import "github.com/hashicorp/terraform/helper/schema"
var GeneratedStorageResourcesMap = map[string]*schema.Resource{
"google_storage_object_access_control": resourceStorageObjectAccessControl(),
}

View File

@ -0,0 +1,125 @@
package google
import (
"fmt"
"io/ioutil"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccStorageObjectAccessControl_basic(t *testing.T) {
t.Parallel()
bucketName := testBucketName()
objectName := testAclObjectName()
objectData := []byte("data data data")
ioutil.WriteFile(tfObjectAcl.Name(), objectData, 0644)
resource.Test(t, resource.TestCase{
PreCheck: func() {
if errObjectAcl != nil {
panic(errObjectAcl)
}
testAccPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testAccStorageObjectAccessControlDestroy,
Steps: []resource.TestStep{
{
Config: testGoogleStorageObjectAccessControlBasic(bucketName, objectName, "READER", "allUsers"),
},
{
ResourceName: "google_storage_object_access_control.default",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccStorageObjectAccessControl_update(t *testing.T) {
t.Parallel()
bucketName := testBucketName()
objectName := testAclObjectName()
objectData := []byte("data data data")
ioutil.WriteFile(tfObjectAcl.Name(), objectData, 0644)
resource.Test(t, resource.TestCase{
PreCheck: func() {
if errObjectAcl != nil {
panic(errObjectAcl)
}
testAccPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testAccStorageObjectAccessControlDestroy,
Steps: []resource.TestStep{
{
Config: testGoogleStorageObjectAccessControlBasic(bucketName, objectName, "READER", "allUsers"),
},
{
ResourceName: "google_storage_object_access_control.default",
ImportState: true,
ImportStateVerify: true,
},
{
Config: testGoogleStorageObjectAccessControlBasic(bucketName, objectName, "OWNER", "allUsers"),
},
{
ResourceName: "google_storage_object_access_control.default",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccStorageObjectAccessControlDestroy(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"]
object := rs.Primary.Attributes["object"]
entity := rs.Primary.Attributes["entity"]
rePairs, err := config.clientStorage.ObjectAccessControls.List(bucket, object).Do()
if err != nil {
return fmt.Errorf("Can't list role entity acl for object %s in bucket %s", object, bucket)
}
for _, v := range rePairs.Items {
if v.Entity == entity {
return fmt.Errorf("found entity %s as role entity acl entry for object %s in bucket %s", entity, object, bucket)
}
}
}
return nil
}
func testGoogleStorageObjectAccessControlBasic(bucketName, objectName, role, entity string) string {
return fmt.Sprintf(`
resource "google_storage_bucket" "bucket" {
name = "%s"
}
resource "google_storage_bucket_object" "object" {
name = "%s"
bucket = "${google_storage_bucket.bucket.name}"
source = "%s"
}
resource "google_storage_object_access_control" "default" {
object = "${google_storage_bucket_object.object.name}"
bucket = "${google_storage_bucket.bucket.name}"
role = "%s"
entity = "%s"
}
`, bucketName, objectName, tfObjectAcl.Name(), role, entity)
}

View File

@ -0,0 +1,343 @@
// ----------------------------------------------------------------------------
//
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
//
// ----------------------------------------------------------------------------
//
// This file is automatically generated by Magic Modules and manual
// changes will be clobbered when the file is regenerated.
//
// Please read more about how to change this file in
// .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------
package google
import (
"fmt"
"log"
"reflect"
"strconv"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)
func resourceStorageObjectAccessControl() *schema.Resource {
return &schema.Resource{
Create: resourceStorageObjectAccessControlCreate,
Read: resourceStorageObjectAccessControlRead,
Update: resourceStorageObjectAccessControlUpdate,
Delete: resourceStorageObjectAccessControlDelete,
Importer: &schema.ResourceImporter{
State: resourceStorageObjectAccessControlImport,
},
Schema: map[string]*schema.Schema{
"bucket": {
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: compareSelfLinkOrResourceName,
},
"entity": {
Type: schema.TypeString,
Required: true,
},
"object": {
Type: schema.TypeString,
Required: true,
},
"role": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"OWNER", "READER"}, false),
},
"domain": {
Type: schema.TypeString,
Computed: true,
},
"email": {
Type: schema.TypeString,
Computed: true,
},
"entity_id": {
Type: schema.TypeString,
Computed: true,
},
"generation": {
Type: schema.TypeInt,
Computed: true,
},
"project_team": {
Type: schema.TypeList,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"project_number": {
Type: schema.TypeString,
Optional: true,
},
"team": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"editors", "owners", "viewers", ""}, false),
},
},
},
},
},
}
}
func resourceStorageObjectAccessControlCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
obj := make(map[string]interface{})
bucketProp, err := expandStorageObjectAccessControlBucket(d.Get("bucket"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("bucket"); !isEmptyValue(reflect.ValueOf(bucketProp)) && (ok || !reflect.DeepEqual(v, bucketProp)) {
obj["bucket"] = bucketProp
}
entityProp, err := expandStorageObjectAccessControlEntity(d.Get("entity"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("entity"); !isEmptyValue(reflect.ValueOf(entityProp)) && (ok || !reflect.DeepEqual(v, entityProp)) {
obj["entity"] = entityProp
}
objectProp, err := expandStorageObjectAccessControlObject(d.Get("object"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("object"); !isEmptyValue(reflect.ValueOf(objectProp)) && (ok || !reflect.DeepEqual(v, objectProp)) {
obj["object"] = objectProp
}
roleProp, err := expandStorageObjectAccessControlRole(d.Get("role"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("role"); !isEmptyValue(reflect.ValueOf(roleProp)) && (ok || !reflect.DeepEqual(v, roleProp)) {
obj["role"] = roleProp
}
url, err := replaceVars(d, config, "https://www.googleapis.com/storage/v1/b/{{bucket}}/o/{{object}}/acl")
if err != nil {
return err
}
log.Printf("[DEBUG] Creating new ObjectAccessControl: %#v", obj)
res, err := sendRequest(config, "POST", url, obj)
if err != nil {
return fmt.Errorf("Error creating ObjectAccessControl: %s", err)
}
// Store the ID now
id, err := replaceVars(d, config, "{{bucket}}/{{object}}/{{entity}}")
if err != nil {
return fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)
log.Printf("[DEBUG] Finished creating ObjectAccessControl %q: %#v", d.Id(), res)
return resourceStorageObjectAccessControlRead(d, meta)
}
func resourceStorageObjectAccessControlRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
url, err := replaceVars(d, config, "https://www.googleapis.com/storage/v1/b/{{bucket}}/o/{{object}}/acl/{{entity}}")
if err != nil {
return err
}
res, err := sendRequest(config, "GET", url, nil)
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("StorageObjectAccessControl %q", d.Id()))
}
if err := d.Set("bucket", flattenStorageObjectAccessControlBucket(res["bucket"])); err != nil {
return fmt.Errorf("Error reading ObjectAccessControl: %s", err)
}
if err := d.Set("domain", flattenStorageObjectAccessControlDomain(res["domain"])); err != nil {
return fmt.Errorf("Error reading ObjectAccessControl: %s", err)
}
if err := d.Set("email", flattenStorageObjectAccessControlEmail(res["email"])); err != nil {
return fmt.Errorf("Error reading ObjectAccessControl: %s", err)
}
if err := d.Set("entity", flattenStorageObjectAccessControlEntity(res["entity"])); err != nil {
return fmt.Errorf("Error reading ObjectAccessControl: %s", err)
}
if err := d.Set("entity_id", flattenStorageObjectAccessControlEntityId(res["entityId"])); err != nil {
return fmt.Errorf("Error reading ObjectAccessControl: %s", err)
}
if err := d.Set("generation", flattenStorageObjectAccessControlGeneration(res["generation"])); err != nil {
return fmt.Errorf("Error reading ObjectAccessControl: %s", err)
}
if err := d.Set("object", flattenStorageObjectAccessControlObject(res["object"])); err != nil {
return fmt.Errorf("Error reading ObjectAccessControl: %s", err)
}
if err := d.Set("project_team", flattenStorageObjectAccessControlProjectTeam(res["projectTeam"])); err != nil {
return fmt.Errorf("Error reading ObjectAccessControl: %s", err)
}
if err := d.Set("role", flattenStorageObjectAccessControlRole(res["role"])); err != nil {
return fmt.Errorf("Error reading ObjectAccessControl: %s", err)
}
return nil
}
func resourceStorageObjectAccessControlUpdate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
obj := make(map[string]interface{})
bucketProp, err := expandStorageObjectAccessControlBucket(d.Get("bucket"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("bucket"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, bucketProp)) {
obj["bucket"] = bucketProp
}
entityProp, err := expandStorageObjectAccessControlEntity(d.Get("entity"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("entity"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, entityProp)) {
obj["entity"] = entityProp
}
objectProp, err := expandStorageObjectAccessControlObject(d.Get("object"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("object"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, objectProp)) {
obj["object"] = objectProp
}
roleProp, err := expandStorageObjectAccessControlRole(d.Get("role"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("role"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, roleProp)) {
obj["role"] = roleProp
}
url, err := replaceVars(d, config, "https://www.googleapis.com/storage/v1/b/{{bucket}}/o/{{object}}/acl/{{entity}}")
if err != nil {
return err
}
log.Printf("[DEBUG] Updating ObjectAccessControl %q: %#v", d.Id(), obj)
_, err = sendRequest(config, "PUT", url, obj)
if err != nil {
return fmt.Errorf("Error updating ObjectAccessControl %q: %s", d.Id(), err)
}
return resourceStorageObjectAccessControlRead(d, meta)
}
func resourceStorageObjectAccessControlDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
url, err := replaceVars(d, config, "https://www.googleapis.com/storage/v1/b/{{bucket}}/o/{{object}}/acl/{{entity}}")
if err != nil {
return err
}
var obj map[string]interface{}
log.Printf("[DEBUG] Deleting ObjectAccessControl %q", d.Id())
res, err := sendRequest(config, "DELETE", url, obj)
if err != nil {
return handleNotFoundError(err, d, "ObjectAccessControl")
}
log.Printf("[DEBUG] Finished deleting ObjectAccessControl %q: %#v", d.Id(), res)
return nil
}
func resourceStorageObjectAccessControlImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
config := meta.(*Config)
parseImportId([]string{"(?P<bucket>[^/]+)/(?P<object>[^/]+)/(?P<entity>[^/]+)"}, d, config)
// Replace import id for the resource id
id, err := replaceVars(d, config, "{{bucket}}/{{object}}/{{entity}}")
if err != nil {
return nil, fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)
return []*schema.ResourceData{d}, nil
}
func flattenStorageObjectAccessControlBucket(v interface{}) interface{} {
if v == nil {
return v
}
return ConvertSelfLinkToV1(v.(string))
}
func flattenStorageObjectAccessControlDomain(v interface{}) interface{} {
return v
}
func flattenStorageObjectAccessControlEmail(v interface{}) interface{} {
return v
}
func flattenStorageObjectAccessControlEntity(v interface{}) interface{} {
return v
}
func flattenStorageObjectAccessControlEntityId(v interface{}) interface{} {
return v
}
func flattenStorageObjectAccessControlGeneration(v interface{}) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil {
return intVal
} // let terraform core handle it if we can't convert the string to an int.
}
return v
}
func flattenStorageObjectAccessControlObject(v interface{}) interface{} {
return v
}
func flattenStorageObjectAccessControlProjectTeam(v interface{}) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
transformed := make(map[string]interface{})
transformed["project_number"] =
flattenStorageObjectAccessControlProjectTeamProjectNumber(original["projectNumber"])
transformed["team"] =
flattenStorageObjectAccessControlProjectTeamTeam(original["team"])
return []interface{}{transformed}
}
func flattenStorageObjectAccessControlProjectTeamProjectNumber(v interface{}) interface{} {
return v
}
func flattenStorageObjectAccessControlProjectTeamTeam(v interface{}) interface{} {
return v
}
func flattenStorageObjectAccessControlRole(v interface{}) interface{} {
return v
}
func expandStorageObjectAccessControlBucket(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandStorageObjectAccessControlEntity(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandStorageObjectAccessControlObject(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandStorageObjectAccessControlRole(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}

View File

@ -62,6 +62,12 @@ func sendRequest(config *Config, method, rawurl string, body map[string]interfac
return nil, err
}
// 204 responses will have no body, so we're going to error with "EOF" if we
// try to parse it. Instead, we can just return nil.
if res.StatusCode == 204 {
return nil, nil
}
result := make(map[string]interface{})
if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
return nil, err

View File

@ -0,0 +1,138 @@
---
# ----------------------------------------------------------------------------
#
# *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
#
# ----------------------------------------------------------------------------
#
# This file is automatically generated by Magic Modules and manual
# changes will be clobbered when the file is regenerated.
#
# Please read more about how to change this file in
# .github/CONTRIBUTING.md.
#
# ----------------------------------------------------------------------------
layout: "google"
page_title: "Google: google_storage_object_access_control"
sidebar_current: "docs-google-storage-object-access-control"
description: |-
The ObjectAccessControls resources represent the Access Control Lists
(ACLs) for objects within Google Cloud Storage.
---
# google\_storage\_object\_access\_control
The ObjectAccessControls resources represent the Access Control Lists
(ACLs) for objects within Google Cloud Storage. ACLs let you specify
who has access to your data and to what extent.
There are two roles that can be assigned to an entity:
READERs can get an object, though the acl property will not be revealed.
OWNERs are READERs, and they can get the acl property, update an object,
and call all objectAccessControls methods on the object. The owner of an
object is always an OWNER.
For more information, see Access Control, with the caveat that this API
uses READER and OWNER instead of READ and FULL_CONTROL.
To get more information about ObjectAccessControl, see:
* [API documentation](https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls)
* How-to Guides
* [Official Documentation](https://cloud.google.com/storage/docs/access-control/create-manage-lists)
## Example Usage
```hcl
resource "google_storage_object_access_control" "public_rule" {
object = "${google_storage_bucket_object.object.name}"
bucket = "${google_storage_bucket.bucket.name}"
role = "READER"
entity = "allUsers"
}
resource "google_storage_bucket" "bucket" {
name = "static-content-bucket"
}
resource "google_storage_bucket_object" "object" {
name = "public-object"
bucket = "${google_storage_bucket.bucket.name}"
source = "../static/img/header-logo.jpg"
}
```
## Argument Reference
The following arguments are supported:
* `bucket` -
(Required)
The name of the bucket.
* `entity` -
(Required)
The entity holding the permission, in one of the following forms:
* user-{{userId}}
* user-{{email}} (such as "user-liz@example.com")
* group-{{groupId}}
* group-{{email}} (such as "group-example@googlegroups.com")
* domain-{{domain}} (such as "domain-example.com")
* project-team-{{projectId}}
* allUsers
* allAuthenticatedUsers
* `object` -
(Required)
The name of the object to apply the access control to.
* `role` -
(Required)
The access permission for the entity.
- - -
## Attributes Reference
In addition to the arguments listed above, the following computed attributes are exported:
* `domain` -
The domain associated with the entity.
* `email` -
The email address associated with the entity.
* `entity_id` -
The ID for the entity
* `generation` -
The content generation of the object, if applied to an object.
* `project_team` -
The project team associated with the entity Structure is documented below.
The `project_team` block contains:
* `project_number` -
(Optional)
The project team associated with the entity
* `team` -
(Optional)
The team.
## Import
ObjectAccessControl can be imported using any of these accepted formats:
```
$ terraform import google_storage_object_access_control.default {{bucket}}/{{object}}/{{entity}}
```