From ec39f7c9b65c3e8899386dc287dd14fee6ad9156 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Mon, 10 Oct 2022 22:13:27 +0000 Subject: [PATCH] bq analytics hub - add listing resource (#6564) * bq analytics hub - add listing resource * iam import * change enum to string * CR comments * rebase + CR comments * only if beta * make template Signed-off-by: Modular Magician --- .changelog/6564.txt | 12 + .../iam_bigquery_analytics_hub_listing.go | 238 ++++++ ...ry_analytics_hub_listing_generated_test.go | 311 +++++++ google-beta/provider.go | 10 +- ...resource_bigquery_analytics_hub_listing.go | 768 ++++++++++++++++++ ...ry_analytics_hub_listing_generated_test.go | 115 +++ ...uery_analytics_hub_listing_sweeper_test.go | 128 +++ ...rce_bigquery_analytics_hub_listing_test.go | 67 ++ ...gquery_analytics_hub_listing.html.markdown | 199 +++++ ...ry_analytics_hub_listing_iam.html.markdown | 161 ++++ 10 files changed, 2006 insertions(+), 3 deletions(-) create mode 100644 .changelog/6564.txt create mode 100644 google-beta/iam_bigquery_analytics_hub_listing.go create mode 100644 google-beta/iam_bigquery_analytics_hub_listing_generated_test.go create mode 100644 google-beta/resource_bigquery_analytics_hub_listing.go create mode 100644 google-beta/resource_bigquery_analytics_hub_listing_generated_test.go create mode 100644 google-beta/resource_bigquery_analytics_hub_listing_sweeper_test.go create mode 100644 google-beta/resource_bigquery_analytics_hub_listing_test.go create mode 100644 website/docs/r/bigquery_analytics_hub_listing.html.markdown create mode 100644 website/docs/r/bigquery_analytics_hub_listing_iam.html.markdown diff --git a/.changelog/6564.txt b/.changelog/6564.txt new file mode 100644 index 0000000000..502330e28b --- /dev/null +++ b/.changelog/6564.txt @@ -0,0 +1,12 @@ +```release-note:new-resource +`google_bigquery_analytics_hub_listing` (beta) +``` +```release-note:new-resource +`google_bigquery_analytics_hub_listing_iam_binding` (beta) +``` +```release-note:new-resource +`google_bigquery_analytics_hub_listing_iam_member` (beta) +``` +```release-note:new-resource +`google_bigquery_analytics_hub_listing_iam_policy` (beta) +``` diff --git a/google-beta/iam_bigquery_analytics_hub_listing.go b/google-beta/iam_bigquery_analytics_hub_listing.go new file mode 100644 index 0000000000..9299c7826e --- /dev/null +++ b/google-beta/iam_bigquery_analytics_hub_listing.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 BigqueryAnalyticsHubListingIamSchema = map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "location": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "data_exchange_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "listing_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, +} + +type BigqueryAnalyticsHubListingIamUpdater struct { + project string + location string + dataExchangeId string + listingId string + d TerraformResourceData + Config *Config +} + +func BigqueryAnalyticsHubListingIamUpdaterProducer(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("data_exchange_id"); ok { + values["data_exchange_id"] = v.(string) + } + + if v, ok := d.GetOk("listing_id"); ok { + values["listing_id"] = 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[^/]+)/dataExchanges/(?P[^/]+)/listings/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Get("listing_id").(string)) + if err != nil { + return nil, err + } + + for k, v := range m { + values[k] = v + } + + u := &BigqueryAnalyticsHubListingIamUpdater{ + project: values["project"], + location: values["location"], + dataExchangeId: values["data_exchange_id"], + listingId: values["listing_id"], + 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("data_exchange_id", u.dataExchangeId); err != nil { + return nil, fmt.Errorf("Error setting data_exchange_id: %s", err) + } + if err := d.Set("listing_id", u.GetResourceId()); err != nil { + return nil, fmt.Errorf("Error setting listing_id: %s", err) + } + + return u, nil +} + +func BigqueryAnalyticsHubListingIdParseFunc(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[^/]+)/dataExchanges/(?P[^/]+)/listings/(?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 := &BigqueryAnalyticsHubListingIamUpdater{ + project: values["project"], + location: values["location"], + dataExchangeId: values["data_exchange_id"], + listingId: values["listing_id"], + d: d, + Config: config, + } + if err := d.Set("listing_id", u.GetResourceId()); err != nil { + return fmt.Errorf("Error setting listing_id: %s", err) + } + d.SetId(u.GetResourceId()) + return nil +} + +func (u *BigqueryAnalyticsHubListingIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { + url, err := u.qualifyListingUrl("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, "POST", 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 *BigqueryAnalyticsHubListingIamUpdater) 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.qualifyListingUrl("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 *BigqueryAnalyticsHubListingIamUpdater) qualifyListingUrl(methodIdentifier string) (string, error) { + urlTemplate := fmt.Sprintf("{{BigqueryAnalyticsHubBasePath}}%s:%s", fmt.Sprintf("projects/%s/locations/%s/dataExchanges/%s/listings/%s", u.project, u.location, u.dataExchangeId, u.listingId), methodIdentifier) + url, err := replaceVars(u.d, u.Config, urlTemplate) + if err != nil { + return "", err + } + return url, nil +} + +func (u *BigqueryAnalyticsHubListingIamUpdater) GetResourceId() string { + return fmt.Sprintf("projects/%s/locations/%s/dataExchanges/%s/listings/%s", u.project, u.location, u.dataExchangeId, u.listingId) +} + +func (u *BigqueryAnalyticsHubListingIamUpdater) GetMutexKey() string { + return fmt.Sprintf("iam-bigqueryanalyticshub-listing-%s", u.GetResourceId()) +} + +func (u *BigqueryAnalyticsHubListingIamUpdater) DescribeResource() string { + return fmt.Sprintf("bigqueryanalyticshub listing %q", u.GetResourceId()) +} diff --git a/google-beta/iam_bigquery_analytics_hub_listing_generated_test.go b/google-beta/iam_bigquery_analytics_hub_listing_generated_test.go new file mode 100644 index 0000000000..4b07bd2d4e --- /dev/null +++ b/google-beta/iam_bigquery_analytics_hub_listing_generated_test.go @@ -0,0 +1,311 @@ +// ---------------------------------------------------------------------------- +// +// *** 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 ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccBigqueryAnalyticsHubListingIamBindingGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + "role": "roles/viewer", + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + Steps: []resource.TestStep{ + { + Config: testAccBigqueryAnalyticsHubListingIamBinding_basicGenerated(context), + }, + { + // Test Iam Binding update + Config: testAccBigqueryAnalyticsHubListingIamBinding_updateGenerated(context), + }, + }, + }) +} + +func TestAccBigqueryAnalyticsHubListingIamMemberGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + "role": "roles/viewer", + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + Steps: []resource.TestStep{ + { + // Test Iam Member creation (no update for member, no need to test) + Config: testAccBigqueryAnalyticsHubListingIamMember_basicGenerated(context), + }, + }, + }) +} + +func TestAccBigqueryAnalyticsHubListingIamPolicyGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + "role": "roles/viewer", + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + Steps: []resource.TestStep{ + { + Config: testAccBigqueryAnalyticsHubListingIamPolicy_basicGenerated(context), + }, + { + Config: testAccBigqueryAnalyticsHubListingIamPolicy_emptyBinding(context), + }, + }, + }) +} + +func testAccBigqueryAnalyticsHubListingIamMember_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_bigquery_analytics_hub_data_exchange" "listing" { + provider = google-beta + location = "US" + data_exchange_id = "tf_test_my_data_exchange%{random_suffix}" + display_name = "tf_test_my_data_exchange%{random_suffix}" + description = "example data exchange%{random_suffix}" +} + +resource "google_bigquery_analytics_hub_listing" "listing" { + provider = google-beta + location = "US" + data_exchange_id = google_bigquery_analytics_hub_data_exchange.listing.data_exchange_id + listing_id = "tf_test_my_listing%{random_suffix}" + display_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + + bigquery_dataset { + dataset = google_bigquery_dataset.listing.id + } +} + +resource "google_bigquery_dataset" "listing" { + provider = google-beta + dataset_id = "tf_test_my_listing%{random_suffix}" + friendly_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + location = "US" +} + +resource "google_bigquery_analytics_hub_listing_iam_member" "foo" { + provider = google-beta + project = google_bigquery_analytics_hub_listing.listing.project + location = google_bigquery_analytics_hub_listing.listing.location + data_exchange_id = google_bigquery_analytics_hub_listing.listing.data_exchange_id + listing_id = google_bigquery_analytics_hub_listing.listing.listing_id + role = "%{role}" + member = "user:admin@hashicorptest.com" +} +`, context) +} + +func testAccBigqueryAnalyticsHubListingIamPolicy_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_bigquery_analytics_hub_data_exchange" "listing" { + provider = google-beta + location = "US" + data_exchange_id = "tf_test_my_data_exchange%{random_suffix}" + display_name = "tf_test_my_data_exchange%{random_suffix}" + description = "example data exchange%{random_suffix}" +} + +resource "google_bigquery_analytics_hub_listing" "listing" { + provider = google-beta + location = "US" + data_exchange_id = google_bigquery_analytics_hub_data_exchange.listing.data_exchange_id + listing_id = "tf_test_my_listing%{random_suffix}" + display_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + + bigquery_dataset { + dataset = google_bigquery_dataset.listing.id + } +} + +resource "google_bigquery_dataset" "listing" { + provider = google-beta + dataset_id = "tf_test_my_listing%{random_suffix}" + friendly_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + location = "US" +} + +data "google_iam_policy" "foo" { + provider = google-beta + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + } +} + +resource "google_bigquery_analytics_hub_listing_iam_policy" "foo" { + provider = google-beta + project = google_bigquery_analytics_hub_listing.listing.project + location = google_bigquery_analytics_hub_listing.listing.location + data_exchange_id = google_bigquery_analytics_hub_listing.listing.data_exchange_id + listing_id = google_bigquery_analytics_hub_listing.listing.listing_id + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccBigqueryAnalyticsHubListingIamPolicy_emptyBinding(context map[string]interface{}) string { + return Nprintf(` +resource "google_bigquery_analytics_hub_data_exchange" "listing" { + provider = google-beta + location = "US" + data_exchange_id = "tf_test_my_data_exchange%{random_suffix}" + display_name = "tf_test_my_data_exchange%{random_suffix}" + description = "example data exchange%{random_suffix}" +} + +resource "google_bigquery_analytics_hub_listing" "listing" { + provider = google-beta + location = "US" + data_exchange_id = google_bigquery_analytics_hub_data_exchange.listing.data_exchange_id + listing_id = "tf_test_my_listing%{random_suffix}" + display_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + + bigquery_dataset { + dataset = google_bigquery_dataset.listing.id + } +} + +resource "google_bigquery_dataset" "listing" { + provider = google-beta + dataset_id = "tf_test_my_listing%{random_suffix}" + friendly_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + location = "US" +} + +data "google_iam_policy" "foo" { + provider = google-beta +} + +resource "google_bigquery_analytics_hub_listing_iam_policy" "foo" { + provider = google-beta + project = google_bigquery_analytics_hub_listing.listing.project + location = google_bigquery_analytics_hub_listing.listing.location + data_exchange_id = google_bigquery_analytics_hub_listing.listing.data_exchange_id + listing_id = google_bigquery_analytics_hub_listing.listing.listing_id + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccBigqueryAnalyticsHubListingIamBinding_basicGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_bigquery_analytics_hub_data_exchange" "listing" { + provider = google-beta + location = "US" + data_exchange_id = "tf_test_my_data_exchange%{random_suffix}" + display_name = "tf_test_my_data_exchange%{random_suffix}" + description = "example data exchange%{random_suffix}" +} + +resource "google_bigquery_analytics_hub_listing" "listing" { + provider = google-beta + location = "US" + data_exchange_id = google_bigquery_analytics_hub_data_exchange.listing.data_exchange_id + listing_id = "tf_test_my_listing%{random_suffix}" + display_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + + bigquery_dataset { + dataset = google_bigquery_dataset.listing.id + } +} + +resource "google_bigquery_dataset" "listing" { + provider = google-beta + dataset_id = "tf_test_my_listing%{random_suffix}" + friendly_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + location = "US" +} + +resource "google_bigquery_analytics_hub_listing_iam_binding" "foo" { + provider = google-beta + project = google_bigquery_analytics_hub_listing.listing.project + location = google_bigquery_analytics_hub_listing.listing.location + data_exchange_id = google_bigquery_analytics_hub_listing.listing.data_exchange_id + listing_id = google_bigquery_analytics_hub_listing.listing.listing_id + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} +`, context) +} + +func testAccBigqueryAnalyticsHubListingIamBinding_updateGenerated(context map[string]interface{}) string { + return Nprintf(` +resource "google_bigquery_analytics_hub_data_exchange" "listing" { + provider = google-beta + location = "US" + data_exchange_id = "tf_test_my_data_exchange%{random_suffix}" + display_name = "tf_test_my_data_exchange%{random_suffix}" + description = "example data exchange%{random_suffix}" +} + +resource "google_bigquery_analytics_hub_listing" "listing" { + provider = google-beta + location = "US" + data_exchange_id = google_bigquery_analytics_hub_data_exchange.listing.data_exchange_id + listing_id = "tf_test_my_listing%{random_suffix}" + display_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + + bigquery_dataset { + dataset = google_bigquery_dataset.listing.id + } +} + +resource "google_bigquery_dataset" "listing" { + provider = google-beta + dataset_id = "tf_test_my_listing%{random_suffix}" + friendly_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + location = "US" +} + +resource "google_bigquery_analytics_hub_listing_iam_binding" "foo" { + provider = google-beta + project = google_bigquery_analytics_hub_listing.listing.project + location = google_bigquery_analytics_hub_listing.listing.location + data_exchange_id = google_bigquery_analytics_hub_listing.listing.data_exchange_id + listing_id = google_bigquery_analytics_hub_listing.listing.listing_id + 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 a2dea8dd10..6e4c8c6aa6 100644 --- a/google-beta/provider.go +++ b/google-beta/provider.go @@ -980,9 +980,9 @@ func Provider() *schema.Provider { return provider } -// Generated resources: 268 -// Generated IAM resources: 174 -// Total generated resources: 442 +// Generated resources: 269 +// Generated IAM resources: 177 +// Total generated resources: 446 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -1053,6 +1053,10 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_bigquery_analytics_hub_data_exchange_iam_binding": ResourceIamBinding(BigqueryAnalyticsHubDataExchangeIamSchema, BigqueryAnalyticsHubDataExchangeIamUpdaterProducer, BigqueryAnalyticsHubDataExchangeIdParseFunc), "google_bigquery_analytics_hub_data_exchange_iam_member": ResourceIamMember(BigqueryAnalyticsHubDataExchangeIamSchema, BigqueryAnalyticsHubDataExchangeIamUpdaterProducer, BigqueryAnalyticsHubDataExchangeIdParseFunc), "google_bigquery_analytics_hub_data_exchange_iam_policy": ResourceIamPolicy(BigqueryAnalyticsHubDataExchangeIamSchema, BigqueryAnalyticsHubDataExchangeIamUpdaterProducer, BigqueryAnalyticsHubDataExchangeIdParseFunc), + "google_bigquery_analytics_hub_listing": resourceBigqueryAnalyticsHubListing(), + "google_bigquery_analytics_hub_listing_iam_binding": ResourceIamBinding(BigqueryAnalyticsHubListingIamSchema, BigqueryAnalyticsHubListingIamUpdaterProducer, BigqueryAnalyticsHubListingIdParseFunc), + "google_bigquery_analytics_hub_listing_iam_member": ResourceIamMember(BigqueryAnalyticsHubListingIamSchema, BigqueryAnalyticsHubListingIamUpdaterProducer, BigqueryAnalyticsHubListingIdParseFunc), + "google_bigquery_analytics_hub_listing_iam_policy": ResourceIamPolicy(BigqueryAnalyticsHubListingIamSchema, BigqueryAnalyticsHubListingIamUpdaterProducer, BigqueryAnalyticsHubListingIdParseFunc), "google_bigquery_connection": resourceBigqueryConnectionConnection(), "google_bigquery_connection_iam_binding": ResourceIamBinding(BigqueryConnectionConnectionIamSchema, BigqueryConnectionConnectionIamUpdaterProducer, BigqueryConnectionConnectionIdParseFunc), "google_bigquery_connection_iam_member": ResourceIamMember(BigqueryConnectionConnectionIamSchema, BigqueryConnectionConnectionIamUpdaterProducer, BigqueryConnectionConnectionIdParseFunc), diff --git a/google-beta/resource_bigquery_analytics_hub_listing.go b/google-beta/resource_bigquery_analytics_hub_listing.go new file mode 100644 index 0000000000..c05bf83918 --- /dev/null +++ b/google-beta/resource_bigquery_analytics_hub_listing.go @@ -0,0 +1,768 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "log" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceBigqueryAnalyticsHubListing() *schema.Resource { + return &schema.Resource{ + Create: resourceBigqueryAnalyticsHubListingCreate, + Read: resourceBigqueryAnalyticsHubListingRead, + Update: resourceBigqueryAnalyticsHubListingUpdate, + Delete: resourceBigqueryAnalyticsHubListingDelete, + + Importer: &schema.ResourceImporter{ + State: resourceBigqueryAnalyticsHubListingImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "bigquery_dataset": { + Type: schema.TypeList, + Required: true, + Description: `Shared dataset i.e. BigQuery dataset source.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dataset": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: projectNumberDiffSuppress, + Description: `Resource name of the dataset source for this listing. e.g. projects/myproject/datasets/123`, + }, + }, + }, + }, + "data_exchange_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The ID of the data exchange. Must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping, or characters outside of ASCII, spaces.`, + }, + "display_name": { + Type: schema.TypeString, + Required: true, + Description: `Human-readable display name of the listing. The display name must contain only Unicode letters, numbers (0-9), underscores (_), dashes (-), spaces ( ), ampersands (&) and can't start or end with spaces.`, + }, + "listing_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The ID of the listing. Must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping, or characters outside of ASCII, spaces.`, + }, + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The name of the location this data exchange listing.`, + }, + "categories": { + Type: schema.TypeList, + Optional: true, + Description: `Categories of the listing. Up to two categories are allowed.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "data_provider": { + Type: schema.TypeList, + Optional: true, + Description: `Details of the data provider who owns the source data.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: `Name of the data provider.`, + }, + "primary_contact": { + Type: schema.TypeString, + Optional: true, + Description: `Email or URL of the data provider.`, + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `Short description of the listing. The description must not contain Unicode non-characters and C0 and C1 control codes except tabs (HT), new lines (LF), carriage returns (CR), and page breaks (FF).`, + }, + "documentation": { + Type: schema.TypeString, + Optional: true, + Description: `Documentation describing the listing.`, + }, + "icon": { + Type: schema.TypeString, + Optional: true, + Description: `Base64 encoded image representing the listing.`, + }, + "primary_contact": { + Type: schema.TypeString, + Optional: true, + Description: `Email or URL of the primary point of contact of the listing.`, + }, + "publisher": { + Type: schema.TypeList, + Optional: true, + Description: `Details of the publisher who owns the listing and who can share the source data.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: `Name of the listing publisher.`, + }, + "primary_contact": { + Type: schema.TypeString, + Optional: true, + Description: `Email or URL of the listing publisher.`, + }, + }, + }, + }, + "request_access": { + Type: schema.TypeString, + Optional: true, + Description: `Email or URL of the request access of the listing. Subscribers can use this reference to request access.`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The resource name of the listing. e.g. "projects/myproject/locations/US/dataExchanges/123/listings/456"`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceBigqueryAnalyticsHubListingCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + displayNameProp, err := expandBigqueryAnalyticsHubListingDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + descriptionProp, err := expandBigqueryAnalyticsHubListingDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + primaryContactProp, err := expandBigqueryAnalyticsHubListingPrimaryContact(d.Get("primary_contact"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("primary_contact"); !isEmptyValue(reflect.ValueOf(primaryContactProp)) && (ok || !reflect.DeepEqual(v, primaryContactProp)) { + obj["primaryContact"] = primaryContactProp + } + documentationProp, err := expandBigqueryAnalyticsHubListingDocumentation(d.Get("documentation"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("documentation"); !isEmptyValue(reflect.ValueOf(documentationProp)) && (ok || !reflect.DeepEqual(v, documentationProp)) { + obj["documentation"] = documentationProp + } + iconProp, err := expandBigqueryAnalyticsHubListingIcon(d.Get("icon"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("icon"); !isEmptyValue(reflect.ValueOf(iconProp)) && (ok || !reflect.DeepEqual(v, iconProp)) { + obj["icon"] = iconProp + } + requestAccessProp, err := expandBigqueryAnalyticsHubListingRequestAccess(d.Get("request_access"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("request_access"); !isEmptyValue(reflect.ValueOf(requestAccessProp)) && (ok || !reflect.DeepEqual(v, requestAccessProp)) { + obj["requestAccess"] = requestAccessProp + } + dataProviderProp, err := expandBigqueryAnalyticsHubListingDataProvider(d.Get("data_provider"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("data_provider"); !isEmptyValue(reflect.ValueOf(dataProviderProp)) && (ok || !reflect.DeepEqual(v, dataProviderProp)) { + obj["dataProvider"] = dataProviderProp + } + publisherProp, err := expandBigqueryAnalyticsHubListingPublisher(d.Get("publisher"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("publisher"); !isEmptyValue(reflect.ValueOf(publisherProp)) && (ok || !reflect.DeepEqual(v, publisherProp)) { + obj["publisher"] = publisherProp + } + categoriesProp, err := expandBigqueryAnalyticsHubListingCategories(d.Get("categories"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("categories"); !isEmptyValue(reflect.ValueOf(categoriesProp)) && (ok || !reflect.DeepEqual(v, categoriesProp)) { + obj["categories"] = categoriesProp + } + bigqueryDatasetProp, err := expandBigqueryAnalyticsHubListingBigqueryDataset(d.Get("bigquery_dataset"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("bigquery_dataset"); !isEmptyValue(reflect.ValueOf(bigqueryDatasetProp)) && (ok || !reflect.DeepEqual(v, bigqueryDatasetProp)) { + obj["bigqueryDataset"] = bigqueryDatasetProp + } + + url, err := replaceVars(d, config, "{{BigqueryAnalyticsHubBasePath}}projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings?listing_id={{listing_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Listing: %#v", obj) + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Listing: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "POST", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating Listing: %s", err) + } + if err := d.Set("name", flattenBigqueryAnalyticsHubListingName(res["name"], d, config)); err != nil { + return fmt.Errorf(`Error setting computed identity field "name": %s`, err) + } + + // Store the ID now + id, err := replaceVars(d, config, "projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating Listing %q: %#v", d.Id(), res) + + return resourceBigqueryAnalyticsHubListingRead(d, meta) +} + +func resourceBigqueryAnalyticsHubListingRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{BigqueryAnalyticsHubBasePath}}projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Listing: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequest(config, "GET", billingProject, url, userAgent, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("BigqueryAnalyticsHubListing %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + + if err := d.Set("name", flattenBigqueryAnalyticsHubListingName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("display_name", flattenBigqueryAnalyticsHubListingDisplayName(res["displayName"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("description", flattenBigqueryAnalyticsHubListingDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("primary_contact", flattenBigqueryAnalyticsHubListingPrimaryContact(res["primaryContact"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("documentation", flattenBigqueryAnalyticsHubListingDocumentation(res["documentation"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("icon", flattenBigqueryAnalyticsHubListingIcon(res["icon"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("request_access", flattenBigqueryAnalyticsHubListingRequestAccess(res["requestAccess"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("data_provider", flattenBigqueryAnalyticsHubListingDataProvider(res["dataProvider"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("publisher", flattenBigqueryAnalyticsHubListingPublisher(res["publisher"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("categories", flattenBigqueryAnalyticsHubListingCategories(res["categories"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + if err := d.Set("bigquery_dataset", flattenBigqueryAnalyticsHubListingBigqueryDataset(res["bigqueryDataset"], d, config)); err != nil { + return fmt.Errorf("Error reading Listing: %s", err) + } + + return nil +} + +func resourceBigqueryAnalyticsHubListingUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Listing: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + displayNameProp, err := expandBigqueryAnalyticsHubListingDisplayName(d.Get("display_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, displayNameProp)) { + obj["displayName"] = displayNameProp + } + descriptionProp, err := expandBigqueryAnalyticsHubListingDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + primaryContactProp, err := expandBigqueryAnalyticsHubListingPrimaryContact(d.Get("primary_contact"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("primary_contact"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, primaryContactProp)) { + obj["primaryContact"] = primaryContactProp + } + documentationProp, err := expandBigqueryAnalyticsHubListingDocumentation(d.Get("documentation"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("documentation"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, documentationProp)) { + obj["documentation"] = documentationProp + } + iconProp, err := expandBigqueryAnalyticsHubListingIcon(d.Get("icon"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("icon"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, iconProp)) { + obj["icon"] = iconProp + } + requestAccessProp, err := expandBigqueryAnalyticsHubListingRequestAccess(d.Get("request_access"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("request_access"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, requestAccessProp)) { + obj["requestAccess"] = requestAccessProp + } + dataProviderProp, err := expandBigqueryAnalyticsHubListingDataProvider(d.Get("data_provider"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("data_provider"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, dataProviderProp)) { + obj["dataProvider"] = dataProviderProp + } + publisherProp, err := expandBigqueryAnalyticsHubListingPublisher(d.Get("publisher"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("publisher"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, publisherProp)) { + obj["publisher"] = publisherProp + } + categoriesProp, err := expandBigqueryAnalyticsHubListingCategories(d.Get("categories"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("categories"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, categoriesProp)) { + obj["categories"] = categoriesProp + } + bigqueryDatasetProp, err := expandBigqueryAnalyticsHubListingBigqueryDataset(d.Get("bigquery_dataset"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("bigquery_dataset"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, bigqueryDatasetProp)) { + obj["bigqueryDataset"] = bigqueryDatasetProp + } + + url, err := replaceVars(d, config, "{{BigqueryAnalyticsHubBasePath}}projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Listing %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("display_name") { + updateMask = append(updateMask, "displayName") + } + + if d.HasChange("description") { + updateMask = append(updateMask, "description") + } + + if d.HasChange("primary_contact") { + updateMask = append(updateMask, "primaryContact") + } + + if d.HasChange("documentation") { + updateMask = append(updateMask, "documentation") + } + + if d.HasChange("icon") { + updateMask = append(updateMask, "icon") + } + + if d.HasChange("request_access") { + updateMask = append(updateMask, "requestAccess") + } + + if d.HasChange("data_provider") { + updateMask = append(updateMask, "dataProvider") + } + + if d.HasChange("publisher") { + updateMask = append(updateMask, "publisher") + } + + if d.HasChange("categories") { + updateMask = append(updateMask, "categories") + } + + if d.HasChange("bigquery_dataset") { + updateMask = append(updateMask, "bigqueryDataset") + } + // updateMask is a URL parameter but not present in the schema, so replaceVars + // won't set it + url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "PATCH", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating Listing %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating Listing %q: %#v", d.Id(), res) + } + + return resourceBigqueryAnalyticsHubListingRead(d, meta) +} + +func resourceBigqueryAnalyticsHubListingDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Listing: %s", err) + } + billingProject = project + + url, err := replaceVars(d, config, "{{BigqueryAnalyticsHubBasePath}}projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting Listing %q", d.Id()) + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "DELETE", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "Listing") + } + + log.Printf("[DEBUG] Finished deleting Listing %q: %#v", d.Id(), res) + return nil +} + +func resourceBigqueryAnalyticsHubListingImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/locations/(?P[^/]+)/dataExchanges/(?P[^/]+)/listings/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenBigqueryAnalyticsHubListingName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingDisplayName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingPrimaryContact(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingDocumentation(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingIcon(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingRequestAccess(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingDataProvider(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["name"] = + flattenBigqueryAnalyticsHubListingDataProviderName(original["name"], d, config) + transformed["primary_contact"] = + flattenBigqueryAnalyticsHubListingDataProviderPrimaryContact(original["primaryContact"], d, config) + return []interface{}{transformed} +} +func flattenBigqueryAnalyticsHubListingDataProviderName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingDataProviderPrimaryContact(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingPublisher(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["name"] = + flattenBigqueryAnalyticsHubListingPublisherName(original["name"], d, config) + transformed["primary_contact"] = + flattenBigqueryAnalyticsHubListingPublisherPrimaryContact(original["primaryContact"], d, config) + return []interface{}{transformed} +} +func flattenBigqueryAnalyticsHubListingPublisherName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingPublisherPrimaryContact(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingCategories(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenBigqueryAnalyticsHubListingBigqueryDataset(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["dataset"] = + flattenBigqueryAnalyticsHubListingBigqueryDatasetDataset(original["dataset"], d, config) + return []interface{}{transformed} +} +func flattenBigqueryAnalyticsHubListingBigqueryDatasetDataset(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func expandBigqueryAnalyticsHubListingDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingPrimaryContact(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingDocumentation(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingIcon(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingRequestAccess(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingDataProvider(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedName, err := expandBigqueryAnalyticsHubListingDataProviderName(original["name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) { + transformed["name"] = transformedName + } + + transformedPrimaryContact, err := expandBigqueryAnalyticsHubListingDataProviderPrimaryContact(original["primary_contact"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPrimaryContact); val.IsValid() && !isEmptyValue(val) { + transformed["primaryContact"] = transformedPrimaryContact + } + + return transformed, nil +} + +func expandBigqueryAnalyticsHubListingDataProviderName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingDataProviderPrimaryContact(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingPublisher(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedName, err := expandBigqueryAnalyticsHubListingPublisherName(original["name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) { + transformed["name"] = transformedName + } + + transformedPrimaryContact, err := expandBigqueryAnalyticsHubListingPublisherPrimaryContact(original["primary_contact"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPrimaryContact); val.IsValid() && !isEmptyValue(val) { + transformed["primaryContact"] = transformedPrimaryContact + } + + return transformed, nil +} + +func expandBigqueryAnalyticsHubListingPublisherName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingPublisherPrimaryContact(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingCategories(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandBigqueryAnalyticsHubListingBigqueryDataset(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedDataset, err := expandBigqueryAnalyticsHubListingBigqueryDatasetDataset(original["dataset"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDataset); val.IsValid() && !isEmptyValue(val) { + transformed["dataset"] = transformedDataset + } + + return transformed, nil +} + +func expandBigqueryAnalyticsHubListingBigqueryDatasetDataset(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google-beta/resource_bigquery_analytics_hub_listing_generated_test.go b/google-beta/resource_bigquery_analytics_hub_listing_generated_test.go new file mode 100644 index 0000000000..a918fed8a6 --- /dev/null +++ b/google-beta/resource_bigquery_analytics_hub_listing_generated_test.go @@ -0,0 +1,115 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccBigqueryAnalyticsHubListing_bigqueryAnalyticshubListingBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + CheckDestroy: testAccCheckBigqueryAnalyticsHubListingDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccBigqueryAnalyticsHubListing_bigqueryAnalyticshubListingBasicExample(context), + }, + { + ResourceName: "google_bigquery_analytics_hub_listing.listing", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"data_exchange_id", "listing_id", "location"}, + }, + }, + }) +} + +func testAccBigqueryAnalyticsHubListing_bigqueryAnalyticshubListingBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_bigquery_analytics_hub_data_exchange" "listing" { + provider = google-beta + location = "US" + data_exchange_id = "tf_test_my_data_exchange%{random_suffix}" + display_name = "tf_test_my_data_exchange%{random_suffix}" + description = "example data exchange%{random_suffix}" +} + +resource "google_bigquery_analytics_hub_listing" "listing" { + provider = google-beta + location = "US" + data_exchange_id = google_bigquery_analytics_hub_data_exchange.listing.data_exchange_id + listing_id = "tf_test_my_listing%{random_suffix}" + display_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + + bigquery_dataset { + dataset = google_bigquery_dataset.listing.id + } +} + +resource "google_bigquery_dataset" "listing" { + provider = google-beta + dataset_id = "tf_test_my_listing%{random_suffix}" + friendly_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + location = "US" +} +`, context) +} + +func testAccCheckBigqueryAnalyticsHubListingDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_bigquery_analytics_hub_listing" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + url, err := replaceVarsForTest(config, rs, "{{BigqueryAnalyticsHubBasePath}}projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = sendRequest(config, "GET", billingProject, url, config.userAgent, nil) + if err == nil { + return fmt.Errorf("BigqueryAnalyticsHubListing still exists at %s", url) + } + } + + return nil + } +} diff --git a/google-beta/resource_bigquery_analytics_hub_listing_sweeper_test.go b/google-beta/resource_bigquery_analytics_hub_listing_sweeper_test.go new file mode 100644 index 0000000000..1ab7d75129 --- /dev/null +++ b/google-beta/resource_bigquery_analytics_hub_listing_sweeper_test.go @@ -0,0 +1,128 @@ +// ---------------------------------------------------------------------------- +// +// *** 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 ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func init() { + resource.AddTestSweepers("BigqueryAnalyticsHubListing", &resource.Sweeper{ + Name: "BigqueryAnalyticsHubListing", + F: testSweepBigqueryAnalyticsHubListing, + }) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepBigqueryAnalyticsHubListing(region string) error { + resourceName := "BigqueryAnalyticsHubListing" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := getTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://analyticshub.googleapis.com/v1beta1/projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings", "?")[0] + listUrl, err := replaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := sendRequest(config, "GET", config.Project, listUrl, config.userAgent, nil) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["listings"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + var name string + // Id detected in the delete URL, attempt to use id. + if obj["id"] != nil { + name = GetResourceNameFromSelfLink(obj["id"].(string)) + } else if obj["name"] != nil { + name = GetResourceNameFromSelfLink(obj["name"].(string)) + } else { + log.Printf("[INFO][SWEEPER_LOG] %s resource name and id were nil", resourceName) + return nil + } + // Skip resources that shouldn't be sweeped + if !isSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://analyticshub.googleapis.com/v1beta1/projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}}" + deleteUrl, err := replaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = sendRequest(config, "DELETE", config.Project, deleteUrl, config.userAgent, nil) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/google-beta/resource_bigquery_analytics_hub_listing_test.go b/google-beta/resource_bigquery_analytics_hub_listing_test.go new file mode 100644 index 0000000000..2fcf1c8f13 --- /dev/null +++ b/google-beta/resource_bigquery_analytics_hub_listing_test.go @@ -0,0 +1,67 @@ +package google + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccBigqueryAnalyticsHubListing_bigqueryAnalyticshubListingUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + CheckDestroy: testAccCheckBigqueryAnalyticsHubListingDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccBigqueryAnalyticsHubListing_bigqueryAnalyticshubListingBasicExample(context), + }, + { + ResourceName: "google_bigquery_analytics_hub_listing.listing", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBigqueryAnalyticsHubListing_bigqueryAnalyticshubListingUpdate(context), + }, + }, + }) +} + +func testAccBigqueryAnalyticsHubListing_bigqueryAnalyticshubListingUpdate(context map[string]interface{}) string { + return Nprintf(` +resource "google_bigquery_analytics_hub_data_exchange" "listing" { + provider = google-beta + location = "US" + data_exchange_id = "tf_test_my_data_exchange%{random_suffix}" + display_name = "tf_test_my_data_exchange%{random_suffix}" + description = "example data exchange%{random_suffix}" +} + +resource "google_bigquery_analytics_hub_listing" "listing" { + provider = google-beta + location = "US" + data_exchange_id = google_bigquery_analytics_hub_data_exchange.listing.data_exchange_id + listing_id = "tf_test_my_listing%{random_suffix}" + display_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange update%{random_suffix}" + + bigquery_dataset { + dataset = google_bigquery_dataset.listing.id + } +} + +resource "google_bigquery_dataset" "listing" { + provider = google-beta + dataset_id = "tf_test_my_listing%{random_suffix}" + friendly_name = "tf_test_my_listing%{random_suffix}" + description = "example data exchange%{random_suffix}" + location = "US" +} +`, context) +} diff --git a/website/docs/r/bigquery_analytics_hub_listing.html.markdown b/website/docs/r/bigquery_analytics_hub_listing.html.markdown new file mode 100644 index 0000000000..8b43ff280d --- /dev/null +++ b/website/docs/r/bigquery_analytics_hub_listing.html.markdown @@ -0,0 +1,199 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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: "Bigquery Analytics Hub" +page_title: "Google: google_bigquery_analytics_hub_listing" +description: |- + A Bigquery Analytics Hub data exchange listing +--- + +# google\_bigquery\_analytics\_hub\_listing + +A Bigquery Analytics Hub data exchange listing + +~> **Warning:** This resource is in beta, and should be used with the terraform-provider-google-beta provider. +See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. + +To get more information about Listing, see: + +* [API documentation](https://cloud.google.com/bigquery/docs/reference/analytics-hub/rest/v1beta1/projects.locations.dataExchanges.listings) +* How-to Guides + * [Official Documentation](https://cloud.google.com/bigquery/docs/analytics-hub-introduction) + + +## Example Usage - Bigquery Analyticshub Listing Basic + + +```hcl +resource "google_bigquery_analytics_hub_data_exchange" "listing" { + provider = google-beta + location = "US" + data_exchange_id = "my_data_exchange" + display_name = "my_data_exchange" + description = "example data exchange" +} + +resource "google_bigquery_analytics_hub_listing" "listing" { + provider = google-beta + location = "US" + data_exchange_id = google_bigquery_analytics_hub_data_exchange.listing.data_exchange_id + listing_id = "my_listing" + display_name = "my_listing" + description = "example data exchange" + + bigquery_dataset { + dataset = google_bigquery_dataset.listing.id + } +} + +resource "google_bigquery_dataset" "listing" { + provider = google-beta + dataset_id = "my_listing" + friendly_name = "my_listing" + description = "example data exchange" + location = "US" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `data_exchange_id` - + (Required) + The ID of the data exchange. Must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping, or characters outside of ASCII, spaces. + +* `listing_id` - + (Required) + The ID of the listing. Must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping, or characters outside of ASCII, spaces. + +* `location` - + (Required) + The name of the location this data exchange listing. + +* `display_name` - + (Required) + Human-readable display name of the listing. The display name must contain only Unicode letters, numbers (0-9), underscores (_), dashes (-), spaces ( ), ampersands (&) and can't start or end with spaces. + +* `bigquery_dataset` - + (Required) + Shared dataset i.e. BigQuery dataset source. + Structure is [documented below](#nested_bigquery_dataset). + + +The `bigquery_dataset` block supports: + +* `dataset` - + (Required) + Resource name of the dataset source for this listing. e.g. projects/myproject/datasets/123 + +- - - + + +* `description` - + (Optional) + Short description of the listing. The description must not contain Unicode non-characters and C0 and C1 control codes except tabs (HT), new lines (LF), carriage returns (CR), and page breaks (FF). + +* `primary_contact` - + (Optional) + Email or URL of the primary point of contact of the listing. + +* `documentation` - + (Optional) + Documentation describing the listing. + +* `icon` - + (Optional) + Base64 encoded image representing the listing. + +* `request_access` - + (Optional) + Email or URL of the request access of the listing. Subscribers can use this reference to request access. + +* `data_provider` - + (Optional) + Details of the data provider who owns the source data. + Structure is [documented below](#nested_data_provider). + +* `publisher` - + (Optional) + Details of the publisher who owns the listing and who can share the source data. + Structure is [documented below](#nested_publisher). + +* `categories` - + (Optional) + Categories of the listing. Up to two categories are allowed. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `data_provider` block supports: + +* `name` - + (Required) + Name of the data provider. + +* `primary_contact` - + (Optional) + Email or URL of the data provider. + +The `publisher` block supports: + +* `name` - + (Required) + Name of the listing publisher. + +* `primary_contact` - + (Optional) + Email or URL of the listing publisher. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}}` + +* `name` - + The resource name of the listing. e.g. "projects/myproject/locations/US/dataExchanges/123/listings/456" + + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. +- `delete` - Default is 20 minutes. + +## Import + + +Listing can be imported using any of these accepted formats: + +``` +$ terraform import google_bigquery_analytics_hub_listing.default projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}} +$ terraform import google_bigquery_analytics_hub_listing.default {{project}}/{{location}}/{{data_exchange_id}}/{{listing_id}} +$ terraform import google_bigquery_analytics_hub_listing.default {{location}}/{{data_exchange_id}}/{{listing_id}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override). diff --git a/website/docs/r/bigquery_analytics_hub_listing_iam.html.markdown b/website/docs/r/bigquery_analytics_hub_listing_iam.html.markdown new file mode 100644 index 0000000000..6c28250d5c --- /dev/null +++ b/website/docs/r/bigquery_analytics_hub_listing_iam.html.markdown @@ -0,0 +1,161 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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: "Bigquery Analytics Hub" +page_title: "Google: google_bigquery_analytics_hub_listing_iam" +description: |- + Collection of resources to manage IAM policy for Bigquery Analytics Hub Listing +--- + +# IAM policy for Bigquery Analytics Hub Listing +Three different resources help you manage your IAM policy for Bigquery Analytics Hub Listing. Each of these resources serves a different use case: + +* `google_bigquery_analytics_hub_listing_iam_policy`: Authoritative. Sets the IAM policy for the listing and replaces any existing policy already attached. +* `google_bigquery_analytics_hub_listing_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 listing are preserved. +* `google_bigquery_analytics_hub_listing_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the listing are preserved. + +~> **Note:** `google_bigquery_analytics_hub_listing_iam_policy` **cannot** be used in conjunction with `google_bigquery_analytics_hub_listing_iam_binding` and `google_bigquery_analytics_hub_listing_iam_member` or they will fight over what your policy should be. + +~> **Note:** `google_bigquery_analytics_hub_listing_iam_binding` resources **can be** used in conjunction with `google_bigquery_analytics_hub_listing_iam_member` resources **only if** they do not grant privilege to the same role. + + +~> **Warning:** This resource is in beta, and should be used with the terraform-provider-google-beta provider. +See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. + + +## google\_bigquery\_analytics\_hub\_listing\_iam\_policy + +```hcl +data "google_iam_policy" "admin" { + provider = google-beta + binding { + role = "roles/viewer" + members = [ + "user:jane@example.com", + ] + } +} + +resource "google_bigquery_analytics_hub_listing_iam_policy" "policy" { + provider = google-beta + project = google_bigquery_analytics_hub_listing.listing.project + location = google_bigquery_analytics_hub_listing.listing.location + data_exchange_id = google_bigquery_analytics_hub_listing.listing.data_exchange_id + listing_id = google_bigquery_analytics_hub_listing.listing.listing_id + policy_data = data.google_iam_policy.admin.policy_data +} +``` + +## google\_bigquery\_analytics\_hub\_listing\_iam\_binding + +```hcl +resource "google_bigquery_analytics_hub_listing_iam_binding" "binding" { + provider = google-beta + project = google_bigquery_analytics_hub_listing.listing.project + location = google_bigquery_analytics_hub_listing.listing.location + data_exchange_id = google_bigquery_analytics_hub_listing.listing.data_exchange_id + listing_id = google_bigquery_analytics_hub_listing.listing.listing_id + role = "roles/viewer" + members = [ + "user:jane@example.com", + ] +} +``` + +## google\_bigquery\_analytics\_hub\_listing\_iam\_member + +```hcl +resource "google_bigquery_analytics_hub_listing_iam_member" "member" { + provider = google-beta + project = google_bigquery_analytics_hub_listing.listing.project + location = google_bigquery_analytics_hub_listing.listing.location + data_exchange_id = google_bigquery_analytics_hub_listing.listing.data_exchange_id + listing_id = google_bigquery_analytics_hub_listing.listing.listing_id + role = "roles/viewer" + member = "user:jane@example.com" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `data_exchange_id` - (Required) The ID of the data exchange. Must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping, or characters outside of ASCII, spaces. Used to find the parent resource to bind the IAM policy to +* `listing_id` - (Required) The ID of the listing. Must contain only Unicode letters, numbers (0-9), underscores (_). Should not use characters that require URL-escaping, or characters outside of ASCII, spaces. Used to find the parent resource to bind the IAM policy to +* `location` - (Required) The name of the location this data exchange listing. + 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_bigquery_analytics_hub_listing_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_bigquery_analytics_hub_listing_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}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}} +* {{project}}/{{location}}/{{data_exchange_id}}/{{listing_id}} +* {{location}}/{{data_exchange_id}}/{{listing_id}} +* {{listing_id}} + +Any variables not passed in the import command will be taken from the provider configuration. + +Bigquery Analytics Hub listing 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_bigquery_analytics_hub_listing_iam_member.editor "projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}} 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_bigquery_analytics_hub_listing_iam_binding.editor "projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}} roles/viewer" +``` + +IAM policy imports use the identifier of the resource in question, e.g. +``` +$ terraform import google_bigquery_analytics_hub_listing_iam_policy.editor projects/{{project}}/locations/{{location}}/dataExchanges/{{data_exchange_id}}/listings/{{listing_id}} +``` + +-> **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://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override).