diff --git a/.changelog/7436.txt b/.changelog/7436.txt new file mode 100644 index 0000000000..d0327eadab --- /dev/null +++ b/.changelog/7436.txt @@ -0,0 +1,9 @@ +```release-note:new-resource +`google_dataplex_lake_iam_*` +``` +```release-note:new-resource +`google_dataplex_zone_iam_*` +``` +```release-note:new-resource +`google_dataplex_asset_iam_*` +``` diff --git a/google-beta/config.go b/google-beta/config.go index faf4730705..f5f4900bec 100644 --- a/google-beta/config.go +++ b/google-beta/config.go @@ -211,6 +211,7 @@ type Config struct { DataformBasePath string DataFusionBasePath string DataLossPreventionBasePath string + DataplexBasePath string DataprocBasePath string DataprocMetastoreBasePath string DatastoreBasePath string @@ -329,6 +330,7 @@ const DataCatalogBasePathKey = "DataCatalog" const DataformBasePathKey = "Dataform" const DataFusionBasePathKey = "DataFusion" const DataLossPreventionBasePathKey = "DataLossPrevention" +const DataplexBasePathKey = "Dataplex" const DataprocBasePathKey = "Dataproc" const DataprocMetastoreBasePathKey = "DataprocMetastore" const DatastoreBasePathKey = "Datastore" @@ -441,6 +443,7 @@ var DefaultBasePaths = map[string]string{ DataformBasePathKey: "https://dataform.googleapis.com/v1beta1/", DataFusionBasePathKey: "https://datafusion.googleapis.com/v1beta1/", DataLossPreventionBasePathKey: "https://dlp.googleapis.com/v2/", + DataplexBasePathKey: "https://dataplex.googleapis.com/v1/", DataprocBasePathKey: "https://dataproc.googleapis.com/v1beta2/", DataprocMetastoreBasePathKey: "https://metastore.googleapis.com/v1beta/", DatastoreBasePathKey: "https://datastore.googleapis.com/v1/", @@ -1343,6 +1346,7 @@ func ConfigureBasePaths(c *Config) { c.DataformBasePath = DefaultBasePaths[DataformBasePathKey] c.DataFusionBasePath = DefaultBasePaths[DataFusionBasePathKey] c.DataLossPreventionBasePath = DefaultBasePaths[DataLossPreventionBasePathKey] + c.DataplexBasePath = DefaultBasePaths[DataplexBasePathKey] c.DataprocBasePath = DefaultBasePaths[DataprocBasePathKey] c.DataprocMetastoreBasePath = DefaultBasePaths[DataprocMetastoreBasePathKey] c.DatastoreBasePath = DefaultBasePaths[DatastoreBasePathKey] diff --git a/google-beta/config_test_utils.go b/google-beta/config_test_utils.go index 632b00537f..c0762c2408 100644 --- a/google-beta/config_test_utils.go +++ b/google-beta/config_test_utils.go @@ -56,6 +56,7 @@ func configureTestBasePaths(c *Config, url string) { c.DataformBasePath = url c.DataFusionBasePath = url c.DataLossPreventionBasePath = url + c.DataplexBasePath = url c.DataprocBasePath = url c.DataprocMetastoreBasePath = url c.DatastoreBasePath = url diff --git a/google-beta/iam_dataplex_asset.go b/google-beta/iam_dataplex_asset.go new file mode 100644 index 0000000000..205496fe60 --- /dev/null +++ b/google-beta/iam_dataplex_asset.go @@ -0,0 +1,253 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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/v2/helper/schema" + "google.golang.org/api/cloudresourcemanager/v1" +) + +var DataplexAssetIamSchema = map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "location": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "lake": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "dataplex_zone": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "asset": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, +} + +type DataplexAssetIamUpdater struct { + project string + location string + lake string + dataplexZone string + asset string + d TerraformResourceData + Config *Config +} + +func DataplexAssetIamUpdaterProducer(d TerraformResourceData, config *Config) (ResourceIamUpdater, error) { + values := make(map[string]string) + + project, _ := getProject(d, config) + if project != "" { + if err := d.Set("project", project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + } + values["project"] = project + location, _ := getLocation(d, config) + if location != "" { + if err := d.Set("location", location); err != nil { + return nil, fmt.Errorf("Error setting location: %s", err) + } + } + values["location"] = location + if v, ok := d.GetOk("lake"); ok { + values["lake"] = v.(string) + } + + if v, ok := d.GetOk("dataplex_zone"); ok { + values["dataplex_zone"] = v.(string) + } + + if v, ok := d.GetOk("asset"); ok { + values["asset"] = v.(string) + } + + // We may have gotten either a long or short name, so attempt to parse long name if possible + m, err := getImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/(?P[^/]+)/lakes/(?P[^/]+)/zones/(?P[^/]+)/assets/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Get("asset").(string)) + if err != nil { + return nil, err + } + + for k, v := range m { + values[k] = v + } + + u := &DataplexAssetIamUpdater{ + project: values["project"], + location: values["location"], + lake: values["lake"], + dataplexZone: values["dataplex_zone"], + asset: values["asset"], + d: d, + Config: config, + } + + if err := d.Set("project", u.project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + if err := d.Set("location", u.location); err != nil { + return nil, fmt.Errorf("Error setting location: %s", err) + } + if err := d.Set("lake", u.lake); err != nil { + return nil, fmt.Errorf("Error setting lake: %s", err) + } + if err := d.Set("dataplex_zone", u.dataplexZone); err != nil { + return nil, fmt.Errorf("Error setting dataplex_zone: %s", err) + } + if err := d.Set("asset", u.GetResourceId()); err != nil { + return nil, fmt.Errorf("Error setting asset: %s", err) + } + + return u, nil +} + +func DataplexAssetIdParseFunc(d *schema.ResourceData, config *Config) error { + values := make(map[string]string) + + project, _ := getProject(d, config) + if project != "" { + values["project"] = project + } + + location, _ := getLocation(d, config) + if location != "" { + values["location"] = location + } + + m, err := getImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/(?P[^/]+)/lakes/(?P[^/]+)/zones/(?P[^/]+)/assets/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Id()) + if err != nil { + return err + } + + for k, v := range m { + values[k] = v + } + + u := &DataplexAssetIamUpdater{ + project: values["project"], + location: values["location"], + lake: values["lake"], + dataplexZone: values["dataplex_zone"], + asset: values["asset"], + d: d, + Config: config, + } + if err := d.Set("asset", u.GetResourceId()); err != nil { + return fmt.Errorf("Error setting asset: %s", err) + } + d.SetId(u.GetResourceId()) + return nil +} + +func (u *DataplexAssetIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { + url, err := u.qualifyAssetUrl("getIamPolicy") + if err != nil { + return nil, err + } + + project, err := getProject(u.d, u.Config) + if err != nil { + return nil, err + } + var obj map[string]interface{} + + userAgent, err := generateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return nil, err + } + + policy, err := SendRequest(u.Config, "GET", project, url, userAgent, obj) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + out := &cloudresourcemanager.Policy{} + err = Convert(policy, out) + if err != nil { + return nil, errwrap.Wrapf("Cannot convert a policy to a resource manager policy: {{err}}", err) + } + + return out, nil +} + +func (u *DataplexAssetIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { + json, err := ConvertToMap(policy) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + obj["policy"] = json + + url, err := u.qualifyAssetUrl("setIamPolicy") + if err != nil { + return err + } + project, err := getProject(u.d, u.Config) + if err != nil { + return err + } + + userAgent, err := generateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return err + } + + _, err = SendRequestWithTimeout(u.Config, "POST", project, url, userAgent, obj, u.d.Timeout(schema.TimeoutCreate)) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *DataplexAssetIamUpdater) qualifyAssetUrl(methodIdentifier string) (string, error) { + urlTemplate := fmt.Sprintf("{{DataplexBasePath}}%s:%s", fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s/assets/%s", u.project, u.location, u.lake, u.dataplexZone, u.asset), methodIdentifier) + url, err := replaceVars(u.d, u.Config, urlTemplate) + if err != nil { + return "", err + } + return url, nil +} + +func (u *DataplexAssetIamUpdater) GetResourceId() string { + return fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s/assets/%s", u.project, u.location, u.lake, u.dataplexZone, u.asset) +} + +func (u *DataplexAssetIamUpdater) GetMutexKey() string { + return fmt.Sprintf("iam-dataplex-asset-%s", u.GetResourceId()) +} + +func (u *DataplexAssetIamUpdater) DescribeResource() string { + return fmt.Sprintf("dataplex asset %q", u.GetResourceId()) +} diff --git a/google-beta/iam_dataplex_asset_generated_test.go b/google-beta/iam_dataplex_asset_generated_test.go new file mode 100644 index 0000000000..e3bbe85331 --- /dev/null +++ b/google-beta/iam_dataplex_asset_generated_test.go @@ -0,0 +1,503 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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/v2/helper/resource" +) + +func TestAccDataplexAssetIamBindingGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "role": "roles/viewer", + "project_name": GetTestProjectFromEnv(), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexAssetIamBinding_basicGenerated(context), + }, + { + ResourceName: "google_dataplex_asset_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s/assets/%s roles/viewer", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"]), fmt.Sprintf("tf-test-asset%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Iam Binding update + Config: testAccDataplexAssetIamBinding_updateGenerated(context), + }, + { + ResourceName: "google_dataplex_asset_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s/assets/%s roles/viewer", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"]), fmt.Sprintf("tf-test-asset%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccDataplexAssetIamMemberGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "role": "roles/viewer", + "project_name": GetTestProjectFromEnv(), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + // Test Iam Member creation (no update for member, no need to test) + Config: testAccDataplexAssetIamMember_basicGenerated(context), + }, + { + ResourceName: "google_dataplex_asset_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s/assets/%s roles/viewer user:admin@hashicorptest.com", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"]), fmt.Sprintf("tf-test-asset%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccDataplexAssetIamPolicyGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "role": "roles/viewer", + "project_name": GetTestProjectFromEnv(), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexAssetIamPolicy_basicGenerated(context), + }, + { + ResourceName: "google_dataplex_asset_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s/assets/%s", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"]), fmt.Sprintf("tf-test-asset%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccDataplexAssetIamPolicy_emptyBinding(context), + }, + { + ResourceName: "google_dataplex_asset_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s/assets/%s", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"]), fmt.Sprintf("tf-test-asset%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccDataplexAssetIamMember_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "primary_bucket" { + name = "dataplex-bucket-%{random_suffix}" + location = "us-central1" + uniform_bucket_level_access = true + lifecycle { + ignore_changes = [ + labels + ] + } + + project = "%{project_name}" +} + +resource "google_dataplex_lake" "example" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.example.name + type = "RAW" + + discovery_spec { + enabled = false + } + + + resource_spec { + location_type = "SINGLE_REGION" + } + + project = "%{project_name}" +} + + + +resource "google_dataplex_asset" "example" { + name = "tf-test-asset%{random_suffix}" + location = "us-central1" + + lake = google_dataplex_lake.example.name + dataplex_zone = google_dataplex_zone.example.name + discovery_spec { + enabled = false + } + + resource_spec { + name = "projects/%{project_name}/buckets/dataplex-bucket-%{random_suffix}" + type = "STORAGE_BUCKET" + } + + project = "%{project_name}" + depends_on = [ + google_storage_bucket.primary_bucket + ] +} + +resource "google_dataplex_asset_iam_member" "foo" { + project = google_dataplex_asset.example.project + location = google_dataplex_asset.example.location + lake = google_dataplex_asset.example.lake + dataplex_zone = google_dataplex_asset.example.dataplex_zone + asset = google_dataplex_asset.example.name + role = "%{role}" + member = "user:admin@hashicorptest.com" +} +`, context) +} + +func testAccDataplexAssetIamPolicy_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "primary_bucket" { + name = "dataplex-bucket-%{random_suffix}" + location = "us-central1" + uniform_bucket_level_access = true + lifecycle { + ignore_changes = [ + labels + ] + } + + project = "%{project_name}" +} + +resource "google_dataplex_lake" "example" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.example.name + type = "RAW" + + discovery_spec { + enabled = false + } + + + resource_spec { + location_type = "SINGLE_REGION" + } + + project = "%{project_name}" +} + + + +resource "google_dataplex_asset" "example" { + name = "tf-test-asset%{random_suffix}" + location = "us-central1" + + lake = google_dataplex_lake.example.name + dataplex_zone = google_dataplex_zone.example.name + discovery_spec { + enabled = false + } + + resource_spec { + name = "projects/%{project_name}/buckets/dataplex-bucket-%{random_suffix}" + type = "STORAGE_BUCKET" + } + + project = "%{project_name}" + depends_on = [ + google_storage_bucket.primary_bucket + ] +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + } +} + +resource "google_dataplex_asset_iam_policy" "foo" { + project = google_dataplex_asset.example.project + location = google_dataplex_asset.example.location + lake = google_dataplex_asset.example.lake + dataplex_zone = google_dataplex_asset.example.dataplex_zone + asset = google_dataplex_asset.example.name + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccDataplexAssetIamPolicy_emptyBinding(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "primary_bucket" { + name = "dataplex-bucket-%{random_suffix}" + location = "us-central1" + uniform_bucket_level_access = true + lifecycle { + ignore_changes = [ + labels + ] + } + + project = "%{project_name}" +} + +resource "google_dataplex_lake" "example" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.example.name + type = "RAW" + + discovery_spec { + enabled = false + } + + + resource_spec { + location_type = "SINGLE_REGION" + } + + project = "%{project_name}" +} + + + +resource "google_dataplex_asset" "example" { + name = "tf-test-asset%{random_suffix}" + location = "us-central1" + + lake = google_dataplex_lake.example.name + dataplex_zone = google_dataplex_zone.example.name + discovery_spec { + enabled = false + } + + resource_spec { + name = "projects/%{project_name}/buckets/dataplex-bucket-%{random_suffix}" + type = "STORAGE_BUCKET" + } + + project = "%{project_name}" + depends_on = [ + google_storage_bucket.primary_bucket + ] +} + +data "google_iam_policy" "foo" { +} + +resource "google_dataplex_asset_iam_policy" "foo" { + project = google_dataplex_asset.example.project + location = google_dataplex_asset.example.location + lake = google_dataplex_asset.example.lake + dataplex_zone = google_dataplex_asset.example.dataplex_zone + asset = google_dataplex_asset.example.name + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccDataplexAssetIamBinding_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "primary_bucket" { + name = "dataplex-bucket-%{random_suffix}" + location = "us-central1" + uniform_bucket_level_access = true + lifecycle { + ignore_changes = [ + labels + ] + } + + project = "%{project_name}" +} + +resource "google_dataplex_lake" "example" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.example.name + type = "RAW" + + discovery_spec { + enabled = false + } + + + resource_spec { + location_type = "SINGLE_REGION" + } + + project = "%{project_name}" +} + + + +resource "google_dataplex_asset" "example" { + name = "tf-test-asset%{random_suffix}" + location = "us-central1" + + lake = google_dataplex_lake.example.name + dataplex_zone = google_dataplex_zone.example.name + discovery_spec { + enabled = false + } + + resource_spec { + name = "projects/%{project_name}/buckets/dataplex-bucket-%{random_suffix}" + type = "STORAGE_BUCKET" + } + + project = "%{project_name}" + depends_on = [ + google_storage_bucket.primary_bucket + ] +} + +resource "google_dataplex_asset_iam_binding" "foo" { + project = google_dataplex_asset.example.project + location = google_dataplex_asset.example.location + lake = google_dataplex_asset.example.lake + dataplex_zone = google_dataplex_asset.example.dataplex_zone + asset = google_dataplex_asset.example.name + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} +`, context) +} + +func testAccDataplexAssetIamBinding_updateGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_storage_bucket" "primary_bucket" { + name = "dataplex-bucket-%{random_suffix}" + location = "us-central1" + uniform_bucket_level_access = true + lifecycle { + ignore_changes = [ + labels + ] + } + + project = "%{project_name}" +} + +resource "google_dataplex_lake" "example" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.example.name + type = "RAW" + + discovery_spec { + enabled = false + } + + + resource_spec { + location_type = "SINGLE_REGION" + } + + project = "%{project_name}" +} + + + +resource "google_dataplex_asset" "example" { + name = "tf-test-asset%{random_suffix}" + location = "us-central1" + + lake = google_dataplex_lake.example.name + dataplex_zone = google_dataplex_zone.example.name + discovery_spec { + enabled = false + } + + resource_spec { + name = "projects/%{project_name}/buckets/dataplex-bucket-%{random_suffix}" + type = "STORAGE_BUCKET" + } + + project = "%{project_name}" + depends_on = [ + google_storage_bucket.primary_bucket + ] +} + +resource "google_dataplex_asset_iam_binding" "foo" { + project = google_dataplex_asset.example.project + location = google_dataplex_asset.example.location + lake = google_dataplex_asset.example.lake + dataplex_zone = google_dataplex_asset.example.dataplex_zone + asset = google_dataplex_asset.example.name + role = "%{role}" + members = ["user:admin@hashicorptest.com", "user:gterraformtest1@gmail.com"] +} +`, context) +} diff --git a/google-beta/iam_dataplex_lake.go b/google-beta/iam_dataplex_lake.go new file mode 100644 index 0000000000..c3505a2cdf --- /dev/null +++ b/google-beta/iam_dataplex_lake.go @@ -0,0 +1,223 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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/v2/helper/schema" + "google.golang.org/api/cloudresourcemanager/v1" +) + +var DataplexLakeIamSchema = map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "location": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "lake": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, +} + +type DataplexLakeIamUpdater struct { + project string + location string + lake string + d TerraformResourceData + Config *Config +} + +func DataplexLakeIamUpdaterProducer(d TerraformResourceData, config *Config) (ResourceIamUpdater, error) { + values := make(map[string]string) + + project, _ := getProject(d, config) + if project != "" { + if err := d.Set("project", project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + } + values["project"] = project + location, _ := getLocation(d, config) + if location != "" { + if err := d.Set("location", location); err != nil { + return nil, fmt.Errorf("Error setting location: %s", err) + } + } + values["location"] = location + if v, ok := d.GetOk("lake"); ok { + values["lake"] = v.(string) + } + + // We may have gotten either a long or short name, so attempt to parse long name if possible + m, err := getImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/(?P[^/]+)/lakes/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Get("lake").(string)) + if err != nil { + return nil, err + } + + for k, v := range m { + values[k] = v + } + + u := &DataplexLakeIamUpdater{ + project: values["project"], + location: values["location"], + lake: values["lake"], + d: d, + Config: config, + } + + if err := d.Set("project", u.project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + if err := d.Set("location", u.location); err != nil { + return nil, fmt.Errorf("Error setting location: %s", err) + } + if err := d.Set("lake", u.GetResourceId()); err != nil { + return nil, fmt.Errorf("Error setting lake: %s", err) + } + + return u, nil +} + +func DataplexLakeIdParseFunc(d *schema.ResourceData, config *Config) error { + values := make(map[string]string) + + project, _ := getProject(d, config) + if project != "" { + values["project"] = project + } + + location, _ := getLocation(d, config) + if location != "" { + values["location"] = location + } + + m, err := getImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/(?P[^/]+)/lakes/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Id()) + if err != nil { + return err + } + + for k, v := range m { + values[k] = v + } + + u := &DataplexLakeIamUpdater{ + project: values["project"], + location: values["location"], + lake: values["lake"], + d: d, + Config: config, + } + if err := d.Set("lake", u.GetResourceId()); err != nil { + return fmt.Errorf("Error setting lake: %s", err) + } + d.SetId(u.GetResourceId()) + return nil +} + +func (u *DataplexLakeIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { + url, err := u.qualifyLakeUrl("getIamPolicy") + if err != nil { + return nil, err + } + + project, err := getProject(u.d, u.Config) + if err != nil { + return nil, err + } + var obj map[string]interface{} + + userAgent, err := generateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return nil, err + } + + policy, err := SendRequest(u.Config, "GET", project, url, userAgent, obj) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + out := &cloudresourcemanager.Policy{} + err = Convert(policy, out) + if err != nil { + return nil, errwrap.Wrapf("Cannot convert a policy to a resource manager policy: {{err}}", err) + } + + return out, nil +} + +func (u *DataplexLakeIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { + json, err := ConvertToMap(policy) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + obj["policy"] = json + + url, err := u.qualifyLakeUrl("setIamPolicy") + if err != nil { + return err + } + project, err := getProject(u.d, u.Config) + if err != nil { + return err + } + + userAgent, err := generateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return err + } + + _, err = SendRequestWithTimeout(u.Config, "POST", project, url, userAgent, obj, u.d.Timeout(schema.TimeoutCreate)) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *DataplexLakeIamUpdater) qualifyLakeUrl(methodIdentifier string) (string, error) { + urlTemplate := fmt.Sprintf("{{DataplexBasePath}}%s:%s", fmt.Sprintf("projects/%s/locations/%s/lakes/%s", u.project, u.location, u.lake), methodIdentifier) + url, err := replaceVars(u.d, u.Config, urlTemplate) + if err != nil { + return "", err + } + return url, nil +} + +func (u *DataplexLakeIamUpdater) GetResourceId() string { + return fmt.Sprintf("projects/%s/locations/%s/lakes/%s", u.project, u.location, u.lake) +} + +func (u *DataplexLakeIamUpdater) GetMutexKey() string { + return fmt.Sprintf("iam-dataplex-lake-%s", u.GetResourceId()) +} + +func (u *DataplexLakeIamUpdater) DescribeResource() string { + return fmt.Sprintf("dataplex lake %q", u.GetResourceId()) +} diff --git a/google-beta/iam_dataplex_lake_generated_test.go b/google-beta/iam_dataplex_lake_generated_test.go new file mode 100644 index 0000000000..1831cf7428 --- /dev/null +++ b/google-beta/iam_dataplex_lake_generated_test.go @@ -0,0 +1,253 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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/v2/helper/resource" +) + +func TestAccDataplexLakeIamBindingGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "role": "roles/viewer", + "project_name": GetTestProjectFromEnv(), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexLakeIamBinding_basicGenerated(context), + }, + { + ResourceName: "google_dataplex_lake_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s roles/viewer", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Iam Binding update + Config: testAccDataplexLakeIamBinding_updateGenerated(context), + }, + { + ResourceName: "google_dataplex_lake_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s roles/viewer", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccDataplexLakeIamMemberGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "role": "roles/viewer", + "project_name": GetTestProjectFromEnv(), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + // Test Iam Member creation (no update for member, no need to test) + Config: testAccDataplexLakeIamMember_basicGenerated(context), + }, + { + ResourceName: "google_dataplex_lake_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s roles/viewer user:admin@hashicorptest.com", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccDataplexLakeIamPolicyGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "role": "roles/viewer", + "project_name": GetTestProjectFromEnv(), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexLakeIamPolicy_basicGenerated(context), + }, + { + ResourceName: "google_dataplex_lake_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccDataplexLakeIamPolicy_emptyBinding(context), + }, + { + ResourceName: "google_dataplex_lake_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccDataplexLakeIamMember_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + +resource "google_dataplex_lake_iam_member" "foo" { + project = google_dataplex_lake.example.project + location = google_dataplex_lake.example.location + lake = google_dataplex_lake.example.name + role = "%{role}" + member = "user:admin@hashicorptest.com" +} +`, context) +} + +func testAccDataplexLakeIamPolicy_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + } +} + +resource "google_dataplex_lake_iam_policy" "foo" { + project = google_dataplex_lake.example.project + location = google_dataplex_lake.example.location + lake = google_dataplex_lake.example.name + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccDataplexLakeIamPolicy_emptyBinding(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + +data "google_iam_policy" "foo" { +} + +resource "google_dataplex_lake_iam_policy" "foo" { + project = google_dataplex_lake.example.project + location = google_dataplex_lake.example.location + lake = google_dataplex_lake.example.name + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccDataplexLakeIamBinding_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + +resource "google_dataplex_lake_iam_binding" "foo" { + project = google_dataplex_lake.example.project + location = google_dataplex_lake.example.location + lake = google_dataplex_lake.example.name + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} +`, context) +} + +func testAccDataplexLakeIamBinding_updateGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + +resource "google_dataplex_lake_iam_binding" "foo" { + project = google_dataplex_lake.example.project + location = google_dataplex_lake.example.location + lake = google_dataplex_lake.example.name + role = "%{role}" + members = ["user:admin@hashicorptest.com", "user:gterraformtest1@gmail.com"] +} +`, context) +} diff --git a/google-beta/iam_dataplex_zone.go b/google-beta/iam_dataplex_zone.go new file mode 100644 index 0000000000..cc34ea7b80 --- /dev/null +++ b/google-beta/iam_dataplex_zone.go @@ -0,0 +1,238 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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/v2/helper/schema" + "google.golang.org/api/cloudresourcemanager/v1" +) + +var DataplexZoneIamSchema = map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "location": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "lake": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "dataplex_zone": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, +} + +type DataplexZoneIamUpdater struct { + project string + location string + lake string + dataplexZone string + d TerraformResourceData + Config *Config +} + +func DataplexZoneIamUpdaterProducer(d TerraformResourceData, config *Config) (ResourceIamUpdater, error) { + values := make(map[string]string) + + project, _ := getProject(d, config) + if project != "" { + if err := d.Set("project", project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + } + values["project"] = project + location, _ := getLocation(d, config) + if location != "" { + if err := d.Set("location", location); err != nil { + return nil, fmt.Errorf("Error setting location: %s", err) + } + } + values["location"] = location + if v, ok := d.GetOk("lake"); ok { + values["lake"] = v.(string) + } + + if v, ok := d.GetOk("dataplex_zone"); ok { + values["dataplex_zone"] = v.(string) + } + + // We may have gotten either a long or short name, so attempt to parse long name if possible + m, err := getImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/(?P[^/]+)/lakes/(?P[^/]+)/zones/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Get("dataplex_zone").(string)) + if err != nil { + return nil, err + } + + for k, v := range m { + values[k] = v + } + + u := &DataplexZoneIamUpdater{ + project: values["project"], + location: values["location"], + lake: values["lake"], + dataplexZone: values["dataplex_zone"], + d: d, + Config: config, + } + + if err := d.Set("project", u.project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + if err := d.Set("location", u.location); err != nil { + return nil, fmt.Errorf("Error setting location: %s", err) + } + if err := d.Set("lake", u.lake); err != nil { + return nil, fmt.Errorf("Error setting lake: %s", err) + } + if err := d.Set("dataplex_zone", u.GetResourceId()); err != nil { + return nil, fmt.Errorf("Error setting dataplex_zone: %s", err) + } + + return u, nil +} + +func DataplexZoneIdParseFunc(d *schema.ResourceData, config *Config) error { + values := make(map[string]string) + + project, _ := getProject(d, config) + if project != "" { + values["project"] = project + } + + location, _ := getLocation(d, config) + if location != "" { + values["location"] = location + } + + m, err := getImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/(?P[^/]+)/lakes/(?P[^/]+)/zones/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Id()) + if err != nil { + return err + } + + for k, v := range m { + values[k] = v + } + + u := &DataplexZoneIamUpdater{ + project: values["project"], + location: values["location"], + lake: values["lake"], + dataplexZone: values["dataplex_zone"], + d: d, + Config: config, + } + if err := d.Set("dataplex_zone", u.GetResourceId()); err != nil { + return fmt.Errorf("Error setting dataplex_zone: %s", err) + } + d.SetId(u.GetResourceId()) + return nil +} + +func (u *DataplexZoneIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { + url, err := u.qualifyZoneUrl("getIamPolicy") + if err != nil { + return nil, err + } + + project, err := getProject(u.d, u.Config) + if err != nil { + return nil, err + } + var obj map[string]interface{} + + userAgent, err := generateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return nil, err + } + + policy, err := SendRequest(u.Config, "GET", project, url, userAgent, obj) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + out := &cloudresourcemanager.Policy{} + err = Convert(policy, out) + if err != nil { + return nil, errwrap.Wrapf("Cannot convert a policy to a resource manager policy: {{err}}", err) + } + + return out, nil +} + +func (u *DataplexZoneIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { + json, err := ConvertToMap(policy) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + obj["policy"] = json + + url, err := u.qualifyZoneUrl("setIamPolicy") + if err != nil { + return err + } + project, err := getProject(u.d, u.Config) + if err != nil { + return err + } + + userAgent, err := generateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return err + } + + _, err = SendRequestWithTimeout(u.Config, "POST", project, url, userAgent, obj, u.d.Timeout(schema.TimeoutCreate)) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *DataplexZoneIamUpdater) qualifyZoneUrl(methodIdentifier string) (string, error) { + urlTemplate := fmt.Sprintf("{{DataplexBasePath}}%s:%s", fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s", u.project, u.location, u.lake, u.dataplexZone), methodIdentifier) + url, err := replaceVars(u.d, u.Config, urlTemplate) + if err != nil { + return "", err + } + return url, nil +} + +func (u *DataplexZoneIamUpdater) GetResourceId() string { + return fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s", u.project, u.location, u.lake, u.dataplexZone) +} + +func (u *DataplexZoneIamUpdater) GetMutexKey() string { + return fmt.Sprintf("iam-dataplex-zone-%s", u.GetResourceId()) +} + +func (u *DataplexZoneIamUpdater) DescribeResource() string { + return fmt.Sprintf("dataplex zone %q", u.GetResourceId()) +} diff --git a/google-beta/iam_dataplex_zone_generated_test.go b/google-beta/iam_dataplex_zone_generated_test.go new file mode 100644 index 0000000000..e09c771dff --- /dev/null +++ b/google-beta/iam_dataplex_zone_generated_test.go @@ -0,0 +1,363 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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/v2/helper/resource" +) + +func TestAccDataplexZoneIamBindingGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "role": "roles/viewer", + "project_name": GetTestProjectFromEnv(), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexZoneIamBinding_basicGenerated(context), + }, + { + ResourceName: "google_dataplex_zone_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s roles/viewer", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Iam Binding update + Config: testAccDataplexZoneIamBinding_updateGenerated(context), + }, + { + ResourceName: "google_dataplex_zone_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s roles/viewer", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccDataplexZoneIamMemberGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "role": "roles/viewer", + "project_name": GetTestProjectFromEnv(), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + // Test Iam Member creation (no update for member, no need to test) + Config: testAccDataplexZoneIamMember_basicGenerated(context), + }, + { + ResourceName: "google_dataplex_zone_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s roles/viewer user:admin@hashicorptest.com", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccDataplexZoneIamPolicyGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "role": "roles/viewer", + "project_name": GetTestProjectFromEnv(), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexZoneIamPolicy_basicGenerated(context), + }, + { + ResourceName: "google_dataplex_zone_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccDataplexZoneIamPolicy_emptyBinding(context), + }, + { + ResourceName: "google_dataplex_zone_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/lakes/%s/zones/%s", GetTestProjectFromEnv(), GetTestRegionFromEnv(), fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), fmt.Sprintf("tf-test-zone%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccDataplexZoneIamMember_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + discovery_spec { + enabled = false + } + + lake = google_dataplex_lake.example.name + location = "us-central1" + + resource_spec { + location_type = "MULTI_REGION" + } + + type = "RAW" + description = "Test Zone" + display_name = "Test Zone" + labels = {} + project = "%{project_name}" +} + +resource "google_dataplex_zone_iam_member" "foo" { + project = google_dataplex_zone.example.project + location = google_dataplex_zone.example.location + lake = google_dataplex_zone.example.lake + dataplex_zone = google_dataplex_zone.example.name + role = "%{role}" + member = "user:admin@hashicorptest.com" +} +`, context) +} + +func testAccDataplexZoneIamPolicy_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + discovery_spec { + enabled = false + } + + lake = google_dataplex_lake.example.name + location = "us-central1" + + resource_spec { + location_type = "MULTI_REGION" + } + + type = "RAW" + description = "Test Zone" + display_name = "Test Zone" + labels = {} + project = "%{project_name}" +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + } +} + +resource "google_dataplex_zone_iam_policy" "foo" { + project = google_dataplex_zone.example.project + location = google_dataplex_zone.example.location + lake = google_dataplex_zone.example.lake + dataplex_zone = google_dataplex_zone.example.name + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccDataplexZoneIamPolicy_emptyBinding(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + discovery_spec { + enabled = false + } + + lake = google_dataplex_lake.example.name + location = "us-central1" + + resource_spec { + location_type = "MULTI_REGION" + } + + type = "RAW" + description = "Test Zone" + display_name = "Test Zone" + labels = {} + project = "%{project_name}" +} + +data "google_iam_policy" "foo" { +} + +resource "google_dataplex_zone_iam_policy" "foo" { + project = google_dataplex_zone.example.project + location = google_dataplex_zone.example.location + lake = google_dataplex_zone.example.lake + dataplex_zone = google_dataplex_zone.example.name + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccDataplexZoneIamBinding_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + discovery_spec { + enabled = false + } + + lake = google_dataplex_lake.example.name + location = "us-central1" + + resource_spec { + location_type = "MULTI_REGION" + } + + type = "RAW" + description = "Test Zone" + display_name = "Test Zone" + labels = {} + project = "%{project_name}" +} + +resource "google_dataplex_zone_iam_binding" "foo" { + project = google_dataplex_zone.example.project + location = google_dataplex_zone.example.location + lake = google_dataplex_zone.example.lake + dataplex_zone = google_dataplex_zone.example.name + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} +`, context) +} + +func testAccDataplexZoneIamBinding_updateGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_dataplex_lake" "example" { + location = "us-central1" + name = "tf-test-lake%{random_suffix}" + description = "Test Lake" + display_name = "Test Lake" + + labels = { + my-lake = "exists" + } + + project = "%{project_name}" +} + + +resource "google_dataplex_zone" "example" { + name = "tf-test-zone%{random_suffix}" + discovery_spec { + enabled = false + } + + lake = google_dataplex_lake.example.name + location = "us-central1" + + resource_spec { + location_type = "MULTI_REGION" + } + + type = "RAW" + description = "Test Zone" + display_name = "Test Zone" + labels = {} + project = "%{project_name}" +} + +resource "google_dataplex_zone_iam_binding" "foo" { + project = google_dataplex_zone.example.project + location = google_dataplex_zone.example.location + lake = google_dataplex_zone.example.lake + dataplex_zone = google_dataplex_zone.example.name + role = "%{role}" + members = ["user:admin@hashicorptest.com", "user:gterraformtest1@gmail.com"] +} +`, context) +} diff --git a/google-beta/provider.go b/google-beta/provider.go index 7b10075b83..0eaf1b47f4 100644 --- a/google-beta/provider.go +++ b/google-beta/provider.go @@ -453,6 +453,14 @@ func Provider() *schema.Provider { "GOOGLE_DATA_LOSS_PREVENTION_CUSTOM_ENDPOINT", }, DefaultBasePaths[DataLossPreventionBasePathKey]), }, + "dataplex_custom_endpoint": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateCustomEndpoint, + DefaultFunc: schema.MultiEnvDefaultFunc([]string{ + "GOOGLE_DATAPLEX_CUSTOM_ENDPOINT", + }, DefaultBasePaths[DataplexBasePathKey]), + }, "dataproc_custom_endpoint": { Type: schema.TypeString, Optional: true, @@ -1109,8 +1117,8 @@ func Provider() *schema.Provider { } // Generated resources: 310 -// Generated IAM resources: 204 -// Total generated resources: 514 +// Generated IAM resources: 213 +// Total generated resources: 523 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -1387,6 +1395,15 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_data_loss_prevention_inspect_template": ResourceDataLossPreventionInspectTemplate(), "google_data_loss_prevention_job_trigger": ResourceDataLossPreventionJobTrigger(), "google_data_loss_prevention_stored_info_type": ResourceDataLossPreventionStoredInfoType(), + "google_dataplex_asset_iam_binding": ResourceIamBinding(DataplexAssetIamSchema, DataplexAssetIamUpdaterProducer, DataplexAssetIdParseFunc), + "google_dataplex_asset_iam_member": ResourceIamMember(DataplexAssetIamSchema, DataplexAssetIamUpdaterProducer, DataplexAssetIdParseFunc), + "google_dataplex_asset_iam_policy": ResourceIamPolicy(DataplexAssetIamSchema, DataplexAssetIamUpdaterProducer, DataplexAssetIdParseFunc), + "google_dataplex_lake_iam_binding": ResourceIamBinding(DataplexLakeIamSchema, DataplexLakeIamUpdaterProducer, DataplexLakeIdParseFunc), + "google_dataplex_lake_iam_member": ResourceIamMember(DataplexLakeIamSchema, DataplexLakeIamUpdaterProducer, DataplexLakeIdParseFunc), + "google_dataplex_lake_iam_policy": ResourceIamPolicy(DataplexLakeIamSchema, DataplexLakeIamUpdaterProducer, DataplexLakeIdParseFunc), + "google_dataplex_zone_iam_binding": ResourceIamBinding(DataplexZoneIamSchema, DataplexZoneIamUpdaterProducer, DataplexZoneIdParseFunc), + "google_dataplex_zone_iam_member": ResourceIamMember(DataplexZoneIamSchema, DataplexZoneIamUpdaterProducer, DataplexZoneIdParseFunc), + "google_dataplex_zone_iam_policy": ResourceIamPolicy(DataplexZoneIamSchema, DataplexZoneIamUpdaterProducer, DataplexZoneIdParseFunc), "google_dataproc_autoscaling_policy": ResourceDataprocAutoscalingPolicy(), "google_dataproc_autoscaling_policy_iam_binding": ResourceIamBinding(DataprocAutoscalingPolicyIamSchema, DataprocAutoscalingPolicyIamUpdaterProducer, DataprocAutoscalingPolicyIdParseFunc), "google_dataproc_autoscaling_policy_iam_member": ResourceIamMember(DataprocAutoscalingPolicyIamSchema, DataprocAutoscalingPolicyIamUpdaterProducer, DataprocAutoscalingPolicyIdParseFunc), @@ -1905,6 +1922,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.DataformBasePath = d.Get("dataform_custom_endpoint").(string) config.DataFusionBasePath = d.Get("data_fusion_custom_endpoint").(string) config.DataLossPreventionBasePath = d.Get("data_loss_prevention_custom_endpoint").(string) + config.DataplexBasePath = d.Get("dataplex_custom_endpoint").(string) config.DataprocBasePath = d.Get("dataproc_custom_endpoint").(string) config.DataprocMetastoreBasePath = d.Get("dataproc_metastore_custom_endpoint").(string) config.DatastoreBasePath = d.Get("datastore_custom_endpoint").(string) diff --git a/google-beta/provider_dcl_endpoints.go b/google-beta/provider_dcl_endpoints.go index 92773c4368..54c38c9424 100644 --- a/google-beta/provider_dcl_endpoints.go +++ b/google-beta/provider_dcl_endpoints.go @@ -67,15 +67,6 @@ var CloudResourceManagerEndpointEntry = &schema.Schema{ }, ""), } -var DataplexEndpointEntryKey = "dataplex_custom_endpoint" -var DataplexEndpointEntry = &schema.Schema{ - Type: schema.TypeString, - Optional: true, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{ - "GOOGLE_DATAPLEX_CUSTOM_ENDPOINT", - }, ""), -} - var EventarcEndpointEntryKey = "eventarc_custom_endpoint" var EventarcEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -127,7 +118,6 @@ type DCLConfig struct { CloudBuildWorkerPoolBasePath string ClouddeployBasePath string CloudResourceManagerBasePath string - DataplexBasePath string EventarcBasePath string FirebaserulesBasePath string GKEHubFeatureBasePath string @@ -141,7 +131,6 @@ func ConfigureDCLProvider(provider *schema.Provider) { provider.Schema[CloudBuildWorkerPoolEndpointEntryKey] = CloudBuildWorkerPoolEndpointEntry provider.Schema[ClouddeployEndpointEntryKey] = ClouddeployEndpointEntry provider.Schema[CloudResourceManagerEndpointEntryKey] = CloudResourceManagerEndpointEntry - provider.Schema[DataplexEndpointEntryKey] = DataplexEndpointEntry provider.Schema[EventarcEndpointEntryKey] = EventarcEndpointEntry provider.Schema[FirebaserulesEndpointEntryKey] = FirebaserulesEndpointEntry provider.Schema[GKEHubFeatureEndpointEntryKey] = GKEHubFeatureEndpointEntry @@ -155,7 +144,6 @@ func ProviderDCLConfigure(d *schema.ResourceData, config *Config) interface{} { config.CloudBuildWorkerPoolBasePath = d.Get(CloudBuildWorkerPoolEndpointEntryKey).(string) config.ClouddeployBasePath = d.Get(ClouddeployEndpointEntryKey).(string) config.CloudResourceManagerBasePath = d.Get(CloudResourceManagerEndpointEntryKey).(string) - config.DataplexBasePath = d.Get(DataplexEndpointEntryKey).(string) config.EventarcBasePath = d.Get(EventarcEndpointEntryKey).(string) config.FirebaserulesBasePath = d.Get(FirebaserulesEndpointEntryKey).(string) config.GKEHubFeatureBasePath = d.Get(GKEHubFeatureEndpointEntryKey).(string) diff --git a/website/docs/r/dataplex_asset_iam.html.markdown b/website/docs/r/dataplex_asset_iam.html.markdown new file mode 100644 index 0000000000..ddd2c9054c --- /dev/null +++ b/website/docs/r/dataplex_asset_iam.html.markdown @@ -0,0 +1,154 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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 Dataplex" +description: |- + Collection of resources to manage IAM policy for Cloud Dataplex Asset +--- + +# IAM policy for Cloud Dataplex Asset +Three different resources help you manage your IAM policy for Cloud Dataplex Asset. Each of these resources serves a different use case: + +* `google_dataplex_asset_iam_policy`: Authoritative. Sets the IAM policy for the asset and replaces any existing policy already attached. +* `google_dataplex_asset_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 asset are preserved. +* `google_dataplex_asset_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the asset are preserved. + +~> **Note:** `google_dataplex_asset_iam_policy` **cannot** be used in conjunction with `google_dataplex_asset_iam_binding` and `google_dataplex_asset_iam_member` or they will fight over what your policy should be. + +~> **Note:** `google_dataplex_asset_iam_binding` resources **can be** used in conjunction with `google_dataplex_asset_iam_member` resources **only if** they do not grant privilege to the same role. + + + + +## google\_dataplex\_asset\_iam\_policy + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/viewer" + members = [ + "user:jane@example.com", + ] + } +} + +resource "google_dataplex_asset_iam_policy" "policy" { + project = google_dataplex_asset.example.project + location = google_dataplex_asset.example.location + lake = google_dataplex_asset.example.lake + dataplex_zone = google_dataplex_asset.example.dataplex_zone + asset = google_dataplex_asset.example.name + policy_data = data.google_iam_policy.admin.policy_data +} +``` + +## google\_dataplex\_asset\_iam\_binding + +```hcl +resource "google_dataplex_asset_iam_binding" "binding" { + project = google_dataplex_asset.example.project + location = google_dataplex_asset.example.location + lake = google_dataplex_asset.example.lake + dataplex_zone = google_dataplex_asset.example.dataplex_zone + asset = google_dataplex_asset.example.name + role = "roles/viewer" + members = [ + "user:jane@example.com", + ] +} +``` + +## google\_dataplex\_asset\_iam\_member + +```hcl +resource "google_dataplex_asset_iam_member" "member" { + project = google_dataplex_asset.example.project + location = google_dataplex_asset.example.location + lake = google_dataplex_asset.example.lake + dataplex_zone = google_dataplex_asset.example.dataplex_zone + asset = google_dataplex_asset.example.name + role = "roles/viewer" + member = "user:jane@example.com" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `asset` - (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: + * **allUsers**: A special identifier that represents anyone who is on the internet; with or without a Google account. + * **allAuthenticatedUsers**: A special identifier that represents anyone who is authenticated with a Google account or a service account. + * **user:{emailid}**: An email address that represents a specific Google account. For example, alice@gmail.com or joe@example.com. + * **serviceAccount:{emailid}**: An email address that represents a service account. For example, my-other-app@appspot.gserviceaccount.com. + * **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. + * **projectOwner:projectid**: Owners of the given project. For example, "projectOwner:my-example-project" + * **projectEditor:projectid**: Editors of the given project. For example, "projectEditor:my-example-project" + * **projectViewer:projectid**: Viewers of the given project. For example, "projectViewer:my-example-project" + +* `role` - (Required) The role that should be applied. Only one + `google_dataplex_asset_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_dataplex_asset_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 IAM policy. + +## Import + +For all import syntaxes, the "resource in question" can take any of the following forms: + +* projects/{{project}}/locations/{{location}}/lakes/{{lake}}/zones/{{dataplex_zone}}/assets/{{name}} +* {{project}}/{{location}}/{{lake}}/{{dataplex_zone}}/{{name}} +* {{location}}/{{lake}}/{{dataplex_zone}}/{{name}} +* {{name}} + +Any variables not passed in the import command will be taken from the provider configuration. + +Cloud Dataplex asset 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_dataplex_asset_iam_member.editor "projects/{{project}}/locations/{{location}}/lakes/{{lake}}/zones/{{dataplex_zone}}/assets/{{asset}} roles/viewer user:jane@example.com" +``` + +IAM binding imports use space-delimited identifiers: the resource in question and the role, e.g. +``` +$ terraform import google_dataplex_asset_iam_binding.editor "projects/{{project}}/locations/{{location}}/lakes/{{lake}}/zones/{{dataplex_zone}}/assets/{{asset}} roles/viewer" +``` + +IAM policy imports use the identifier of the resource in question, e.g. +``` +$ terraform import google_dataplex_asset_iam_policy.editor projects/{{project}}/locations/{{location}}/lakes/{{lake}}/zones/{{dataplex_zone}}/assets/{{asset}} +``` + +-> **Custom Roles**: If you're importing a IAM resource with a custom role, make sure to use the + full name of the custom role, e.g. `[projects/my-project|organizations/my-org]/roles/my-custom-role`. + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override). diff --git a/website/docs/r/dataplex_lake_iam.html.markdown b/website/docs/r/dataplex_lake_iam.html.markdown new file mode 100644 index 0000000000..b96da363c9 --- /dev/null +++ b/website/docs/r/dataplex_lake_iam.html.markdown @@ -0,0 +1,148 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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 Dataplex" +description: |- + Collection of resources to manage IAM policy for Cloud Dataplex Lake +--- + +# IAM policy for Cloud Dataplex Lake +Three different resources help you manage your IAM policy for Cloud Dataplex Lake. Each of these resources serves a different use case: + +* `google_dataplex_lake_iam_policy`: Authoritative. Sets the IAM policy for the lake and replaces any existing policy already attached. +* `google_dataplex_lake_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 lake are preserved. +* `google_dataplex_lake_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the lake are preserved. + +~> **Note:** `google_dataplex_lake_iam_policy` **cannot** be used in conjunction with `google_dataplex_lake_iam_binding` and `google_dataplex_lake_iam_member` or they will fight over what your policy should be. + +~> **Note:** `google_dataplex_lake_iam_binding` resources **can be** used in conjunction with `google_dataplex_lake_iam_member` resources **only if** they do not grant privilege to the same role. + + + + +## google\_dataplex\_lake\_iam\_policy + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/viewer" + members = [ + "user:jane@example.com", + ] + } +} + +resource "google_dataplex_lake_iam_policy" "policy" { + project = google_dataplex_lake.example.project + location = google_dataplex_lake.example.location + lake = google_dataplex_lake.example.name + policy_data = data.google_iam_policy.admin.policy_data +} +``` + +## google\_dataplex\_lake\_iam\_binding + +```hcl +resource "google_dataplex_lake_iam_binding" "binding" { + project = google_dataplex_lake.example.project + location = google_dataplex_lake.example.location + lake = google_dataplex_lake.example.name + role = "roles/viewer" + members = [ + "user:jane@example.com", + ] +} +``` + +## google\_dataplex\_lake\_iam\_member + +```hcl +resource "google_dataplex_lake_iam_member" "member" { + project = google_dataplex_lake.example.project + location = google_dataplex_lake.example.location + lake = google_dataplex_lake.example.name + role = "roles/viewer" + member = "user:jane@example.com" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `lake` - (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: + * **allUsers**: A special identifier that represents anyone who is on the internet; with or without a Google account. + * **allAuthenticatedUsers**: A special identifier that represents anyone who is authenticated with a Google account or a service account. + * **user:{emailid}**: An email address that represents a specific Google account. For example, alice@gmail.com or joe@example.com. + * **serviceAccount:{emailid}**: An email address that represents a service account. For example, my-other-app@appspot.gserviceaccount.com. + * **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. + * **projectOwner:projectid**: Owners of the given project. For example, "projectOwner:my-example-project" + * **projectEditor:projectid**: Editors of the given project. For example, "projectEditor:my-example-project" + * **projectViewer:projectid**: Viewers of the given project. For example, "projectViewer:my-example-project" + +* `role` - (Required) The role that should be applied. Only one + `google_dataplex_lake_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_dataplex_lake_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 IAM policy. + +## Import + +For all import syntaxes, the "resource in question" can take any of the following forms: + +* projects/{{project}}/locations/{{location}}/lakes/{{name}} +* {{project}}/{{location}}/{{name}} +* {{location}}/{{name}} +* {{name}} + +Any variables not passed in the import command will be taken from the provider configuration. + +Cloud Dataplex lake 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_dataplex_lake_iam_member.editor "projects/{{project}}/locations/{{location}}/lakes/{{lake}} roles/viewer user:jane@example.com" +``` + +IAM binding imports use space-delimited identifiers: the resource in question and the role, e.g. +``` +$ terraform import google_dataplex_lake_iam_binding.editor "projects/{{project}}/locations/{{location}}/lakes/{{lake}} roles/viewer" +``` + +IAM policy imports use the identifier of the resource in question, e.g. +``` +$ terraform import google_dataplex_lake_iam_policy.editor projects/{{project}}/locations/{{location}}/lakes/{{lake}} +``` + +-> **Custom Roles**: If you're importing a IAM resource with a custom role, make sure to use the + full name of the custom role, e.g. `[projects/my-project|organizations/my-org]/roles/my-custom-role`. + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override). diff --git a/website/docs/r/dataplex_zone_iam.html.markdown b/website/docs/r/dataplex_zone_iam.html.markdown new file mode 100644 index 0000000000..01e12dc20d --- /dev/null +++ b/website/docs/r/dataplex_zone_iam.html.markdown @@ -0,0 +1,151 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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 Dataplex" +description: |- + Collection of resources to manage IAM policy for Cloud Dataplex Zone +--- + +# IAM policy for Cloud Dataplex Zone +Three different resources help you manage your IAM policy for Cloud Dataplex Zone. Each of these resources serves a different use case: + +* `google_dataplex_zone_iam_policy`: Authoritative. Sets the IAM policy for the zone and replaces any existing policy already attached. +* `google_dataplex_zone_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 zone are preserved. +* `google_dataplex_zone_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the zone are preserved. + +~> **Note:** `google_dataplex_zone_iam_policy` **cannot** be used in conjunction with `google_dataplex_zone_iam_binding` and `google_dataplex_zone_iam_member` or they will fight over what your policy should be. + +~> **Note:** `google_dataplex_zone_iam_binding` resources **can be** used in conjunction with `google_dataplex_zone_iam_member` resources **only if** they do not grant privilege to the same role. + + + + +## google\_dataplex\_zone\_iam\_policy + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/viewer" + members = [ + "user:jane@example.com", + ] + } +} + +resource "google_dataplex_zone_iam_policy" "policy" { + project = google_dataplex_zone.example.project + location = google_dataplex_zone.example.location + lake = google_dataplex_zone.example.lake + dataplex_zone = google_dataplex_zone.example.name + policy_data = data.google_iam_policy.admin.policy_data +} +``` + +## google\_dataplex\_zone\_iam\_binding + +```hcl +resource "google_dataplex_zone_iam_binding" "binding" { + project = google_dataplex_zone.example.project + location = google_dataplex_zone.example.location + lake = google_dataplex_zone.example.lake + dataplex_zone = google_dataplex_zone.example.name + role = "roles/viewer" + members = [ + "user:jane@example.com", + ] +} +``` + +## google\_dataplex\_zone\_iam\_member + +```hcl +resource "google_dataplex_zone_iam_member" "member" { + project = google_dataplex_zone.example.project + location = google_dataplex_zone.example.location + lake = google_dataplex_zone.example.lake + dataplex_zone = google_dataplex_zone.example.name + role = "roles/viewer" + member = "user:jane@example.com" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `dataplex_zone` - (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: + * **allUsers**: A special identifier that represents anyone who is on the internet; with or without a Google account. + * **allAuthenticatedUsers**: A special identifier that represents anyone who is authenticated with a Google account or a service account. + * **user:{emailid}**: An email address that represents a specific Google account. For example, alice@gmail.com or joe@example.com. + * **serviceAccount:{emailid}**: An email address that represents a service account. For example, my-other-app@appspot.gserviceaccount.com. + * **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. + * **projectOwner:projectid**: Owners of the given project. For example, "projectOwner:my-example-project" + * **projectEditor:projectid**: Editors of the given project. For example, "projectEditor:my-example-project" + * **projectViewer:projectid**: Viewers of the given project. For example, "projectViewer:my-example-project" + +* `role` - (Required) The role that should be applied. Only one + `google_dataplex_zone_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_dataplex_zone_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 IAM policy. + +## Import + +For all import syntaxes, the "resource in question" can take any of the following forms: + +* projects/{{project}}/locations/{{location}}/lakes/{{lake}}/zones/{{name}} +* {{project}}/{{location}}/{{lake}}/{{name}} +* {{location}}/{{lake}}/{{name}} +* {{name}} + +Any variables not passed in the import command will be taken from the provider configuration. + +Cloud Dataplex zone 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_dataplex_zone_iam_member.editor "projects/{{project}}/locations/{{location}}/lakes/{{lake}}/zones/{{zone}} roles/viewer user:jane@example.com" +``` + +IAM binding imports use space-delimited identifiers: the resource in question and the role, e.g. +``` +$ terraform import google_dataplex_zone_iam_binding.editor "projects/{{project}}/locations/{{location}}/lakes/{{lake}}/zones/{{zone}} roles/viewer" +``` + +IAM policy imports use the identifier of the resource in question, e.g. +``` +$ terraform import google_dataplex_zone_iam_policy.editor projects/{{project}}/locations/{{location}}/lakes/{{lake}}/zones/{{zone}} +``` + +-> **Custom Roles**: If you're importing a IAM resource with a custom role, make sure to use the + full name of the custom role, e.g. `[projects/my-project|organizations/my-org]/roles/my-custom-role`. + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).