diff --git a/.changelog/8670.txt b/.changelog/8670.txt new file mode 100644 index 0000000000..8ec013c069 --- /dev/null +++ b/.changelog/8670.txt @@ -0,0 +1,3 @@ +```release-note:none + +``` diff --git a/google-beta/fwmodels/provider_model.go b/google-beta/fwmodels/provider_model.go index 7f795842cf..33a715fd55 100644 --- a/google-beta/fwmodels/provider_model.go +++ b/google-beta/fwmodels/provider_model.go @@ -22,6 +22,7 @@ type ProviderModel struct { UserProjectOverride types.Bool `tfsdk:"user_project_override"` RequestTimeout types.String `tfsdk:"request_timeout"` RequestReason types.String `tfsdk:"request_reason"` + DefaultLabels types.Map `tfsdk:"default_labels"` // Generated Products AccessApprovalCustomEndpoint types.String `tfsdk:"access_approval_custom_endpoint"` diff --git a/google-beta/fwprovider/framework_provider.go b/google-beta/fwprovider/framework_provider.go index 4be00cdc0a..62c7fd521e 100644 --- a/google-beta/fwprovider/framework_provider.go +++ b/google-beta/fwprovider/framework_provider.go @@ -112,6 +112,10 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, "request_reason": schema.StringAttribute{ Optional: true, }, + "default_labels": schema.MapAttribute{ + Optional: true, + ElementType: types.StringType, + }, // Generated Products "access_approval_custom_endpoint": &schema.StringAttribute{ diff --git a/google-beta/provider/provider.go b/google-beta/provider/provider.go index b9f4e85e33..f8e90c57d0 100644 --- a/google-beta/provider/provider.go +++ b/google-beta/provider/provider.go @@ -235,6 +235,12 @@ func Provider() *schema.Provider { Optional: true, }, + "default_labels": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + // Generated Products "access_approval_custom_endpoint": { Type: schema.TypeString, @@ -1923,6 +1929,13 @@ func ProviderConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.Scopes[i] = scope.(string) } + config.DefaultLabels = make(map[string]string) + defaultLabels := d.Get("default_labels").(map[string]interface{}) + + for k, v := range defaultLabels { + config.DefaultLabels[k] = v.(string) + } + batchCfg, err := transport_tpg.ExpandProviderBatchingConfig(d.Get("batching")) if err != nil { return nil, diag.FromErr(err) diff --git a/google-beta/services/bigquery/resource_bigquery_dataset.go b/google-beta/services/bigquery/resource_bigquery_dataset.go index 41920149a6..8e48f7f564 100644 --- a/google-beta/services/bigquery/resource_bigquery_dataset.go +++ b/google-beta/services/bigquery/resource_bigquery_dataset.go @@ -77,6 +77,7 @@ func ResourceBigQueryDataset() *schema.Resource { }, CustomizeDiff: customdiff.All( + tpgresource.SetTerraformLabelsDiff, tpgresource.DefaultProviderProject, ), @@ -256,6 +257,13 @@ epoch.`, Description: `The date when this dataset or any of its tables was last modified, in milliseconds since the epoch.`, }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "delete_contents_on_destroy": { Type: schema.TypeBool, Optional: true, @@ -480,12 +488,6 @@ func resourceBigQueryDatasetCreate(d *schema.ResourceData, meta interface{}) err } else if v, ok := d.GetOkExists("friendly_name"); ok || !reflect.DeepEqual(v, friendlyNameProp) { obj["friendlyName"] = friendlyNameProp } - labelsProp, err := expandBigQueryDatasetLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } locationProp, err := expandBigQueryDatasetLocation(d.Get("location"), d, config) if err != nil { return err @@ -516,6 +518,12 @@ func resourceBigQueryDatasetCreate(d *schema.ResourceData, meta interface{}) err } else if v, ok := d.GetOkExists("storage_billing_model"); !tpgresource.IsEmptyValue(reflect.ValueOf(storageBillingModelProp)) && (ok || !reflect.DeepEqual(v, storageBillingModelProp)) { obj["storageBillingModel"] = storageBillingModelProp } + labelsProp, err := expandBigQueryDatasetTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{BigQueryBasePath}}projects/{{project}}/datasets") if err != nil { @@ -667,6 +675,9 @@ func resourceBigQueryDatasetRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("storage_billing_model", flattenBigQueryDatasetStorageBillingModel(res["storageBillingModel"], d, config)); err != nil { return fmt.Errorf("Error reading Dataset: %s", err) } + if err := d.Set("terraform_labels", flattenBigQueryDatasetTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading Dataset: %s", err) + } if err := d.Set("effective_labels", flattenBigQueryDatasetEffectiveLabels(res["labels"], d, config)); err != nil { return fmt.Errorf("Error reading Dataset: %s", err) } @@ -735,12 +746,6 @@ func resourceBigQueryDatasetUpdate(d *schema.ResourceData, meta interface{}) err } else if v, ok := d.GetOkExists("friendly_name"); ok || !reflect.DeepEqual(v, friendlyNameProp) { obj["friendlyName"] = friendlyNameProp } - labelsProp, err := expandBigQueryDatasetLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } locationProp, err := expandBigQueryDatasetLocation(d.Get("location"), d, config) if err != nil { return err @@ -771,6 +776,12 @@ func resourceBigQueryDatasetUpdate(d *schema.ResourceData, meta interface{}) err } else if v, ok := d.GetOkExists("storage_billing_model"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, storageBillingModelProp)) { obj["storageBillingModel"] = storageBillingModelProp } + labelsProp, err := expandBigQueryDatasetTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{BigQueryBasePath}}projects/{{project}}/datasets/{{dataset_id}}") if err != nil { @@ -1173,6 +1184,21 @@ func flattenBigQueryDatasetStorageBillingModel(v interface{}, d *schema.Resource return v } +func flattenBigQueryDatasetTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + func flattenBigQueryDatasetEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { return v } @@ -1459,17 +1485,6 @@ func expandBigQueryDatasetFriendlyName(v interface{}, d tpgresource.TerraformRes return v, nil } -func expandBigQueryDatasetLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { - if v == nil { - return map[string]string{}, nil - } - m := make(map[string]string) - for k, val := range v.(map[string]interface{}) { - m[k] = val.(string) - } - return m, nil -} - func expandBigQueryDatasetLocation(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -1508,3 +1523,14 @@ func expandBigQueryDatasetDefaultCollation(v interface{}, d tpgresource.Terrafor func expandBigQueryDatasetStorageBillingModel(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } + +func expandBigQueryDatasetTerraformLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} diff --git a/google-beta/services/bigquery/resource_bigquery_dataset_generated_test.go b/google-beta/services/bigquery/resource_bigquery_dataset_generated_test.go index 0dc61c5456..14389b6e44 100644 --- a/google-beta/services/bigquery/resource_bigquery_dataset_generated_test.go +++ b/google-beta/services/bigquery/resource_bigquery_dataset_generated_test.go @@ -50,7 +50,7 @@ func TestAccBigQueryDataset_bigqueryDatasetBasicExample(t *testing.T) { ResourceName: "google_bigquery_dataset.dataset", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) @@ -105,7 +105,7 @@ func TestAccBigQueryDataset_bigqueryDatasetWithMaxTimeTravelHoursExample(t *test ResourceName: "google_bigquery_dataset.dataset", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) @@ -161,7 +161,7 @@ func TestAccBigQueryDataset_bigqueryDatasetAuthorizedDatasetExample(t *testing.T ResourceName: "google_bigquery_dataset.dataset", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) @@ -249,7 +249,7 @@ func TestAccBigQueryDataset_bigqueryDatasetAuthorizedRoutineExample(t *testing.T ResourceName: "google_bigquery_dataset.private", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) @@ -317,7 +317,7 @@ func TestAccBigQueryDataset_bigqueryDatasetCaseInsensitiveNamesExample(t *testin ResourceName: "google_bigquery_dataset.dataset", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) @@ -373,7 +373,7 @@ func TestAccBigQueryDataset_bigqueryDatasetDefaultCollationSetExample(t *testing ResourceName: "google_bigquery_dataset.dataset", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) diff --git a/google-beta/services/bigquery/resource_bigquery_dataset_test.go b/google-beta/services/bigquery/resource_bigquery_dataset_test.go index 38207b9115..17b2966033 100644 --- a/google-beta/services/bigquery/resource_bigquery_dataset_test.go +++ b/google-beta/services/bigquery/resource_bigquery_dataset_test.go @@ -53,7 +53,7 @@ func TestAccBigQueryDataset_basic(t *testing.T) { ImportStateVerify: true, // The labels field in the state is decided by the configuration. // During importing, the configuration is unavailable, so the labels field in the state after importing is empty. - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, { Config: testAccBigQueryDatasetUpdated(datasetID), @@ -71,7 +71,7 @@ func TestAccBigQueryDataset_basic(t *testing.T) { ResourceName: "google_bigquery_dataset.test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, { Config: testAccBigQueryDatasetUpdated2(datasetID), @@ -80,7 +80,7 @@ func TestAccBigQueryDataset_basic(t *testing.T) { ResourceName: "google_bigquery_dataset.test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, { Config: testAccBigQueryDataset_withoutLabels(datasetID), @@ -158,7 +158,7 @@ func TestAccBigQueryDataset_datasetWithContents(t *testing.T) { ResourceName: "google_bigquery_dataset.contents_test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"delete_contents_on_destroy", "labels"}, + ImportStateVerifyIgnore: []string{"delete_contents_on_destroy", "labels", "terraform_labels"}, }, }, }) @@ -183,7 +183,7 @@ func TestAccBigQueryDataset_access(t *testing.T) { ResourceName: "google_bigquery_dataset.access_test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, { Config: testAccBigQueryDatasetWithTwoAccess(datasetID), @@ -192,7 +192,7 @@ func TestAccBigQueryDataset_access(t *testing.T) { ResourceName: "google_bigquery_dataset.access_test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, { Config: testAccBigQueryDatasetWithOneAccess(datasetID), @@ -201,7 +201,7 @@ func TestAccBigQueryDataset_access(t *testing.T) { ResourceName: "google_bigquery_dataset.access_test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, { Config: testAccBigQueryDatasetWithViewAccess(datasetID, otherDatasetID, otherTableID), @@ -210,7 +210,7 @@ func TestAccBigQueryDataset_access(t *testing.T) { ResourceName: "google_bigquery_dataset.access_test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) @@ -233,7 +233,7 @@ func TestAccBigQueryDataset_regionalLocation(t *testing.T) { ResourceName: "google_bigquery_dataset.test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) @@ -279,7 +279,7 @@ func TestAccBigQueryDataset_storageBillModel(t *testing.T) { ResourceName: "google_bigquery_dataset.test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) diff --git a/google-beta/services/compute/resource_compute_address.go b/google-beta/services/compute/resource_compute_address.go index 8966fa1cf1..1b9db6f774 100644 --- a/google-beta/services/compute/resource_compute_address.go +++ b/google-beta/services/compute/resource_compute_address.go @@ -49,6 +49,7 @@ func ResourceComputeAddress() *schema.Resource { }, CustomizeDiff: customdiff.All( + tpgresource.SetTerraformLabelsDiff, tpgresource.DefaultProviderProject, ), @@ -204,6 +205,13 @@ GCE_ENDPOINT/DNS_RESOLVER purposes.`, Description: `The fingerprint used for optimistic locking of this resource. Used internally during updates.`, }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "users": { Type: schema.TypeList, Computed: true, @@ -277,12 +285,6 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro } else if v, ok := d.GetOkExists("subnetwork"); !tpgresource.IsEmptyValue(reflect.ValueOf(subnetworkProp)) && (ok || !reflect.DeepEqual(v, subnetworkProp)) { obj["subnetwork"] = subnetworkProp } - labelsProp, err := expandComputeAddressLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeAddressLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err @@ -313,6 +315,12 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro } else if v, ok := d.GetOkExists("ipv6_endpoint_type"); !tpgresource.IsEmptyValue(reflect.ValueOf(ipv6EndpointTypeProp)) && (ok || !reflect.DeepEqual(v, ipv6EndpointTypeProp)) { obj["ipv6EndpointType"] = ipv6EndpointTypeProp } + labelsProp, err := expandComputeAddressTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } regionProp, err := expandComputeAddressRegion(d.Get("region"), d, config) if err != nil { return err @@ -369,7 +377,8 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("Error waiting to create Address: %s", err) } - if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + labels := d.Get("labels") // Labels cannot be set in a create. We'll have to set them here. err = resourceComputeAddressRead(d, meta) if err != nil { @@ -377,8 +386,8 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro } obj := make(map[string]interface{}) - // d.Get("labels") will have been overridden by the Read call. - labelsProp, err := expandComputeAddressLabels(v, d, config) + // d.Get("terraform_labels") will have been overridden by the Read call. + labelsProp, err := expandComputeAddressTerraformLabels(v, d, config) if err != nil { return err } @@ -411,9 +420,14 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro } // Set back the labels field, as it is needed to decide the value of "labels" in the state in the read function. - if err := d.Set("labels", v); err != nil { + if err := d.Set("labels", labels); err != nil { return fmt.Errorf("Error setting back labels: %s", err) } + + // Set back the terraform_labels field, as it is needed to decide the value of "terraform_labels" in the state in the read function. + if err := d.Set("terraform_labels", v); err != nil { + return fmt.Errorf("Error setting back terraform_labels: %s", err) + } } log.Printf("[DEBUG] Finished creating Address %q: %#v", d.Id(), res) @@ -506,6 +520,9 @@ func resourceComputeAddressRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("ipv6_endpoint_type", flattenComputeAddressIpv6EndpointType(res["ipv6EndpointType"], d, config)); err != nil { return fmt.Errorf("Error reading Address: %s", err) } + if err := d.Set("terraform_labels", flattenComputeAddressTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading Address: %s", err) + } if err := d.Set("effective_labels", flattenComputeAddressEffectiveLabels(res["labels"], d, config)); err != nil { return fmt.Errorf("Error reading Address: %s", err) } @@ -536,21 +553,21 @@ func resourceComputeAddressUpdate(d *schema.ResourceData, meta interface{}) erro d.Partial(true) - if d.HasChange("labels") || d.HasChange("label_fingerprint") { + if d.HasChange("label_fingerprint") || d.HasChange("terraform_labels") { obj := make(map[string]interface{}) - labelsProp, err := expandComputeAddressLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeAddressLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("label_fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelFingerprintProp)) { obj["labelFingerprint"] = labelFingerprintProp } + labelsProp, err := expandComputeAddressTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/addresses/{{name}}/setLabels") if err != nil { @@ -758,6 +775,21 @@ func flattenComputeAddressIpv6EndpointType(v interface{}, d *schema.ResourceData return v } +func flattenComputeAddressTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + func flattenComputeAddressEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { return v } @@ -801,17 +833,6 @@ func expandComputeAddressSubnetwork(v interface{}, d tpgresource.TerraformResour return f.RelativeLink(), nil } -func expandComputeAddressLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { - if v == nil { - return map[string]string{}, nil - } - m := make(map[string]string) - for k, val := range v.(map[string]interface{}) { - m[k] = val.(string) - } - return m, nil -} - func expandComputeAddressLabelFingerprint(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -836,6 +857,17 @@ func expandComputeAddressIpv6EndpointType(v interface{}, d tpgresource.Terraform return v, nil } +func expandComputeAddressTerraformLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} + func expandComputeAddressRegion(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { f, err := tpgresource.ParseGlobalFieldValue("regions", v.(string), "project", d, config, true) if err != nil { diff --git a/google-beta/services/compute/resource_compute_address_generated_test.go b/google-beta/services/compute/resource_compute_address_generated_test.go index 8cdaacbfa2..51d8ae13c7 100644 --- a/google-beta/services/compute/resource_compute_address_generated_test.go +++ b/google-beta/services/compute/resource_compute_address_generated_test.go @@ -49,7 +49,7 @@ func TestAccComputeAddress_addressBasicExample(t *testing.T) { ResourceName: "google_compute_address.ip_address", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "region"}, + ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "terraform_labels", "region"}, }, }, }) @@ -82,7 +82,7 @@ func TestAccComputeAddress_addressWithSubnetworkExample(t *testing.T) { ResourceName: "google_compute_address.internal_with_subnet_and_address", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "region"}, + ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "terraform_labels", "region"}, }, }, }) @@ -130,7 +130,7 @@ func TestAccComputeAddress_addressWithGceEndpointExample(t *testing.T) { ResourceName: "google_compute_address.internal_with_gce_endpoint", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "region"}, + ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "terraform_labels", "region"}, }, }, }) @@ -165,7 +165,7 @@ func TestAccComputeAddress_addressWithSharedLoadbalancerVipExample(t *testing.T) ResourceName: "google_compute_address.internal_with_shared_loadbalancer_vip", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "region"}, + ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "terraform_labels", "region"}, }, }, }) @@ -200,7 +200,7 @@ func TestAccComputeAddress_instanceWithIpExample(t *testing.T) { ResourceName: "google_compute_address.static", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "region"}, + ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "terraform_labels", "region"}, }, }, }) @@ -257,7 +257,7 @@ func TestAccComputeAddress_computeAddressIpsecInterconnectExample(t *testing.T) ResourceName: "google_compute_address.ipsec-interconnect-address", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "region"}, + ImportStateVerifyIgnore: []string{"subnetwork", "labels", "network", "terraform_labels", "region"}, }, }, }) diff --git a/google-beta/services/compute/resource_compute_address_test.go b/google-beta/services/compute/resource_compute_address_test.go index d9bc79a547..a6c5963309 100644 --- a/google-beta/services/compute/resource_compute_address_test.go +++ b/google-beta/services/compute/resource_compute_address_test.go @@ -97,7 +97,7 @@ func TestAccComputeAddress_networkTier_withLabels(t *testing.T) { ImportStateVerify: true, // The labels field in the state is decided by the configuration. // During importing, the configuration is unavailable, so the labels field in the state after importing is empty. - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, { Config: testAccComputeAddress_networkTier_withLabelsUpdate(acctest.RandString(t, 10)), @@ -115,7 +115,7 @@ func TestAccComputeAddress_networkTier_withLabels(t *testing.T) { ResourceName: "google_compute_address.foobar", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, { Config: testAccComputeAddress_networkTier(acctest.RandString(t, 10)), @@ -172,6 +172,121 @@ func TestAccComputeAddress_networkTier_withProvider5(t *testing.T) { }) } +func TestAccComputeAddress_withProviderDefaultLabels(t *testing.T) { + // The test failed if VCR testing is enabled, because the cached provider config is used. + // With the cached provider config, any changes in the provider default labels will not be applied. + acctest.SkipIfVcr(t) + t.Parallel() + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeAddressDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeAddress_withProviderDefaultLabels(acctest.RandString(t, 10)), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.%", "2"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.env", "foo"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.default_expiration_ms", "3600000"), + + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.%", "3"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.default_key1", "default_value1"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.env", "foo"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.default_expiration_ms", "3600000"), + + resource.TestCheckResourceAttr("google_compute_address.foobar", "effective_labels.%", "3"), + ), + }, + { + ResourceName: "google_compute_address.foobar", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccComputeAddress_resourceLabelsOverridesProviderDefaultLabels(acctest.RandString(t, 10)), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.%", "3"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.env", "foo"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.default_expiration_ms", "3600000"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.default_key1", "value1"), + + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.%", "3"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.default_key1", "value1"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.env", "foo"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.default_expiration_ms", "3600000"), + + resource.TestCheckResourceAttr("google_compute_address.foobar", "effective_labels.%", "3"), + ), + }, + { + ResourceName: "google_compute_address.foobar", + ImportState: true, + ImportStateVerify: true, + // The labels field in the state is decided by the configuration. + // During importing, the configuration is unavailable, so the labels field in the state after importing is empty. + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccComputeAddress_moveResourceLabelToProviderDefaultLabels(acctest.RandString(t, 10)), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.%", "2"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.default_expiration_ms", "3600000"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.default_key1", "value1"), + + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.%", "3"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.default_key1", "value1"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.env", "foo"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.default_expiration_ms", "3600000"), + + resource.TestCheckResourceAttr("google_compute_address.foobar", "effective_labels.%", "3"), + ), + }, + { + ResourceName: "google_compute_address.foobar", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccComputeAddress_resourceLabelsOverridesProviderDefaultLabels(acctest.RandString(t, 10)), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.%", "3"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.env", "foo"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.default_expiration_ms", "3600000"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "labels.default_key1", "value1"), + + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.%", "3"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.default_key1", "value1"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.env", "foo"), + resource.TestCheckResourceAttr("google_compute_address.foobar", "terraform_labels.default_expiration_ms", "3600000"), + + resource.TestCheckResourceAttr("google_compute_address.foobar", "effective_labels.%", "3"), + ), + }, + { + ResourceName: "google_compute_address.foobar", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccComputeAddress_networkTier(acctest.RandString(t, 10)), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckNoResourceAttr("google_compute_address.foobar", "labels.%"), + resource.TestCheckNoResourceAttr("google_compute_address.foobar", "effective_labels.%"), + ), + }, + { + ResourceName: "google_compute_address.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccComputeAddress_networkTier_withLabels(i string) string { return fmt.Sprintf(` resource "google_compute_address" "foobar" { @@ -179,7 +294,7 @@ resource "google_compute_address" "foobar" { network_tier = "STANDARD" labels = { - env = "foo" + env = "foo" default_expiration_ms = 3600000 } } @@ -193,13 +308,75 @@ resource "google_compute_address" "foobar" { network_tier = "STANDARD" labels = { - env = "bar" + env = "bar" default_expiration_ms = 7200000 } } `, i) } +func testAccComputeAddress_withProviderDefaultLabels(i string) string { + return fmt.Sprintf(` +provider "google" { + default_labels = { + default_key1 = "default_value1" + } +} + +resource "google_compute_address" "foobar" { + name = "tf-test-address-%s" + network_tier = "STANDARD" + + labels = { + env = "foo" + default_expiration_ms = 3600000 + } +} +`, i) +} + +func testAccComputeAddress_resourceLabelsOverridesProviderDefaultLabels(i string) string { + return fmt.Sprintf(` +provider "google" { + default_labels = { + default_key1 = "default_value1" + } +} + +resource "google_compute_address" "foobar" { + name = "tf-test-address-%s" + network_tier = "STANDARD" + + labels = { + env = "foo" + default_expiration_ms = 3600000 + default_key1 = "value1" + } +} +`, i) +} + +func testAccComputeAddress_moveResourceLabelToProviderDefaultLabels(i string) string { + return fmt.Sprintf(` +provider "google" { + default_labels = { + default_key1 = "default_value1" + env = "foo" + } +} + +resource "google_compute_address" "foobar" { + name = "tf-test-address-%s" + network_tier = "STANDARD" + + labels = { + default_expiration_ms = 3600000 + default_key1 = "value1" + } +} +`, i) +} + func testAccComputeAddress_internal(i string) string { return fmt.Sprintf(` resource "google_compute_address" "internal" { diff --git a/google-beta/services/compute/resource_compute_forwarding_rule.go b/google-beta/services/compute/resource_compute_forwarding_rule.go index 25f7d62a27..3e72f53b0a 100644 --- a/google-beta/services/compute/resource_compute_forwarding_rule.go +++ b/google-beta/services/compute/resource_compute_forwarding_rule.go @@ -50,6 +50,7 @@ func ResourceComputeForwardingRule() *schema.Resource { }, CustomizeDiff: customdiff.All( + tpgresource.SetTerraformLabelsDiff, tpgresource.DefaultProviderProject, ), @@ -446,6 +447,12 @@ For Private Service Connect forwarding rules that forward traffic to managed ser Computed: true, Description: `Creation timestamp in RFC3339 text format.`, }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "label_fingerprint": { Type: schema.TypeString, Computed: true, @@ -469,6 +476,13 @@ internally during updates.`, This field is only used for INTERNAL load balancing.`, }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "project": { Type: schema.TypeString, Optional: true, @@ -570,12 +584,6 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{ } else if v, ok := d.GetOkExists("allow_global_access"); ok || !reflect.DeepEqual(v, allowGlobalAccessProp) { obj["allowGlobalAccess"] = allowGlobalAccessProp } - labelsProp, err := expandComputeForwardingRuleLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeForwardingRuleLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err @@ -630,6 +638,12 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{ } else if v, ok := d.GetOkExists("ip_version"); !tpgresource.IsEmptyValue(reflect.ValueOf(ipVersionProp)) && (ok || !reflect.DeepEqual(v, ipVersionProp)) { obj["ipVersion"] = ipVersionProp } + labelsProp, err := expandComputeForwardingRuleTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } regionProp, err := expandComputeForwardingRuleRegion(d.Get("region"), d, config) if err != nil { return err @@ -688,7 +702,8 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{ return fmt.Errorf("Error waiting to create ForwardingRule: %s", err) } - if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + labels := d.Get("labels") // Labels cannot be set in a create. We'll have to set them here. err = resourceComputeForwardingRuleRead(d, meta) if err != nil { @@ -696,8 +711,8 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{ } obj := make(map[string]interface{}) - // d.Get("labels") will have been overridden by the Read call. - labelsProp, err := expandComputeForwardingRuleLabels(v, d, config) + // d.Get("terraform_labels") will have been overridden by the Read call. + labelsProp, err := expandComputeForwardingRuleTerraformLabels(v, d, config) if err != nil { return err } @@ -730,9 +745,14 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{ } // Set back the labels field, as it is needed to decide the value of "labels" in the state in the read function. - if err := d.Set("labels", v); err != nil { + if err := d.Set("labels", labels); err != nil { return fmt.Errorf("Error setting back labels: %s", err) } + + // Set back the terraform_labels field, as it is needed to decide the value of "terraform_labels" in the state in the read function. + if err := d.Set("terraform_labels", v); err != nil { + return fmt.Errorf("Error setting back terraform_labels: %s", err) + } } log.Printf("[DEBUG] Finished creating ForwardingRule %q: %#v", d.Id(), res) @@ -862,6 +882,12 @@ func resourceComputeForwardingRuleRead(d *schema.ResourceData, meta interface{}) if err := d.Set("ip_version", flattenComputeForwardingRuleIpVersion(res["ipVersion"], d, config)); err != nil { return fmt.Errorf("Error reading ForwardingRule: %s", err) } + if err := d.Set("terraform_labels", flattenComputeForwardingRuleTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading ForwardingRule: %s", err) + } + if err := d.Set("effective_labels", flattenComputeForwardingRuleEffectiveLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading ForwardingRule: %s", err) + } if err := d.Set("region", flattenComputeForwardingRuleRegion(res["region"], d, config)); err != nil { return fmt.Errorf("Error reading ForwardingRule: %s", err) } @@ -975,21 +1001,21 @@ func resourceComputeForwardingRuleUpdate(d *schema.ResourceData, meta interface{ return err } } - if d.HasChange("labels") || d.HasChange("label_fingerprint") { + if d.HasChange("label_fingerprint") || d.HasChange("terraform_labels") { obj := make(map[string]interface{}) - labelsProp, err := expandComputeForwardingRuleLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeForwardingRuleLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("label_fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelFingerprintProp)) { obj["labelFingerprint"] = labelFingerprintProp } + labelsProp, err := expandComputeForwardingRuleTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/forwardingRules/{{name}}/setLabels") if err != nil { @@ -1183,7 +1209,18 @@ func flattenComputeForwardingRuleAllowGlobalAccess(v interface{}, d *schema.Reso } func flattenComputeForwardingRuleLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - return v + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed } func flattenComputeForwardingRuleLabelFingerprint(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { @@ -1249,6 +1286,25 @@ func flattenComputeForwardingRuleIpVersion(v interface{}, d *schema.ResourceData return v } +func flattenComputeForwardingRuleTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenComputeForwardingRuleEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func flattenComputeForwardingRuleRegion(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { if v == nil { return v @@ -1374,17 +1430,6 @@ func expandComputeForwardingRuleAllowGlobalAccess(v interface{}, d tpgresource.T return v, nil } -func expandComputeForwardingRuleLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { - if v == nil { - return map[string]string{}, nil - } - m := make(map[string]string) - for k, val := range v.(map[string]interface{}) { - m[k] = val.(string) - } - return m, nil -} - func expandComputeForwardingRuleLabelFingerprint(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -1454,6 +1499,17 @@ func expandComputeForwardingRuleIpVersion(v interface{}, d tpgresource.Terraform return v, nil } +func expandComputeForwardingRuleTerraformLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} + func expandComputeForwardingRuleRegion(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { f, err := tpgresource.ParseGlobalFieldValue("regions", v.(string), "project", d, config, true) if err != nil { diff --git a/google-beta/services/compute/resource_compute_forwarding_rule_generated_test.go b/google-beta/services/compute/resource_compute_forwarding_rule_generated_test.go index 41e802d0be..5a438de191 100644 --- a/google-beta/services/compute/resource_compute_forwarding_rule_generated_test.go +++ b/google-beta/services/compute/resource_compute_forwarding_rule_generated_test.go @@ -49,7 +49,7 @@ func TestAccComputeForwardingRule_internalHttpLbWithMigBackendExample(t *testing ResourceName: "google_compute_forwarding_rule.google_compute_forwarding_rule", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region", "port_range", "target"}, }, }, }) @@ -268,7 +268,7 @@ func TestAccComputeForwardingRule_internalTcpUdpLbWithMigBackendExample(t *testi ResourceName: "google_compute_forwarding_rule.google_compute_forwarding_rule", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region"}, }, }, }) @@ -476,7 +476,7 @@ func TestAccComputeForwardingRule_forwardingRuleExternallbExample(t *testing.T) ResourceName: "google_compute_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region", "port_range"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region", "port_range"}, }, }, }) @@ -532,7 +532,7 @@ func TestAccComputeForwardingRule_forwardingRuleGlobalInternallbExample(t *testi ResourceName: "google_compute_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region"}, }, }, }) @@ -596,7 +596,7 @@ func TestAccComputeForwardingRule_forwardingRuleBasicExample(t *testing.T) { ResourceName: "google_compute_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region", "port_range", "target"}, }, }, }) @@ -635,7 +635,7 @@ func TestAccComputeForwardingRule_forwardingRuleL3DefaultExample(t *testing.T) { ResourceName: "google_compute_forwarding_rule.fwd_rule", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region"}, }, }, }) @@ -691,7 +691,7 @@ func TestAccComputeForwardingRule_forwardingRuleInternallbExample(t *testing.T) ResourceName: "google_compute_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region", "port_range", "target"}, }, }, }) @@ -761,7 +761,7 @@ func TestAccComputeForwardingRule_forwardingRuleHttpLbExample(t *testing.T) { ResourceName: "google_compute_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region", "port_range", "target"}, }, }, }) @@ -980,7 +980,7 @@ func TestAccComputeForwardingRule_forwardingRuleRegionalHttpXlbExample(t *testin ResourceName: "google_compute_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region", "port_range", "target", "ip_address"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region", "port_range", "target", "ip_address"}, }, }, }) @@ -1206,7 +1206,7 @@ func TestAccComputeForwardingRule_forwardingRuleVpcPscExample(t *testing.T) { ResourceName: "google_compute_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region", "port_range", "target", "ip_address"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region", "port_range", "target", "ip_address"}, }, }, }) @@ -1330,7 +1330,7 @@ func TestAccComputeForwardingRule_forwardingRuleVpcPscNoAutomateDnsExample(t *te ResourceName: "google_compute_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region", "port_range", "target", "ip_address"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region", "port_range", "target", "ip_address"}, }, }, }) @@ -1450,7 +1450,7 @@ func TestAccComputeForwardingRule_forwardingRuleRegionalSteeringExample(t *testi ResourceName: "google_compute_forwarding_rule.steering", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region"}, }, }, }) @@ -1508,7 +1508,7 @@ func TestAccComputeForwardingRule_forwardingRuleInternallbIpv6Example(t *testing ResourceName: "google_compute_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "no_automate_dns_zone", "region", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"backend_service", "network", "subnetwork", "labels", "no_automate_dns_zone", "terraform_labels", "region", "port_range", "target"}, }, }, }) diff --git a/google-beta/services/compute/resource_compute_forwarding_rule_test.go b/google-beta/services/compute/resource_compute_forwarding_rule_test.go index 375ca6e747..d284bd9c0b 100644 --- a/google-beta/services/compute/resource_compute_forwarding_rule_test.go +++ b/google-beta/services/compute/resource_compute_forwarding_rule_test.go @@ -25,17 +25,19 @@ func TestAccComputeForwardingRule_update(t *testing.T) { Config: testAccComputeForwardingRule_basic(poolName, ruleName), }, { - ResourceName: "google_compute_forwarding_rule.foobar", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_compute_forwarding_rule.foobar", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, { Config: testAccComputeForwardingRule_update(poolName, ruleName), }, { - ResourceName: "google_compute_forwarding_rule.foobar", - ImportState: true, - ImportStateVerify: true, + ResourceName: "google_compute_forwarding_rule.foobar", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) diff --git a/google-beta/services/compute/resource_compute_global_address.go b/google-beta/services/compute/resource_compute_global_address.go index fe518d11ed..51384595e0 100644 --- a/google-beta/services/compute/resource_compute_global_address.go +++ b/google-beta/services/compute/resource_compute_global_address.go @@ -49,6 +49,7 @@ func ResourceComputeGlobalAddress() *schema.Resource { }, CustomizeDiff: customdiff.All( + tpgresource.SetTerraformLabelsDiff, tpgresource.DefaultProviderProject, ), @@ -143,12 +144,25 @@ when purpose=PRIVATE_SERVICE_CONNECT`, Computed: true, Description: `Creation timestamp in RFC3339 text format.`, }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "label_fingerprint": { Type: schema.TypeString, Computed: true, Description: `The fingerprint used for optimistic locking of this resource. Used internally during updates.`, }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "project": { Type: schema.TypeString, Optional: true, @@ -190,12 +204,6 @@ func resourceComputeGlobalAddressCreate(d *schema.ResourceData, meta interface{} } else if v, ok := d.GetOkExists("name"); !tpgresource.IsEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { obj["name"] = nameProp } - labelsProp, err := expandComputeGlobalAddressLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeGlobalAddressLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err @@ -232,6 +240,12 @@ func resourceComputeGlobalAddressCreate(d *schema.ResourceData, meta interface{} } else if v, ok := d.GetOkExists("network"); !tpgresource.IsEmptyValue(reflect.ValueOf(networkProp)) && (ok || !reflect.DeepEqual(v, networkProp)) { obj["network"] = networkProp } + labelsProp, err := expandComputeGlobalAddressTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/addresses") if err != nil { @@ -282,7 +296,8 @@ func resourceComputeGlobalAddressCreate(d *schema.ResourceData, meta interface{} return fmt.Errorf("Error waiting to create GlobalAddress: %s", err) } - if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + labels := d.Get("labels") // Labels cannot be set in a create. We'll have to set them here. err = resourceComputeGlobalAddressRead(d, meta) if err != nil { @@ -290,8 +305,8 @@ func resourceComputeGlobalAddressCreate(d *schema.ResourceData, meta interface{} } obj := make(map[string]interface{}) - // d.Get("labels") will have been overridden by the Read call. - labelsProp, err := expandComputeGlobalAddressLabels(v, d, config) + // d.Get("terraform_labels") will have been overridden by the Read call. + labelsProp, err := expandComputeGlobalAddressTerraformLabels(v, d, config) if err != nil { return err } @@ -324,9 +339,14 @@ func resourceComputeGlobalAddressCreate(d *schema.ResourceData, meta interface{} } // Set back the labels field, as it is needed to decide the value of "labels" in the state in the read function. - if err := d.Set("labels", v); err != nil { + if err := d.Set("labels", labels); err != nil { return fmt.Errorf("Error setting back labels: %s", err) } + + // Set back the terraform_labels field, as it is needed to decide the value of "terraform_labels" in the state in the read function. + if err := d.Set("terraform_labels", v); err != nil { + return fmt.Errorf("Error setting back terraform_labels: %s", err) + } } log.Printf("[DEBUG] Finished creating GlobalAddress %q: %#v", d.Id(), res) @@ -407,6 +427,12 @@ func resourceComputeGlobalAddressRead(d *schema.ResourceData, meta interface{}) if err := d.Set("network", flattenComputeGlobalAddressNetwork(res["network"], d, config)); err != nil { return fmt.Errorf("Error reading GlobalAddress: %s", err) } + if err := d.Set("terraform_labels", flattenComputeGlobalAddressTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } + if err := d.Set("effective_labels", flattenComputeGlobalAddressEffectiveLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } if err := d.Set("self_link", tpgresource.ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { return fmt.Errorf("Error reading GlobalAddress: %s", err) } @@ -431,21 +457,21 @@ func resourceComputeGlobalAddressUpdate(d *schema.ResourceData, meta interface{} d.Partial(true) - if d.HasChange("labels") || d.HasChange("label_fingerprint") { + if d.HasChange("label_fingerprint") || d.HasChange("terraform_labels") { obj := make(map[string]interface{}) - labelsProp, err := expandComputeGlobalAddressLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeGlobalAddressLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("label_fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelFingerprintProp)) { obj["labelFingerprint"] = labelFingerprintProp } + labelsProp, err := expandComputeGlobalAddressTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/addresses/{{name}}/setLabels") if err != nil { @@ -575,7 +601,18 @@ func flattenComputeGlobalAddressName(v interface{}, d *schema.ResourceData, conf } func flattenComputeGlobalAddressLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - return v + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed } func flattenComputeGlobalAddressLabelFingerprint(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { @@ -618,6 +655,25 @@ func flattenComputeGlobalAddressNetwork(v interface{}, d *schema.ResourceData, c return tpgresource.ConvertSelfLinkToV1(v.(string)) } +func flattenComputeGlobalAddressTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenComputeGlobalAddressEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func expandComputeGlobalAddressAddress(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -630,17 +686,6 @@ func expandComputeGlobalAddressName(v interface{}, d tpgresource.TerraformResour return v, nil } -func expandComputeGlobalAddressLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { - if v == nil { - return map[string]string{}, nil - } - m := make(map[string]string) - for k, val := range v.(map[string]interface{}) { - m[k] = val.(string) - } - return m, nil -} - func expandComputeGlobalAddressLabelFingerprint(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -668,3 +713,14 @@ func expandComputeGlobalAddressNetwork(v interface{}, d tpgresource.TerraformRes } return f.RelativeLink(), nil } + +func expandComputeGlobalAddressTerraformLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} diff --git a/google-beta/services/compute/resource_compute_global_address_generated_test.go b/google-beta/services/compute/resource_compute_global_address_generated_test.go index eab1fc5333..b5cc913a59 100644 --- a/google-beta/services/compute/resource_compute_global_address_generated_test.go +++ b/google-beta/services/compute/resource_compute_global_address_generated_test.go @@ -49,7 +49,7 @@ func TestAccComputeGlobalAddress_globalAddressBasicExample(t *testing.T) { ResourceName: "google_compute_global_address.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network"}, + ImportStateVerifyIgnore: []string{"labels", "network", "terraform_labels"}, }, }, }) @@ -82,7 +82,7 @@ func TestAccComputeGlobalAddress_globalAddressPrivateServicesConnectExample(t *t ResourceName: "google_compute_global_address.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network"}, + ImportStateVerifyIgnore: []string{"labels", "network", "terraform_labels"}, }, }, }) diff --git a/google-beta/services/compute/resource_compute_global_forwarding_rule.go b/google-beta/services/compute/resource_compute_global_forwarding_rule.go index 67c066872b..24e14ea6c5 100644 --- a/google-beta/services/compute/resource_compute_global_forwarding_rule.go +++ b/google-beta/services/compute/resource_compute_global_forwarding_rule.go @@ -50,6 +50,7 @@ func ResourceComputeGlobalForwardingRule() *schema.Resource { }, CustomizeDiff: customdiff.All( + tpgresource.SetTerraformLabelsDiff, tpgresource.DefaultProviderProject, ), @@ -335,6 +336,12 @@ mode or when creating external forwarding rule with IPv6.`, Computed: true, Description: `[Output Only] The URL for the corresponding base Forwarding Rule. By base Forwarding Rule, we mean the Forwarding Rule that has the same IP address, protocol, and port settings with the current Forwarding Rule, but without sourceIPRanges specified. Always empty if the current Forwarding Rule does not have sourceIPRanges specified.`, }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "label_fingerprint": { Type: schema.TypeString, Computed: true, @@ -351,6 +358,13 @@ internally during updates.`, Computed: true, Description: `The PSC connection status of the PSC Forwarding Rule. Possible values: 'STATUS_UNSPECIFIED', 'PENDING', 'ACCEPTED', 'REJECTED', 'CLOSED'`, }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "project": { Type: schema.TypeString, Optional: true, @@ -398,12 +412,6 @@ func resourceComputeGlobalForwardingRuleCreate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("ip_version"); !tpgresource.IsEmptyValue(reflect.ValueOf(ipVersionProp)) && (ok || !reflect.DeepEqual(v, ipVersionProp)) { obj["ipVersion"] = ipVersionProp } - labelsProp, err := expandComputeGlobalForwardingRuleLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeGlobalForwardingRuleLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err @@ -470,6 +478,12 @@ func resourceComputeGlobalForwardingRuleCreate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("no_automate_dns_zone"); ok || !reflect.DeepEqual(v, noAutomateDnsZoneProp) { obj["noAutomateDnsZone"] = noAutomateDnsZoneProp } + labelsProp, err := expandComputeGlobalForwardingRuleTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/forwardingRules") if err != nil { @@ -522,7 +536,8 @@ func resourceComputeGlobalForwardingRuleCreate(d *schema.ResourceData, meta inte return fmt.Errorf("Error waiting to create GlobalForwardingRule: %s", err) } - if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + labels := d.Get("labels") // Labels cannot be set in a create. We'll have to set them here. err = resourceComputeGlobalForwardingRuleRead(d, meta) if err != nil { @@ -530,8 +545,8 @@ func resourceComputeGlobalForwardingRuleCreate(d *schema.ResourceData, meta inte } obj := make(map[string]interface{}) - // d.Get("labels") will have been overridden by the Read call. - labelsProp, err := expandComputeGlobalForwardingRuleLabels(v, d, config) + // d.Get("terraform_labels") will have been overridden by the Read call. + labelsProp, err := expandComputeGlobalForwardingRuleTerraformLabels(v, d, config) if err != nil { return err } @@ -564,9 +579,14 @@ func resourceComputeGlobalForwardingRuleCreate(d *schema.ResourceData, meta inte } // Set back the labels field, as it is needed to decide the value of "labels" in the state in the read function. - if err := d.Set("labels", v); err != nil { + if err := d.Set("labels", labels); err != nil { return fmt.Errorf("Error setting back labels: %s", err) } + + // Set back the terraform_labels field, as it is needed to decide the value of "terraform_labels" in the state in the read function. + if err := d.Set("terraform_labels", v); err != nil { + return fmt.Errorf("Error setting back terraform_labels: %s", err) + } } log.Printf("[DEBUG] Finished creating GlobalForwardingRule %q: %#v", d.Id(), res) @@ -669,6 +689,12 @@ func resourceComputeGlobalForwardingRuleRead(d *schema.ResourceData, meta interf if err := d.Set("allow_psc_global_access", flattenComputeGlobalForwardingRuleAllowPscGlobalAccess(res["allowPscGlobalAccess"], d, config)); err != nil { return fmt.Errorf("Error reading GlobalForwardingRule: %s", err) } + if err := d.Set("terraform_labels", flattenComputeGlobalForwardingRuleTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlobalForwardingRule: %s", err) + } + if err := d.Set("effective_labels", flattenComputeGlobalForwardingRuleEffectiveLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading GlobalForwardingRule: %s", err) + } if err := d.Set("self_link", tpgresource.ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { return fmt.Errorf("Error reading GlobalForwardingRule: %s", err) } @@ -693,21 +719,21 @@ func resourceComputeGlobalForwardingRuleUpdate(d *schema.ResourceData, meta inte d.Partial(true) - if d.HasChange("labels") || d.HasChange("label_fingerprint") { + if d.HasChange("label_fingerprint") || d.HasChange("terraform_labels") { obj := make(map[string]interface{}) - labelsProp, err := expandComputeGlobalForwardingRuleLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeGlobalForwardingRuleLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("label_fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelFingerprintProp)) { obj["labelFingerprint"] = labelFingerprintProp } + labelsProp, err := expandComputeGlobalForwardingRuleTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/forwardingRules/{{name}}/setLabels") if err != nil { @@ -891,7 +917,18 @@ func flattenComputeGlobalForwardingRuleIpVersion(v interface{}, d *schema.Resour } func flattenComputeGlobalForwardingRuleLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - return v + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed } func flattenComputeGlobalForwardingRuleLabelFingerprint(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { @@ -990,6 +1027,25 @@ func flattenComputeGlobalForwardingRuleAllowPscGlobalAccess(v interface{}, d *sc return v } +func flattenComputeGlobalForwardingRuleTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenComputeGlobalForwardingRuleEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func expandComputeGlobalForwardingRuleDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -1006,17 +1062,6 @@ func expandComputeGlobalForwardingRuleIpVersion(v interface{}, d tpgresource.Ter return v, nil } -func expandComputeGlobalForwardingRuleLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { - if v == nil { - return map[string]string{}, nil - } - m := make(map[string]string) - for k, val := range v.(map[string]interface{}) { - m[k] = val.(string) - } - return m, nil -} - func expandComputeGlobalForwardingRuleLabelFingerprint(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -1134,3 +1179,14 @@ func expandComputeGlobalForwardingRuleAllowPscGlobalAccess(v interface{}, d tpgr func expandComputeGlobalForwardingRuleNoAutomateDnsZone(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } + +func expandComputeGlobalForwardingRuleTerraformLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} diff --git a/google-beta/services/compute/resource_compute_global_forwarding_rule_generated_test.go b/google-beta/services/compute/resource_compute_global_forwarding_rule_generated_test.go index cfed48c279..9721f1d81d 100644 --- a/google-beta/services/compute/resource_compute_global_forwarding_rule_generated_test.go +++ b/google-beta/services/compute/resource_compute_global_forwarding_rule_generated_test.go @@ -50,7 +50,7 @@ func TestAccComputeGlobalForwardingRule_externalTcpProxyLbMigBackendExample(t *t ResourceName: "google_compute_global_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network", "subnetwork", "no_automate_dns_zone", "port_range", "target", "ip_address"}, + ImportStateVerifyIgnore: []string{"labels", "network", "subnetwork", "no_automate_dns_zone", "terraform_labels", "port_range", "target", "ip_address"}, }, }, }) @@ -223,7 +223,7 @@ func TestAccComputeGlobalForwardingRule_externalHttpLbMigBackendCustomHeaderExam ResourceName: "google_compute_global_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network", "subnetwork", "no_automate_dns_zone", "port_range", "target", "ip_address"}, + ImportStateVerifyIgnore: []string{"labels", "network", "subnetwork", "no_automate_dns_zone", "terraform_labels", "port_range", "target", "ip_address"}, }, }, }) @@ -408,7 +408,7 @@ func TestAccComputeGlobalForwardingRule_globalForwardingRuleHttpExample(t *testi ResourceName: "google_compute_global_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network", "subnetwork", "no_automate_dns_zone", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"labels", "network", "subnetwork", "no_automate_dns_zone", "terraform_labels", "port_range", "target"}, }, }, }) @@ -486,7 +486,7 @@ func TestAccComputeGlobalForwardingRule_globalForwardingRuleInternalExample(t *t ResourceName: "google_compute_global_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network", "subnetwork", "no_automate_dns_zone", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"labels", "network", "subnetwork", "no_automate_dns_zone", "terraform_labels", "port_range", "target"}, }, }, }) @@ -623,7 +623,7 @@ func TestAccComputeGlobalForwardingRule_globalForwardingRuleExternalManagedExamp ResourceName: "google_compute_global_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network", "subnetwork", "no_automate_dns_zone", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"labels", "network", "subnetwork", "no_automate_dns_zone", "terraform_labels", "port_range", "target"}, }, }, }) @@ -694,7 +694,7 @@ func TestAccComputeGlobalForwardingRule_globalForwardingRuleHybridExample(t *tes ResourceName: "google_compute_global_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network", "subnetwork", "no_automate_dns_zone", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"labels", "network", "subnetwork", "no_automate_dns_zone", "terraform_labels", "port_range", "target"}, }, }, }) @@ -854,7 +854,7 @@ func TestAccComputeGlobalForwardingRule_globalInternalHttpLbWithMigBackendExampl ResourceName: "google_compute_global_forwarding_rule.google_compute_forwarding_rule", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network", "subnetwork", "no_automate_dns_zone", "port_range", "target"}, + ImportStateVerifyIgnore: []string{"labels", "network", "subnetwork", "no_automate_dns_zone", "terraform_labels", "port_range", "target"}, }, }, }) @@ -1068,7 +1068,7 @@ func TestAccComputeGlobalForwardingRule_privateServiceConnectGoogleApisExample(t ResourceName: "google_compute_global_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network", "subnetwork", "no_automate_dns_zone", "ip_address"}, + ImportStateVerifyIgnore: []string{"labels", "network", "subnetwork", "no_automate_dns_zone", "terraform_labels", "ip_address"}, }, }, }) @@ -1135,7 +1135,7 @@ func TestAccComputeGlobalForwardingRule_privateServiceConnectGoogleApisNoAutomat ResourceName: "google_compute_global_forwarding_rule.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network", "subnetwork", "no_automate_dns_zone", "ip_address"}, + ImportStateVerifyIgnore: []string{"labels", "network", "subnetwork", "no_automate_dns_zone", "terraform_labels", "ip_address"}, }, }, }) diff --git a/google-beta/services/compute/resource_compute_global_forwarding_rule_test.go b/google-beta/services/compute/resource_compute_global_forwarding_rule_test.go index 49604bd6cc..3a0e85c099 100644 --- a/google-beta/services/compute/resource_compute_global_forwarding_rule_test.go +++ b/google-beta/services/compute/resource_compute_global_forwarding_rule_test.go @@ -108,7 +108,7 @@ func TestAccComputeGlobalForwardingRule_labels(t *testing.T) { ResourceName: "google_compute_global_forwarding_rule.forwarding_rule", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"port_range", "target"}, + ImportStateVerifyIgnore: []string{"port_range", "target", "labels", "terraform_labels"}, }, { Config: testAccComputeGlobalForwardingRule_labelsUpdated(fr, proxy, backend, hc, urlmap), @@ -117,7 +117,7 @@ func TestAccComputeGlobalForwardingRule_labels(t *testing.T) { ResourceName: "google_compute_global_forwarding_rule.forwarding_rule", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"port_range", "target"}, + ImportStateVerifyIgnore: []string{"port_range", "target", "labels", "terraform_labels"}, }, }, }) diff --git a/google-beta/services/compute/resource_compute_vpn_tunnel.go b/google-beta/services/compute/resource_compute_vpn_tunnel.go index 0bddedcd09..bc8a7e5350 100644 --- a/google-beta/services/compute/resource_compute_vpn_tunnel.go +++ b/google-beta/services/compute/resource_compute_vpn_tunnel.go @@ -152,6 +152,7 @@ func ResourceComputeVpnTunnel() *schema.Resource { }, CustomizeDiff: customdiff.All( + tpgresource.SetTerraformLabelsDiff, tpgresource.DefaultProviderProject, ), @@ -306,6 +307,12 @@ This field must reference a 'google_compute_ha_vpn_gateway' resource.`, Computed: true, Description: `Detailed status message for the VPN tunnel.`, }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "label_fingerprint": { Type: schema.TypeString, Computed: true, @@ -317,6 +324,13 @@ internally during updates.`, Computed: true, Description: `Hash of the shared secret.`, }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "tunnel_id": { Type: schema.TypeString, Computed: true, @@ -429,18 +443,18 @@ func resourceComputeVpnTunnelCreate(d *schema.ResourceData, meta interface{}) er } else if v, ok := d.GetOkExists("remote_traffic_selector"); !tpgresource.IsEmptyValue(reflect.ValueOf(remoteTrafficSelectorProp)) && (ok || !reflect.DeepEqual(v, remoteTrafficSelectorProp)) { obj["remoteTrafficSelector"] = remoteTrafficSelectorProp } - labelsProp, err := expandComputeVpnTunnelLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeVpnTunnelLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("label_fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelFingerprintProp)) && (ok || !reflect.DeepEqual(v, labelFingerprintProp)) { obj["labelFingerprint"] = labelFingerprintProp } + labelsProp, err := expandComputeVpnTunnelTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } regionProp, err := expandComputeVpnTunnelRegion(d.Get("region"), d, config) if err != nil { return err @@ -502,7 +516,8 @@ func resourceComputeVpnTunnelCreate(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("Error waiting to create VpnTunnel: %s", err) } - if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + labels := d.Get("labels") // Labels cannot be set in a create. We'll have to set them here. err = resourceComputeVpnTunnelRead(d, meta) if err != nil { @@ -510,8 +525,8 @@ func resourceComputeVpnTunnelCreate(d *schema.ResourceData, meta interface{}) er } obj := make(map[string]interface{}) - // d.Get("labels") will have been overridden by the Read call. - labelsProp, err := expandComputeVpnTunnelLabels(v, d, config) + // d.Get("terraform_labels") will have been overridden by the Read call. + labelsProp, err := expandComputeVpnTunnelTerraformLabels(v, d, config) if err != nil { return err } @@ -544,9 +559,14 @@ func resourceComputeVpnTunnelCreate(d *schema.ResourceData, meta interface{}) er } // Set back the labels field, as it is needed to decide the value of "labels" in the state in the read function. - if err := d.Set("labels", v); err != nil { + if err := d.Set("labels", labels); err != nil { return fmt.Errorf("Error setting back labels: %s", err) } + + // Set back the terraform_labels field, as it is needed to decide the value of "terraform_labels" in the state in the read function. + if err := d.Set("terraform_labels", v); err != nil { + return fmt.Errorf("Error setting back terraform_labels: %s", err) + } } log.Printf("[DEBUG] Finished creating VpnTunnel %q: %#v", d.Id(), res) @@ -651,6 +671,12 @@ func resourceComputeVpnTunnelRead(d *schema.ResourceData, meta interface{}) erro if err := d.Set("detailed_status", flattenComputeVpnTunnelDetailedStatus(res["detailedStatus"], d, config)); err != nil { return fmt.Errorf("Error reading VpnTunnel: %s", err) } + if err := d.Set("terraform_labels", flattenComputeVpnTunnelTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } + if err := d.Set("effective_labels", flattenComputeVpnTunnelEffectiveLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } if err := d.Set("region", flattenComputeVpnTunnelRegion(res["region"], d, config)); err != nil { return fmt.Errorf("Error reading VpnTunnel: %s", err) } @@ -678,21 +704,21 @@ func resourceComputeVpnTunnelUpdate(d *schema.ResourceData, meta interface{}) er d.Partial(true) - if d.HasChange("labels") || d.HasChange("label_fingerprint") { + if d.HasChange("label_fingerprint") || d.HasChange("terraform_labels") { obj := make(map[string]interface{}) - labelsProp, err := expandComputeVpnTunnelLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } labelFingerprintProp, err := expandComputeVpnTunnelLabelFingerprint(d.Get("label_fingerprint"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("label_fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelFingerprintProp)) { obj["labelFingerprint"] = labelFingerprintProp } + labelsProp, err := expandComputeVpnTunnelTerraformLabels(d.Get("terraform_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("terraform_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/vpnTunnels/{{name}}/setLabels") if err != nil { @@ -931,7 +957,18 @@ func flattenComputeVpnTunnelRemoteTrafficSelector(v interface{}, d *schema.Resou } func flattenComputeVpnTunnelLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - return v + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed } func flattenComputeVpnTunnelLabelFingerprint(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { @@ -942,6 +979,25 @@ func flattenComputeVpnTunnelDetailedStatus(v interface{}, d *schema.ResourceData return v } +func flattenComputeVpnTunnelTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenComputeVpnTunnelEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func flattenComputeVpnTunnelRegion(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { if v == nil { return v @@ -1036,7 +1092,11 @@ func expandComputeVpnTunnelRemoteTrafficSelector(v interface{}, d tpgresource.Te return v, nil } -func expandComputeVpnTunnelLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { +func expandComputeVpnTunnelLabelFingerprint(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandComputeVpnTunnelTerraformLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { if v == nil { return map[string]string{}, nil } @@ -1047,10 +1107,6 @@ func expandComputeVpnTunnelLabels(v interface{}, d tpgresource.TerraformResource return m, nil } -func expandComputeVpnTunnelLabelFingerprint(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { - return v, nil -} - func expandComputeVpnTunnelRegion(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { f, err := tpgresource.ParseGlobalFieldValue("regions", v.(string), "project", d, config, true) if err != nil { diff --git a/google-beta/services/compute/resource_compute_vpn_tunnel_generated_test.go b/google-beta/services/compute/resource_compute_vpn_tunnel_generated_test.go index 915eabdcff..ca4765a675 100644 --- a/google-beta/services/compute/resource_compute_vpn_tunnel_generated_test.go +++ b/google-beta/services/compute/resource_compute_vpn_tunnel_generated_test.go @@ -49,7 +49,7 @@ func TestAccComputeVpnTunnel_vpnTunnelBasicExample(t *testing.T) { ResourceName: "google_compute_vpn_tunnel.tunnel1", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"target_vpn_gateway", "vpn_gateway", "peer_external_gateway", "peer_gcp_gateway", "router", "shared_secret", "region"}, + ImportStateVerifyIgnore: []string{"target_vpn_gateway", "vpn_gateway", "peer_external_gateway", "peer_gcp_gateway", "router", "shared_secret", "labels", "terraform_labels", "region"}, }, }, }) @@ -139,7 +139,7 @@ func TestAccComputeVpnTunnel_vpnTunnelBetaExample(t *testing.T) { ResourceName: "google_compute_vpn_tunnel.tunnel1", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"target_vpn_gateway", "vpn_gateway", "peer_external_gateway", "peer_gcp_gateway", "router", "shared_secret", "region"}, + ImportStateVerifyIgnore: []string{"target_vpn_gateway", "vpn_gateway", "peer_external_gateway", "peer_gcp_gateway", "router", "shared_secret", "labels", "terraform_labels", "region"}, }, }, }) diff --git a/google-beta/tpgresource/labels.go b/google-beta/tpgresource/labels.go new file mode 100644 index 0000000000..ad652ee49f --- /dev/null +++ b/google-beta/tpgresource/labels.go @@ -0,0 +1,63 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package tpgresource + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" +) + +func SetTerraformLabelsDiff(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { + config := meta.(*transport_tpg.Config) + + // Merge provider default labels with the user defined labels in the resource to get terraform managed labels + terraformLabels := make(map[string]string) + for k, v := range config.DefaultLabels { + terraformLabels[k] = v + } + + labels := d.Get("labels").(map[string]interface{}) + for k, v := range labels { + terraformLabels[k] = v.(string) + } + + if err := d.SetNew("terraform_labels", terraformLabels); err != nil { + return fmt.Errorf("error setting new terraform_labels diff: %w", err) + } + + return nil +} + +func SetMetadataTerraformLabelsDiff(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { + v := d.Get("metadata") + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil + } + + config := meta.(*transport_tpg.Config) + + // Merge provider default labels with the user defined labels in the resource to get terraform managed labels + terraformLabels := make(map[string]string) + for k, v := range config.DefaultLabels { + terraformLabels[k] = v + } + + labels := d.Get("metadata.0.labels").(map[string]interface{}) + for k, v := range labels { + terraformLabels[k] = v.(string) + } + + raw := l[0] + original := raw.(map[string]interface{}) + original["terraform_labels"] = terraformLabels + + if err := d.SetNew("metadata", []interface{}{original}); err != nil { + return fmt.Errorf("error setting new metadata diff: %w", err) + } + + return nil +} diff --git a/google-beta/transport/config.go b/google-beta/transport/config.go index 21518c5bca..96a70177bf 100644 --- a/google-beta/transport/config.go +++ b/google-beta/transport/config.go @@ -172,6 +172,7 @@ type Config struct { UserProjectOverride bool RequestReason string RequestTimeout time.Duration + DefaultLabels map[string]string // PollInterval is passed to resource.StateChangeConf in common_operation.go // It controls the interval at which we poll for successful operations PollInterval time.Duration diff --git a/website/docs/r/bigquery_dataset.html.markdown b/website/docs/r/bigquery_dataset.html.markdown index ce92c742f6..a27ba1029d 100644 --- a/website/docs/r/bigquery_dataset.html.markdown +++ b/website/docs/r/bigquery_dataset.html.markdown @@ -468,6 +468,10 @@ In addition to the arguments listed above, the following computed attributes are The date when this dataset or any of its tables was last modified, in milliseconds since the epoch. +* `terraform_labels` - + The combination of labels configured directly on the resource + and default labels configured on the provider. + * `effective_labels` - All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. * `self_link` - The URI of the created resource. diff --git a/website/docs/r/compute_address.html.markdown b/website/docs/r/compute_address.html.markdown index f6a690fe85..452222ea3c 100644 --- a/website/docs/r/compute_address.html.markdown +++ b/website/docs/r/compute_address.html.markdown @@ -278,6 +278,11 @@ In addition to the arguments listed above, the following computed attributes are The fingerprint used for optimistic locking of this resource. Used internally during updates. +* `terraform_labels` - + ([Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + The combination of labels configured directly on the resource + and default labels configured on the provider. + * `effective_labels` - ([Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. diff --git a/website/docs/r/compute_forwarding_rule.html.markdown b/website/docs/r/compute_forwarding_rule.html.markdown index 5c0d41be00..683b9cbf4a 100644 --- a/website/docs/r/compute_forwarding_rule.html.markdown +++ b/website/docs/r/compute_forwarding_rule.html.markdown @@ -1603,6 +1603,13 @@ In addition to the arguments listed above, the following computed attributes are * `base_forwarding_rule` - [Output Only] The URL for the corresponding base Forwarding Rule. By base Forwarding Rule, we mean the Forwarding Rule that has the same IP address, protocol, and port settings with the current Forwarding Rule, but without sourceIPRanges specified. Always empty if the current Forwarding Rule does not have sourceIPRanges specified. + +* `terraform_labels` - + The combination of labels configured directly on the resource + and default labels configured on the provider. + +* `effective_labels` - + All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. * `self_link` - The URI of the created resource. diff --git a/website/docs/r/compute_global_address.html.markdown b/website/docs/r/compute_global_address.html.markdown index 13d6f666b4..fd2532f4df 100644 --- a/website/docs/r/compute_global_address.html.markdown +++ b/website/docs/r/compute_global_address.html.markdown @@ -150,6 +150,15 @@ In addition to the arguments listed above, the following computed attributes are ([Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) The fingerprint used for optimistic locking of this resource. Used internally during updates. + +* `terraform_labels` - + ([Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + The combination of labels configured directly on the resource + and default labels configured on the provider. + +* `effective_labels` - + ([Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. * `self_link` - The URI of the created resource. diff --git a/website/docs/r/compute_global_forwarding_rule.html.markdown b/website/docs/r/compute_global_forwarding_rule.html.markdown index 5fb5d8e926..ab8c2adc51 100644 --- a/website/docs/r/compute_global_forwarding_rule.html.markdown +++ b/website/docs/r/compute_global_forwarding_rule.html.markdown @@ -1410,6 +1410,13 @@ In addition to the arguments listed above, the following computed attributes are * `base_forwarding_rule` - [Output Only] The URL for the corresponding base Forwarding Rule. By base Forwarding Rule, we mean the Forwarding Rule that has the same IP address, protocol, and port settings with the current Forwarding Rule, but without sourceIPRanges specified. Always empty if the current Forwarding Rule does not have sourceIPRanges specified. + +* `terraform_labels` - + The combination of labels configured directly on the resource + and default labels configured on the provider. + +* `effective_labels` - + All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. * `self_link` - The URI of the created resource. diff --git a/website/docs/r/compute_vpn_tunnel.html.markdown b/website/docs/r/compute_vpn_tunnel.html.markdown index 3adcfa52c9..ef4562b1c9 100644 --- a/website/docs/r/compute_vpn_tunnel.html.markdown +++ b/website/docs/r/compute_vpn_tunnel.html.markdown @@ -309,6 +309,15 @@ In addition to the arguments listed above, the following computed attributes are * `detailed_status` - Detailed status message for the VPN tunnel. + +* `terraform_labels` - + ([Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + The combination of labels configured directly on the resource + and default labels configured on the provider. + +* `effective_labels` - + ([Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. * `self_link` - The URI of the created resource.