From c9d4703e73d0fad182f7d7534467ab2b34d315d9 Mon Sep 17 00:00:00 2001 From: Zhenhua Li Date: Tue, 22 Aug 2023 14:11:40 -0700 Subject: [PATCH] Support provider default labels for DCL resources --- ...rce_dataproc_workflow_template_test.go.erb | 4 +-- tpgtools/property.go | 36 ++++++++++++++++++- tpgtools/resource.go | 14 ++++++-- tpgtools/templates/resource.go.tmpl | 19 ++++++++-- tpgtools/templates/serialization.go.tmpl | 2 +- 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_workflow_template_test.go.erb b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_workflow_template_test.go.erb index aa3dc64a6223..21988d0cb673 100644 --- a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_workflow_template_test.go.erb +++ b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_workflow_template_test.go.erb @@ -38,9 +38,9 @@ func TestAccDataprocWorkflowTemplate_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, // The "labels" field in the state are decided by the configuration. - // During importing, as the configuration is unavailableafter, the "labels" field in the state will be empty. + // During importing, as the configuration is unavailable, the "labels" field in the state will be empty. // So add the "labels" to the ImportStateVerifyIgnore list. - ImportStateVerifyIgnore: []string{"labels"}, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, ResourceName: "google_dataproc_workflow_template.template", }, }, diff --git a/tpgtools/property.go b/tpgtools/property.go index 0292c3124857..43a0b634bc07 100644 --- a/tpgtools/property.go +++ b/tpgtools/property.go @@ -452,6 +452,10 @@ func (p Property) IsResourceAnnotations() bool { return p.Name() == "annotations" && p.parent == nil } +func (p Property) ShouldShowUpInSamples() bool { + return (p.Settable && p.Name() != "effective_labels" && p.Name() != "effective_annotations") || p.IsResourceLabels() || p.IsResourceAnnotations() +} + // collapsedProperties returns the input list of properties with nested objects collapsed if needed. func collapsedProperties(props []Property) (collapsed []Property) { for _, v := range props { @@ -897,7 +901,14 @@ func createPropertiesFromSchema(schema *openapi.Schema, typeFetcher *TypeFetcher note := "**Note**: This field is non-authoritative, and will only manage the labels present in your configuration. " + "Please refer to the field `effective_labels` for all of the labels present on the resource." p.Description = fmt.Sprintf("%s\n\n%s", p.Description, note) + p.Settable = false + p.StateGetter = nil + props = append(props, build_effective_labels_field(p, resource, parent)) + + if p.IsResourceLabels() { + props = append(props, build_terraform_labels_field(p, resource, parent)) + } } props = append(props, p) @@ -929,7 +940,7 @@ func build_effective_labels_field(p Property, resource *Resource, parent *Proper description := fmt.Sprintf("All of %s (key/value pairs) present on the resource in GCP, including the %s configured through Terraform, other clients and services.", p.title, p.title) stateSetter := fmt.Sprintf("d.Set(%q, res.%s)", title, p.PackageName) - return Property{ + effectiveLabels := Property{ title: title, Type: p.Type, Description: description, @@ -937,6 +948,29 @@ func build_effective_labels_field(p Property, resource *Resource, parent *Proper parent: parent, Optional: false, Computed: true, + PackageName: p.PackageName, + Settable: true, + StateSetter: &stateSetter, + } + + stateGetter := effectiveLabels.DefaultStateGetter() + effectiveLabels.StateGetter = &stateGetter + return effectiveLabels +} + +func build_terraform_labels_field(p Property, resource *Resource, parent *Property) Property { + title := fmt.Sprintf("terraform_%s", p.title) + description := fmt.Sprintf("The combination of %s configured directly on the resource and default %s configured on the provider.", p.title, p.title) + stateSetter := fmt.Sprintf("d.Set(%q, flatten%sTerraform%s(res.%s, d))", title, p.resource.PathType(), p.PackagePath(), p.PackageName) + + return Property{ + title: title, + Type: p.Type, + Description: description, + resource: resource, + parent: parent, + Computed: true, + PackageName: p.PackageName, StateSetter: &stateSetter, } } diff --git a/tpgtools/resource.go b/tpgtools/resource.go index 1e6f6e7a1498..26c94420ef45 100644 --- a/tpgtools/resource.go +++ b/tpgtools/resource.go @@ -586,6 +586,14 @@ func createResource(schema *openapi.Schema, info *openapi.Info, typeFetcher *Typ res.CustomizeDiff = cdiff.Functions } + if res.HasLabels() { + res.CustomizeDiff = append(res.CustomizeDiff, "tpgresource.SetLabelsDiff") + } + + if res.HasAnnotations() { + res.CustomizeDiff = append(res.CustomizeDiff, "tpgresource.SetAnnotationsDiff") + } + // ListFields if parameters, ok := typeFetcher.doc.Paths["list"]; ok { for _, param := range parameters.Parameters { @@ -835,7 +843,7 @@ func (r *Resource) loadHandWrittenSamples() []Sample { // During importing, as the configuration is unavailableafter, the "labels" and "annotations" fields in the state will be empty. // So add the "labels" and the "annotations" fields to the ImportStateVerifyIgnore list. if r.HasLabels() { - sample.IgnoreRead = append(sample.IgnoreRead, "labels") + sample.IgnoreRead = append(sample.IgnoreRead, "labels", "terraform_labels") } if r.HasAnnotations() { @@ -930,10 +938,10 @@ func (r *Resource) loadDCLSamples() []Sample { sample.TestSlug = RenderedString(sampleNameToTitleCase(*sample.Name).titlecase()) // The "labels" and "annotations" fields in the state are decided by the configuration. - // During importing, as the configuration is unavailableafter, the "labels" and "annotations" fields in the state will be empty. + // During importing, as the configuration is unavailable, the "labels" and "annotations" fields in the state will be empty. // So add the "labels" and the "annotations" fields to the ImportStateVerifyIgnore list. if r.HasLabels() { - sample.IgnoreRead = append(sample.IgnoreRead, "labels") + sample.IgnoreRead = append(sample.IgnoreRead, "labels", "terraform_labels") } if r.HasAnnotations() { diff --git a/tpgtools/templates/resource.go.tmpl b/tpgtools/templates/resource.go.tmpl index a3f10f2db10b..db1eeb4d6aea 100644 --- a/tpgtools/templates/resource.go.tmpl +++ b/tpgtools/templates/resource.go.tmpl @@ -723,7 +723,22 @@ func flatten{{$.PathType}}Labels(v map[string]string, d *schema.ResourceData) in transformed := make(map[string]interface{}) if l, ok := d.Get("labels").(map[string]interface{}); ok { for k, _ := range l { - transformed[k] = l[k] + transformed[k] = v[k] + } + } + + return transformed +} + +func flatten{{$.PathType}}TerraformLabels(v map[string]string, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + + transformed := make(map[string]interface{}) + if l, ok := d.Get("terraform_labels").(map[string]interface{}); ok { + for k, _ := range l { + transformed[k] = v[k] } } @@ -740,7 +755,7 @@ func flatten{{$.PathType}}Annotations(v map[string]string, d *schema.ResourceDat transformed := make(map[string]interface{}) if l, ok := d.Get("annotations").(map[string]interface{}); ok { for k, _ := range l { - transformed[k] = l[k] + transformed[k] = v[k] } } diff --git a/tpgtools/templates/serialization.go.tmpl b/tpgtools/templates/serialization.go.tmpl index 7936e1a0119c..faba0a38cdfc 100644 --- a/tpgtools/templates/serialization.go.tmpl +++ b/tpgtools/templates/serialization.go.tmpl @@ -126,7 +126,7 @@ func ConvertSampleJSONToHCL(product DCLPackageName, resource miscellaneousNameSn func {{ $res.TitleCaseFullName }}{{$version.SerializationSuffix}}AsHCL(r {{$res.Package}}{{$version.SerializationSuffix}}.{{$res.DCLStructName}}, hasGAEquivalent bool) (string, error) { outputConfig := "resource \"{{$res.TerraformName}}\" \"output\" {\n" {{- range $field := $res.Properties}} - {{- if $field.Settable }} + {{- if $field.ShouldShowUpInSamples }} {{- if eq $field.Type.String "TypeString" "TypeInt" "TypeBool" "TypeFloat" }} {{- if $field.Type.IsDateTime }} if !r.{{$field.PackageName}}.IsZero() {