diff --git a/google/iam_binary_authorization_attestor.go b/google/iam_binary_authorization_attestor.go index d2c582b0dda..fdec67b1e66 100644 --- a/google/iam_binary_authorization_attestor.go +++ b/google/iam_binary_authorization_attestor.go @@ -146,7 +146,6 @@ func (u *BinaryAuthorizationAttestorIamUpdater) SetResourceIamPolicy(policy *clo if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_cloud_functions_cloud_function.go b/google/iam_cloud_functions_cloud_function.go index 991b405f08f..fd55e349d62 100644 --- a/google/iam_cloud_functions_cloud_function.go +++ b/google/iam_cloud_functions_cloud_function.go @@ -166,7 +166,6 @@ func (u *CloudFunctionsCloudFunctionIamUpdater) SetResourceIamPolicy(policy *clo if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_cloud_run_service.go b/google/iam_cloud_run_service.go index cc3ece339be..1ef65a411d7 100644 --- a/google/iam_cloud_run_service.go +++ b/google/iam_cloud_run_service.go @@ -166,7 +166,6 @@ func (u *CloudRunServiceIamUpdater) SetResourceIamPolicy(policy *cloudresourcema if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_compute_instance.go b/google/iam_compute_instance.go index cdd6419033c..fe4c4faa369 100644 --- a/google/iam_compute_instance.go +++ b/google/iam_compute_instance.go @@ -166,7 +166,6 @@ func (u *ComputeInstanceIamUpdater) SetResourceIamPolicy(policy *cloudresourcema if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_compute_subnetwork.go b/google/iam_compute_subnetwork.go index 7f4e8498b0d..5381f3b4f27 100644 --- a/google/iam_compute_subnetwork.go +++ b/google/iam_compute_subnetwork.go @@ -166,7 +166,6 @@ func (u *ComputeSubnetworkIamUpdater) SetResourceIamPolicy(policy *cloudresource if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_iap_app_engine_service.go b/google/iam_iap_app_engine_service.go index 2f6f06767b7..81eb3012c11 100644 --- a/google/iam_iap_app_engine_service.go +++ b/google/iam_iap_app_engine_service.go @@ -159,7 +159,6 @@ func (u *IapAppEngineServiceIamUpdater) SetResourceIamPolicy(policy *cloudresour if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_iap_app_engine_version.go b/google/iam_iap_app_engine_version.go index 87bc07d075a..aeaf0a90a68 100644 --- a/google/iam_iap_app_engine_version.go +++ b/google/iam_iap_app_engine_version.go @@ -172,7 +172,6 @@ func (u *IapAppEngineVersionIamUpdater) SetResourceIamPolicy(policy *cloudresour if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_iap_web.go b/google/iam_iap_web.go index ba81e4e8d73..0623948793b 100644 --- a/google/iam_iap_web.go +++ b/google/iam_iap_web.go @@ -134,7 +134,6 @@ func (u *IapWebIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Pol if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_iap_web_backend_service.go b/google/iam_iap_web_backend_service.go index 6d4335460ed..aa0b115ddf8 100644 --- a/google/iam_iap_web_backend_service.go +++ b/google/iam_iap_web_backend_service.go @@ -146,7 +146,6 @@ func (u *IapWebBackendServiceIamUpdater) SetResourceIamPolicy(policy *cloudresou if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_iap_web_type_app_engine.go b/google/iam_iap_web_type_app_engine.go index f54a9e67084..7fafebb795f 100644 --- a/google/iam_iap_web_type_app_engine.go +++ b/google/iam_iap_web_type_app_engine.go @@ -160,7 +160,6 @@ func (u *IapWebTypeAppEngineIamUpdater) SetResourceIamPolicy(policy *cloudresour if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_iap_web_type_compute.go b/google/iam_iap_web_type_compute.go index 9b5c667d178..a51f329072b 100644 --- a/google/iam_iap_web_type_compute.go +++ b/google/iam_iap_web_type_compute.go @@ -134,7 +134,6 @@ func (u *IapWebTypeComputeIamUpdater) SetResourceIamPolicy(policy *cloudresource if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_pubsub_topic.go b/google/iam_pubsub_topic.go index c50de29addb..bb1ba2c524a 100644 --- a/google/iam_pubsub_topic.go +++ b/google/iam_pubsub_topic.go @@ -146,7 +146,6 @@ func (u *PubsubTopicIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanage if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_runtime_config_config.go b/google/iam_runtime_config_config.go index fa3b326fcd5..f75c61dffab 100644 --- a/google/iam_runtime_config_config.go +++ b/google/iam_runtime_config_config.go @@ -146,7 +146,6 @@ func (u *RuntimeConfigConfigIamUpdater) SetResourceIamPolicy(policy *cloudresour if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_source_repo_repository.go b/google/iam_source_repo_repository.go index ade79acbc8f..0796b037e1f 100644 --- a/google/iam_source_repo_repository.go +++ b/google/iam_source_repo_repository.go @@ -146,7 +146,6 @@ func (u *SourceRepoRepositoryIamUpdater) SetResourceIamPolicy(policy *cloudresou if err != nil { return err } - project, err := getProject(u.d, u.Config) if err != nil { return err diff --git a/google/iam_storage_bucket.go b/google/iam_storage_bucket.go index 22aae1157b3..2fa2a97ebb6 100644 --- a/google/iam_storage_bucket.go +++ b/google/iam_storage_bucket.go @@ -1,68 +1,127 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "google.golang.org/api/cloudresourcemanager/v1" - "google.golang.org/api/storage/v1" ) -var IamStorageBucketSchema = map[string]*schema.Schema{ +var StorageBucketIamSchema = map[string]*schema.Schema{ "bucket": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, }, } -func StorageBucketIdParseFunc(d *schema.ResourceData, _ *Config) error { - d.Set("bucket", d.Id()) - return nil -} - type StorageBucketIamUpdater struct { bucket string + d *schema.ResourceData Config *Config } -func NewStorageBucketIamUpdater(d *schema.ResourceData, config *Config) (ResourceIamUpdater, error) { - bucket := d.Get("bucket").(string) +func StorageBucketIamUpdaterProducer(d *schema.ResourceData, config *Config) (ResourceIamUpdater, error) { + values := make(map[string]string) - return &StorageBucketIamUpdater{ - bucket: bucket, + if v, ok := d.GetOk("bucket"); ok { + values["bucket"] = v.(string) + } + + // We may have gotten either a long or short name, so attempt to parse long name if possible + m, err := getImportIdQualifiers([]string{"b/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Get("bucket").(string)) + if err != nil { + return nil, err + } + + for k, v := range m { + values[k] = v + } + + u := &StorageBucketIamUpdater{ + bucket: values["bucket"], + d: d, Config: config, - }, nil + } + + d.Set("bucket", u.GetResourceId()) + + return u, nil +} + +func StorageBucketIdParseFunc(d *schema.ResourceData, config *Config) error { + values := make(map[string]string) + + m, err := getImportIdQualifiers([]string{"b/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Id()) + if err != nil { + return err + } + + for k, v := range m { + values[k] = v + } + + u := &StorageBucketIamUpdater{ + bucket: values["bucket"], + d: d, + Config: config, + } + d.Set("bucket", u.GetResourceId()) + d.SetId(u.GetResourceId()) + return nil } func (u *StorageBucketIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { - p, err := u.Config.clientStorage.Buckets.GetIamPolicy(u.bucket).Do() + url, err := u.qualifyBucketUrl("iam") + if err != nil { + return nil, err + } + + var obj map[string]interface{} + + policy, err := sendRequest(u.Config, "GET", "", url, obj) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) } - cloudResourcePolicy, err := storageToResourceManagerPolicy(p) + out := &cloudresourcemanager.Policy{} + err = Convert(policy, out) if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err) + return nil, errwrap.Wrapf("Cannot convert a policy to a resource manager policy: {{err}}", err) } - return cloudResourcePolicy, nil + return out, nil } func (u *StorageBucketIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { - storagePolicy, err := resourceManagerToStoragePolicy(policy) - + json, err := ConvertToMap(policy) if err != nil { - return errwrap.Wrapf(fmt.Sprintf("Invalid IAM policy for %s: {{err}}", u.DescribeResource()), err) + return err } - ppolicy, err := u.Config.clientStorage.Buckets.GetIamPolicy(u.bucket).Do() + obj := json + + url, err := u.qualifyBucketUrl("iam") if err != nil { - return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) + return err } - storagePolicy.Etag = ppolicy.Etag - _, err = u.Config.clientStorage.Buckets.SetIamPolicy(u.bucket, storagePolicy).Do() + _, err = sendRequestWithTimeout(u.Config, "PUT", "", url, obj, u.d.Timeout(schema.TimeoutCreate)) if err != nil { return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) } @@ -70,32 +129,23 @@ func (u *StorageBucketIamUpdater) SetResourceIamPolicy(policy *cloudresourcemana return nil } +func (u *StorageBucketIamUpdater) qualifyBucketUrl(methodIdentifier string) (string, error) { + urlTemplate := fmt.Sprintf("{{StorageBasePath}}%s/%s", fmt.Sprintf("b/%s", u.bucket), methodIdentifier) + url, err := replaceVars(u.d, u.Config, urlTemplate) + if err != nil { + return "", err + } + return url, nil +} + func (u *StorageBucketIamUpdater) GetResourceId() string { - return u.bucket + return fmt.Sprintf("b/%s", u.bucket) } func (u *StorageBucketIamUpdater) GetMutexKey() string { - return fmt.Sprintf("iam-storage-bucket-%s", u.bucket) + return fmt.Sprintf("iam-storage-bucket-%s", u.GetResourceId()) } func (u *StorageBucketIamUpdater) DescribeResource() string { - return fmt.Sprintf("Storage Bucket %q", u.bucket) -} - -func resourceManagerToStoragePolicy(p *cloudresourcemanager.Policy) (*storage.Policy, error) { - out := &storage.Policy{} - err := Convert(p, out) - if err != nil { - return nil, errwrap.Wrapf("Cannot convert a v1 policy to a storage policy: {{err}}", err) - } - return out, nil -} - -func storageToResourceManagerPolicy(p *storage.Policy) (*cloudresourcemanager.Policy, error) { - out := &cloudresourcemanager.Policy{} - err := Convert(p, out) - if err != nil { - return nil, errwrap.Wrapf("Cannot convert a storage policy to a v1 policy: {{err}}", err) - } - return out, nil + return fmt.Sprintf("storage bucket %q", u.GetResourceId()) } diff --git a/google/iam_storage_bucket_generated_test.go b/google/iam_storage_bucket_generated_test.go new file mode 100644 index 00000000000..004c01b251a --- /dev/null +++ b/google/iam_storage_bucket_generated_test.go @@ -0,0 +1,183 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccStorageBucketIamBindingGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/storage.objectViewer", + "admin_role": "roles/storage.admin", + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccStorageBucketIamBinding_basicGenerated(context), + }, + { + ResourceName: "google_storage_bucket_iam_binding.foo", + ImportStateId: fmt.Sprintf("b/%s roles/storage.objectViewer", fmt.Sprintf("my-bucket%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Iam Binding update + Config: testAccStorageBucketIamBinding_updateGenerated(context), + }, + { + ResourceName: "google_storage_bucket_iam_binding.foo", + ImportStateId: fmt.Sprintf("b/%s roles/storage.objectViewer", fmt.Sprintf("my-bucket%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccStorageBucketIamMemberGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/storage.objectViewer", + "admin_role": "roles/storage.admin", + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + // Test Iam Member creation (no update for member, no need to test) + Config: testAccStorageBucketIamMember_basicGenerated(context), + }, + { + ResourceName: "google_storage_bucket_iam_member.foo", + ImportStateId: fmt.Sprintf("b/%s roles/storage.objectViewer user:admin@hashicorptest.com", fmt.Sprintf("my-bucket%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccStorageBucketIamPolicyGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + "role": "roles/storage.objectViewer", + "admin_role": "roles/storage.admin", + } + context["service_account"] = getTestServiceAccountFromEnv(t) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccStorageBucketIamPolicy_basicGenerated(context), + }, + { + ResourceName: "google_storage_bucket_iam_policy.foo", + ImportStateId: fmt.Sprintf("b/%s", fmt.Sprintf("my-bucket%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccStorageBucketIamMember_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "default" { + name = "my-bucket%{random_suffix}" + bucket_policy_only = true +} + +resource "google_storage_bucket_iam_member" "foo" { + bucket = "${google_storage_bucket.default.name}" + role = "%{role}" + member = "user:admin@hashicorptest.com" +} +`, context) +} + +func testAccStorageBucketIamPolicy_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "default" { + name = "my-bucket%{random_suffix}" + bucket_policy_only = true +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + } + binding { + role = "%{admin_role}" + members = ["serviceAccount:%{service_account}"] + } +} + +resource "google_storage_bucket_iam_policy" "foo" { + bucket = "${google_storage_bucket.default.name}" + policy_data = "${data.google_iam_policy.foo.policy_data}" +} +`, context) +} + +func testAccStorageBucketIamBinding_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "default" { + name = "my-bucket%{random_suffix}" + bucket_policy_only = true +} + +resource "google_storage_bucket_iam_binding" "foo" { + bucket = "${google_storage_bucket.default.name}" + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} +`, context) +} + +func testAccStorageBucketIamBinding_updateGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "default" { + name = "my-bucket%{random_suffix}" + bucket_policy_only = true +} + +resource "google_storage_bucket_iam_binding" "foo" { + bucket = "${google_storage_bucket.default.name}" + role = "%{role}" + members = ["user:admin@hashicorptest.com", "user:paddy@hashicorp.com"] +} +`, context) +} diff --git a/google/provider.go b/google/provider.go index c038bc7588b..69df00416ae 100644 --- a/google/provider.go +++ b/google/provider.go @@ -469,8 +469,8 @@ func Provider() terraform.ResourceProvider { } // Generated resources: 88 -// Generated IAM resources: 42 -// Total generated resources: 130 +// Generated IAM resources: 45 +// Total generated resources: 133 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -605,6 +605,9 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_spanner_instance": resourceSpannerInstance(), "google_spanner_database": resourceSpannerDatabase(), "google_sql_database": resourceSQLDatabase(), + "google_storage_bucket_iam_binding": ResourceIamBinding(StorageBucketIamSchema, StorageBucketIamUpdaterProducer, StorageBucketIdParseFunc), + "google_storage_bucket_iam_member": ResourceIamMember(StorageBucketIamSchema, StorageBucketIamUpdaterProducer, StorageBucketIdParseFunc), + "google_storage_bucket_iam_policy": ResourceIamPolicy(StorageBucketIamSchema, StorageBucketIamUpdaterProducer, StorageBucketIdParseFunc), "google_storage_bucket_access_control": resourceStorageBucketAccessControl(), "google_storage_object_access_control": resourceStorageObjectAccessControl(), "google_storage_default_object_access_control": resourceStorageDefaultObjectAccessControl(), @@ -709,17 +712,11 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_service_account_key": resourceGoogleServiceAccountKey(), "google_storage_bucket": resourceStorageBucket(), "google_storage_bucket_acl": resourceStorageBucketAcl(), - // Legacy roles such as roles/storage.legacyBucketReader are automatically added - // when creating a bucket. For this reason, it is better not to add the authoritative - // google_storage_bucket_iam_policy resource. - "google_storage_bucket_iam_binding": ResourceIamBinding(IamStorageBucketSchema, NewStorageBucketIamUpdater, StorageBucketIdParseFunc), - "google_storage_bucket_iam_member": ResourceIamMember(IamStorageBucketSchema, NewStorageBucketIamUpdater, StorageBucketIdParseFunc), - "google_storage_bucket_iam_policy": ResourceIamPolicy(IamStorageBucketSchema, NewStorageBucketIamUpdater, StorageBucketIdParseFunc), - "google_storage_bucket_object": resourceStorageBucketObject(), - "google_storage_object_acl": resourceStorageObjectAcl(), - "google_storage_default_object_acl": resourceStorageDefaultObjectAcl(), - "google_storage_notification": resourceStorageNotification(), - "google_storage_transfer_job": resourceStorageTransferJob(), + "google_storage_bucket_object": resourceStorageBucketObject(), + "google_storage_object_acl": resourceStorageObjectAcl(), + "google_storage_default_object_acl": resourceStorageDefaultObjectAcl(), + "google_storage_notification": resourceStorageNotification(), + "google_storage_transfer_job": resourceStorageTransferJob(), }, ) } diff --git a/google/resource_iam_policy.go b/google/resource_iam_policy.go index 5d11da3aaea..c99dc4615e2 100644 --- a/google/resource_iam_policy.go +++ b/google/resource_iam_policy.go @@ -115,7 +115,11 @@ func ResourceIamPolicyDelete(newUpdaterFunc newResourceIamUpdaterFunc) schema.De } // Set an empty policy to delete the attached policy. - err = updater.SetResourceIamPolicy(&cloudresourcemanager.Policy{}) + pol := &cloudresourcemanager.Policy{} + if v, ok := d.GetOk("etag"); ok { + pol.Etag = v.(string) + } + err = updater.SetResourceIamPolicy(pol) if err != nil { return err } diff --git a/google/resource_storage_bucket_iam_test.go b/google/resource_storage_bucket_iam_test.go index 2148003a137..42753c1bfde 100644 --- a/google/resource_storage_bucket_iam_test.go +++ b/google/resource_storage_bucket_iam_test.go @@ -2,51 +2,12 @@ package google import ( "fmt" - "reflect" - "sort" "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" ) -func TestAccStorageBucketIamBinding(t *testing.T) { - t.Parallel() - - bucket := acctest.RandomWithPrefix("tf-test") - account := acctest.RandomWithPrefix("tf-test") - role := "roles/storage.objectViewer" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - // Test IAM Binding creation - Config: testAccStorageBucketIamBinding_basic(bucket, account, role), - Check: testAccCheckGoogleStorageBucketIam(bucket, role, []string{ - fmt.Sprintf("serviceAccount:%s-1@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()), - }), - }, - { - ResourceName: "google_storage_bucket_iam_binding.foo", - ImportStateId: fmt.Sprintf("%s %s", bucket, role), - ImportState: true, - ImportStateVerify: true, - }, - { - // Test IAM Binding update - Config: testAccStorageBucketIamBinding_update(bucket, account, role), - Check: testAccCheckGoogleStorageBucketIam(bucket, "roles/storage.objectViewer", []string{ - fmt.Sprintf("serviceAccount:%s-1@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()), - fmt.Sprintf("serviceAccount:%s-2@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()), - }), - }, - }, - }) -} - func TestAccStorageBucketIamPolicy(t *testing.T) { t.Parallel() @@ -61,9 +22,6 @@ func TestAccStorageBucketIamPolicy(t *testing.T) { { // Test IAM Policy creation Config: testAccStorageBucketIamPolicy_basic(bucket, account, serviceAcct), - Check: testAccCheckGoogleStorageBucketIam(bucket, "roles/storage.objectViewer", []string{ - fmt.Sprintf("serviceAccount:%s-1@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()), - }), }, { ResourceName: "google_storage_bucket_iam_policy.bucket-binding", @@ -74,35 +32,10 @@ func TestAccStorageBucketIamPolicy(t *testing.T) { { // Test IAM Policy update Config: testAccStorageBucketIamPolicy_update(bucket, account, serviceAcct), - Check: testAccCheckGoogleStorageBucketIam(bucket, "roles/storage.objectViewer", []string{ - fmt.Sprintf("serviceAccount:%s-1@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()), - fmt.Sprintf("serviceAccount:%s-2@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()), - }), - }, - }, - }) -} - -func TestAccStorageBucketIamMember(t *testing.T) { - t.Parallel() - - bucket := acctest.RandomWithPrefix("tf-test") - account := acctest.RandomWithPrefix("tf-test") - role := "roles/storage.admin" - member := fmt.Sprintf("serviceAccount:%s-1@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - // Test Iam Member creation (no update for member, no need to test) - Config: testAccStorageBucketIamMember_basic(bucket, account, role), - Check: testAccCheckGoogleStorageBucketIam(bucket, role, []string{member}), }, { - ResourceName: "google_storage_bucket_iam_member.foo", - ImportStateId: fmt.Sprintf("%s %s %s", bucket, role, member), + ResourceName: "google_storage_bucket_iam_policy.bucket-binding", + ImportStateId: bucket, ImportState: true, ImportStateVerify: true, }, @@ -110,31 +43,6 @@ func TestAccStorageBucketIamMember(t *testing.T) { }) } -func testAccCheckGoogleStorageBucketIam(bucket, role string, members []string) resource.TestCheckFunc { - return func(s *terraform.State) error { - config := testAccProvider.Meta().(*Config) - p, err := config.clientStorage.Buckets.GetIamPolicy(bucket).Do() - if err != nil { - return err - } - - for _, binding := range p.Bindings { - if binding.Role == role { - sort.Strings(members) - sort.Strings(binding.Members) - - if reflect.DeepEqual(members, binding.Members) { - return nil - } - - return fmt.Errorf("Binding found but expected members is %v, got %v", members, binding.Members) - } - } - - return fmt.Errorf("No binding for role %q", role) - } -} - func testAccStorageBucketIamPolicy_update(bucket, account, serviceAcct string) string { return fmt.Sprintf(` resource "google_storage_bucket" "bucket" { @@ -209,70 +117,3 @@ resource "google_storage_bucket_iam_policy" "bucket-binding" { } `, bucket, account, serviceAcct) } - -func testAccStorageBucketIamBinding_basic(bucket, account, role string) string { - return fmt.Sprintf(` -resource "google_storage_bucket" "bucket" { - name = "%s" -} - -resource "google_service_account" "test-account-1" { - account_id = "%s-1" - display_name = "Storage Bucket Iam Testing Account" -} - -resource "google_storage_bucket_iam_binding" "foo" { - bucket = google_storage_bucket.bucket.name - role = "%s" - members = [ - "serviceAccount:${google_service_account.test-account-1.email}", - ] -} -`, bucket, account, role) -} - -func testAccStorageBucketIamBinding_update(bucket, account, role string) string { - return fmt.Sprintf(` -resource "google_storage_bucket" "bucket" { - name = "%s" -} - -resource "google_service_account" "test-account-1" { - account_id = "%s-1" - display_name = "Storage Bucket Iam Testing Account" -} - -resource "google_service_account" "test-account-2" { - account_id = "%s-2" - display_name = "Storage Bucket Iam Testing Account" -} - -resource "google_storage_bucket_iam_binding" "foo" { - bucket = google_storage_bucket.bucket.name - role = "%s" - members = [ - "serviceAccount:${google_service_account.test-account-1.email}", - "serviceAccount:${google_service_account.test-account-2.email}", - ] -} -`, bucket, account, account, role) -} - -func testAccStorageBucketIamMember_basic(bucket, account, role string) string { - return fmt.Sprintf(` -resource "google_storage_bucket" "bucket" { - name = "%s" -} - -resource "google_service_account" "test-account-1" { - account_id = "%s-1" - display_name = "Storage Bucket Iam Testing Account" -} - -resource "google_storage_bucket_iam_member" "foo" { - bucket = google_storage_bucket.bucket.name - role = "%s" - member = "serviceAccount:${google_service_account.test-account-1.email}" -} -`, bucket, account, role) -} diff --git a/website/docs/r/storage_bucket_iam.html.markdown b/website/docs/r/storage_bucket_iam.html.markdown index bc2510a7730..b27d1bc4d6c 100644 --- a/website/docs/r/storage_bucket_iam.html.markdown +++ b/website/docs/r/storage_bucket_iam.html.markdown @@ -1,75 +1,86 @@ --- +# ---------------------------------------------------------------------------- +# +# *** 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. +# +# ---------------------------------------------------------------------------- subcategory: "Cloud Storage" layout: "google" page_title: "Google: google_storage_bucket_iam" sidebar_current: "docs-google-storage-bucket-iam" description: |- - Collection of resources to manage IAM policy for a Google storage bucket. + Collection of resources to manage IAM policy for StorageBucket --- -# IAM policy for Google storage bucket +# IAM policy for StorageBucket +Three different resources help you manage your IAM policy for Storage Bucket. Each of these resources serves a different use case: -Three different resources help you manage your IAM policy for storage bucket. Each of these resources serves a different use case: - -* `google_storage_bucket_iam_binding`: Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the storage bucket are preserved. -* `google_storage_bucket_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the storage bucket are preserved. -* `google_storage_bucket_iam_policy`: Setting a policy removes all other permissions on the bucket, and if done incorrectly, there's a real chance you will lock yourself out of the bucket. If possible for your use case, using multiple google_storage_bucket_iam_binding resources will be much safer. See the usage example on how to work with policy correctly. +* `google_storage_bucket_iam_policy`: Authoritative. Sets the IAM policy for the bucket and replaces any existing policy already attached. +* `google_storage_bucket_iam_binding`: Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the bucket are preserved. +* `google_storage_bucket_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the bucket are preserved. +~> **Note:** `google_storage_bucket_iam_policy` **cannot** be used in conjunction with `google_storage_bucket_iam_binding` and `google_storage_bucket_iam_member` or they will fight over what your policy should be. ~> **Note:** `google_storage_bucket_iam_binding` resources **can be** used in conjunction with `google_storage_bucket_iam_member` resources **only if** they do not grant privilege to the same role. -## google\_storage\_bucket\_iam\_binding + + +## google\_storage\_bucket\_iam\_policy ```hcl -resource "google_storage_bucket_iam_binding" "binding" { - bucket = "your-bucket-name" - role = "roles/storage.objectViewer" +data "google_iam_policy" "admin" { + binding { + role = "roles/storage.admin" + members = [ + "user:jane@example.com", + ] + } +} - members = [ - "user:jane@example.com", - ] +resource "google_storage_bucket_iam_policy" "editor" { + bucket = "${google_storage_bucket.default.name}" + policy_data = "${data.google_iam_policy.admin.policy_data}" } ``` -## google\_storage\_bucket\_iam\_member +## google\_storage\_bucket\_iam\_binding ```hcl -resource "google_storage_bucket_iam_member" "member" { - bucket = "your-bucket-name" - role = "roles/storage.objectViewer" - member = "user:jane@example.com" +resource "google_storage_bucket_iam_binding" "editor" { + bucket = "${google_storage_bucket.default.name}" + role = "roles/storage.admin" + members = [ + "user:jane@example.com", + ] } ``` -## google\_storage\_bucket\_iam\_policy - -When applying a policy that does not include the roles listed below, you lose the default permissions which google adds to your bucket: -* `roles/storage.legacyBucketOwner` -* `roles/storage.legacyBucketReader` - -If this happens only an entity with `roles/storage.admin` privileges can repair this bucket's policies. It is recommended to include the above roles in policies to get the same behaviour as with the other two options. +## google\_storage\_bucket\_iam\_member ```hcl -data "google_iam_policy" "foo-policy" { - binding { - role = "roles/your-role" - - members = ["group:yourgroup@example.com"] - } -} - -resource "google_storage_bucket_iam_policy" "member" { - bucket = "your-bucket-name" - policy_data = data.google_iam_policy.foo-policy.policy_data +resource "google_storage_bucket_iam_member" "editor" { + bucket = "${google_storage_bucket.default.name}" + role = "roles/storage.admin" + member = "user:jane@example.com" } ``` - ## Argument Reference The following arguments are supported: -* `bucket` - (Required) The name of the bucket it applies to. +* `bucket` - (Required) Used to find the parent resource to bind the IAM policy to + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the project will be parsed from the identifier of the parent resource. If no project is provided in the parent identifier and no project is specified, the provider project is used. * `member/members` - (Required) Identities that will be granted the privilege in `role`. Each entry can have one of the following values: @@ -80,27 +91,49 @@ The following arguments are supported: * **group:{emailid}**: An email address that represents a Google group. For example, admins@example.com. * **domain:{domain}**: A G Suite domain (primary, instead of alias) name that represents all the users of that domain. For example, google.com or example.com. -* `role` - (Required) The role that should be applied. Note that custom roles must be of the format +* `role` - (Required) The role that should be applied. Only one + `google_storage_bucket_iam_binding` can be used per role. Note that custom roles must be of the format `[projects|organizations]/{parent-name}/roles/{role-name}`. +* `policy_data` - (Required only by `google_storage_bucket_iam_policy`) The policy data generated by + a `google_iam_policy` data source. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: -* `etag` - (Computed) The etag of the storage bucket's IAM policy. - +* `etag` - (Computed) The etag of the IAM policy. ## Import -For `google_storage_bucket_iam_policy`: +For all import syntaxes, the "resource in question" can take any of the following forms: + +* b/{{name}} +* {{name}} + +Any variables not passed in the import command will be taken from the provider configuration. -IAM member imports use space-delimited identifiers - generally the resource in question, the role, and the member identity (i.e. `serviceAccount: my-sa@my-project.iam.gserviceaccount.com` or `user:foo@example.com`). Policies, bindings, and members can be respectively imported as follows: +Storage bucket IAM resources can be imported using the resource identifiers, role, and member. +IAM member imports use space-delimited identifiers: the resource in question, the role, and the member identity, e.g. +``` +$ terraform import google_storage_bucket_iam_member.editor "b/{{bucket}}?projection=full roles/storage.objectViewer jane@example.com" ``` -$ terraform import google_storage_bucket_iam_policy.policy "my-bucket user:foo@example.com" -$ terraform import google_storage_bucket_iam_binding.binding "my-bucket roles/my-role " +IAM binding imports use space-delimited identifiers: the resource in question and the role, e.g. +``` +$ terraform import google_storage_bucket_iam_binding.editor "b/{{bucket}} roles/storage.objectViewer" +``` -$ terraform import google_storage_bucket_iam_member.member "my-bucket roles/my-role user:foo@example.com" +IAM policy imports use the identifier of the resource in question, e.g. +``` +$ terraform import google_storage_bucket_iam_policy.editor b/{{bucket}} ``` + +-> If you're importing a resource with beta features, make sure to include `-provider=google-beta` +as an argument so that Terraform uses the correct provider to import your resource. + +## User Project Overrides + +This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override).