From 62e1ef2d91e2bf309a5051550ccd9fa0b54afd1d Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:49:35 -0800 Subject: [PATCH] `EphemeralWriteOnly`: Initial support for MMv1 Generation in schema & docs (#12550) --- mmv1/api/resource.go | 17 ++++++++++ mmv1/api/resource/docs.go | 2 ++ mmv1/api/type.go | 34 +++++++++++++++++++ .../terraform/expand_property_method.go.tmpl | 12 ++++--- .../terraform/flatten_property_method.go.tmpl | 8 +++-- ..._property_documentation.html.markdown.tmpl | 4 +-- ...rite_only_documentation.html.markdown.tmpl | 27 +++++++++++++++ .../property_documentation.html.markdown.tmpl | 3 ++ .../terraform/resource.html.markdown.tmpl | 24 +++++++++++-- .../terraform/schema_property.go.tmpl | 3 ++ tpgtools/property.go | 1 + tpgtools/templates/resource.go.tmpl | 6 ++++ 12 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 mmv1/templates/terraform/nested_property_write_only_documentation.html.markdown.tmpl diff --git a/mmv1/api/resource.go b/mmv1/api/resource.go index 3edcd10210c1..15554d6f2d0b 100644 --- a/mmv1/api/resource.go +++ b/mmv1/api/resource.go @@ -547,6 +547,13 @@ func (r Resource) SensitiveProps() []*Type { }) } +func (r Resource) WriteOnlyProps() []*Type { + props := r.AllNestedProperties(r.RootProperties()) + return google.Select(props, func(p *Type) bool { + return p.WriteOnly + }) +} + func (r Resource) SensitivePropsToString() string { var props []string @@ -557,6 +564,16 @@ func (r Resource) SensitivePropsToString() string { return strings.Join(props, ", ") } +func (r Resource) WriteOnlyPropsToString() string { + var props []string + + for _, prop := range r.WriteOnlyProps() { + props = append(props, fmt.Sprintf("`%s`", prop.Lineage())) + } + + return strings.Join(props, ", ") +} + // All settable properties in the resource. // Fingerprints aren't *really" settable properties, but they behave like one. // At Create, they have no value but they can just be read in anyways, and after a Read diff --git a/mmv1/api/resource/docs.go b/mmv1/api/resource/docs.go index 1d5d76769131..cab80142c65c 100644 --- a/mmv1/api/resource/docs.go +++ b/mmv1/api/resource/docs.go @@ -32,5 +32,7 @@ type Docs struct { OptionalProperties string `yaml:"optional_properties"` + WriteOnlyProperties string `yaml:"write_only_properties"` + Attributes string } diff --git a/mmv1/api/type.go b/mmv1/api/type.go index 8e155f9fcd89..dd8cb4070a29 100644 --- a/mmv1/api/type.go +++ b/mmv1/api/type.go @@ -171,6 +171,8 @@ type Type struct { Sensitive bool `yaml:"sensitive,omitempty"` // Adds `Sensitive: true` to the schema + WriteOnly bool `yaml:"write_only,omitempty"` // Adds `WriteOnly: true` to the schema + // Does not set this value to the returned API value. Useful for fields // like secrets where the returned API value is not helpful. IgnoreRead bool `yaml:"ignore_read,omitempty"` @@ -361,6 +363,14 @@ func (t *Type) Validate(rName string) { log.Fatalf("'default_value' and 'default_from_api' cannot be both set in resource %s", rName) } + if t.WriteOnly && (t.DefaultFromApi || t.Output) { + log.Fatalf("Property %s cannot be write_only and default_from_api or output at the same time in resource %s", t.Name, rName) + } + + if t.WriteOnly && t.Sensitive { + log.Fatalf("Property %s cannot be write_only and sensitive at the same time in resource %s", t.Name, rName) + } + t.validateLabelsField() switch { @@ -640,6 +650,30 @@ func (t Type) NestedProperties() []*Type { return props } +// Returns write-only properties for this property. +func (t Type) WriteOnlyProperties() []*Type { + props := make([]*Type, 0) + + switch { + case t.IsA("Array"): + if t.ItemType.IsA("NestedObject") { + props = google.Reject(t.ItemType.WriteOnlyProperties(), func(p *Type) bool { + return t.Exclude + }) + } + case t.IsA("NestedObject"): + props = google.Select(t.UserProperties(), func(p *Type) bool { + return p.WriteOnly + }) + case t.IsA("Map"): + props = google.Reject(t.ValueType.WriteOnlyProperties(), func(p *Type) bool { + return t.Exclude + }) + default: + } + return props +} + func (t Type) Removed() bool { return t.RemovedMessage != "" } diff --git a/mmv1/templates/terraform/expand_property_method.go.tmpl b/mmv1/templates/terraform/expand_property_method.go.tmpl index 87da148953e8..6411f7296abf 100644 --- a/mmv1/templates/terraform/expand_property_method.go.tmpl +++ b/mmv1/templates/terraform/expand_property_method.go.tmpl @@ -26,7 +26,8 @@ func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.T original := raw.(map[string]interface{}) transformed := make(map[string]interface{}) {{- range $prop := $.NestedProperties }} - {{- if not (eq $prop.Name $prop.KeyName) }} + {{- if $prop.WriteOnly }} + {{- else if not (eq $prop.Name $prop.KeyName) }} transformed{{$prop.TitlelizeProperty}}, err := expand{{$.GetPrefix}}{{$.TitlelizeProperty}}{{$prop.TitlelizeProperty}}(original["{{ underscore $prop.Name }}"], d, config) if err != nil { @@ -65,7 +66,7 @@ func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.T func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { transformed := make(map[string]interface{}) {{- range $prop := $.NestedProperties }} - {{- if not (and (hasPrefix $prop.Type "KeyValue") $prop.IgnoreWrite) }} + {{- if not (and (hasPrefix $prop.Type "KeyValue") $prop.IgnoreWrite (not $prop.WriteOnly)) }} transformed{{$prop.TitlelizeProperty}}, err := expand{{$.GetPrefix}}{{$.TitlelizeProperty}}{{$prop.TitlelizeProperty}}({{ if $prop.FlattenObject }}nil{{ else }}d.Get("{{ underscore $prop.Name }}"), d, config) if err != nil { return nil, err @@ -83,6 +84,7 @@ func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.T return transformed, nil } {{ else }}{{/* if $.IsA "Map" */}} + {{- if not $.WriteOnly }} func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { {{- if $.IsSet }} v = v.(*schema.Set).List() @@ -118,7 +120,8 @@ func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.T {{- end }}{{/* if $.IsA "Array */}} transformed := make(map[string]interface{}) {{ range $prop := $.NestedProperties }} - {{- if not (and (hasPrefix $prop.Type "KeyValue") $prop.IgnoreWrite) }} + {{- if $prop.WriteOnly }} + {{- else if not (and (hasPrefix $prop.Type "KeyValue") $prop.IgnoreWrite) }} transformed{{$prop.TitlelizeProperty}}, err := expand{{$.GetPrefix}}{{$.TitlelizeProperty}}{{$prop.TitlelizeProperty}}(original["{{ underscore $prop.Name }}"], d, config) if err != nil { return nil, err @@ -155,11 +158,12 @@ func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.T {{- else }} return v, nil } + {{ end }}{{/* if not $.WriteOnly */}} {{- end }}{{/* if $.NestedProperties */}} {{- end }}{{/* if $.IsA "Map" */}} {{ if $.NestedProperties }} {{- range $prop := $.NestedProperties }} - {{- if not (and (hasPrefix $prop.Type "KeyValue") $prop.IgnoreWrite) }} + {{- if not (and (hasPrefix $prop.Type "KeyValue") (not $prop.WriteOnly)) }} {{- template "expandPropertyMethod" $prop -}} {{- end }} {{- end }} diff --git a/mmv1/templates/terraform/flatten_property_method.go.tmpl b/mmv1/templates/terraform/flatten_property_method.go.tmpl index 28d81ac7b0a0..5737fd68ad04 100644 --- a/mmv1/templates/terraform/flatten_property_method.go.tmpl +++ b/mmv1/templates/terraform/flatten_property_method.go.tmpl @@ -13,7 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -}} {{- define "flattenPropertyMethod" }} -{{- if $.CustomFlatten }} +{{- if $.WriteOnly }} +{{- else if $.CustomFlatten }} {{- $.CustomTemplate $.CustomFlatten false -}} {{- else -}} func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { @@ -33,7 +34,8 @@ func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.Reso {{- end }} transformed := make(map[string]interface{}) {{- range $prop := $.UserProperties }} - {{- if $prop.FlattenObject }} + {{- if $prop.WriteOnly }} + {{- else if $prop.FlattenObject }} if {{ $prop.ApiName }} := flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}{{$prop.TitlelizeProperty}}(original["{{ $prop.ApiName }}"], d, config); {{ $prop.ApiName }} != nil { obj := {{ $prop.ApiName }}.([]interface{})[0] for k, v := range obj.(map[string]interface{}) { @@ -73,7 +75,7 @@ func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.Reso {{- end }} {{- range $prop := $.ItemType.UserProperties }} - {{- if not $prop.IgnoreRead }} + {{- if not (or $prop.IgnoreRead $prop.WriteOnly) }} "{{ underscore $prop.Name }}": flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}{{$prop.TitlelizeProperty}}(original["{{ $prop.ApiName }}"], d, config), {{- end }} {{- end }} diff --git a/mmv1/templates/terraform/nested_property_documentation.html.markdown.tmpl b/mmv1/templates/terraform/nested_property_documentation.html.markdown.tmpl index 4b4979bc6193..038384cc64b9 100644 --- a/mmv1/templates/terraform/nested_property_documentation.html.markdown.tmpl +++ b/mmv1/templates/terraform/nested_property_documentation.html.markdown.tmpl @@ -1,9 +1,9 @@ {{ "" }} -{{- if $.FlattenObject }} +{{- if and $.FlattenObject (not $.WriteOnlyProperties) }} {{- range $np := $.NestedProperties }} {{- trimTemplate "nested_property_documentation.html.markdown.tmpl" $np -}} {{- end -}} -{{- else if $.NestedProperties }} +{{- else if and $.NestedProperties (not $.WriteOnlyProperties) }} The `{{ underscore $.Name }}` block {{ if $.Output }}contains{{ else }}supports{{ end }}: {{ "" }} {{- if $.IsA "Map" }} diff --git a/mmv1/templates/terraform/nested_property_write_only_documentation.html.markdown.tmpl b/mmv1/templates/terraform/nested_property_write_only_documentation.html.markdown.tmpl new file mode 100644 index 000000000000..4c4aa286648b --- /dev/null +++ b/mmv1/templates/terraform/nested_property_write_only_documentation.html.markdown.tmpl @@ -0,0 +1,27 @@ +{{- if $.WriteOnlyProperties }} +The `{{ underscore $.Name }}` block {{ if $.Output }}contains{{ else }}supports{{ end }}: +{{ "" }} + {{- if $.NestedProperties }} + {{- range $np := $.NestedProperties }} + {{- if $np.WriteOnly }} +{{- trimTemplate "property_documentation.html.markdown.tmpl" $np -}} + {{- end -}} + {{- end -}} +{{ "" }} + {{- $innerNested := false }} + {{- range $np := $.NestedProperties }} + {{- if $np.NestedProperties }} + {{- $innerNested = true }} + {{- end }} + {{- end }} + {{- if $innerNested}} +{{ "" }} + {{- end }} + {{- range $np := $.NestedProperties }} + {{- if $np.NestedProperties }} +{{- trimTemplate "nested_property_write_only_documentation.html.markdown.tmpl" $np -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{ "" }} \ No newline at end of file diff --git a/mmv1/templates/terraform/property_documentation.html.markdown.tmpl b/mmv1/templates/terraform/property_documentation.html.markdown.tmpl index 4eed7644c652..915a0775b761 100644 --- a/mmv1/templates/terraform/property_documentation.html.markdown.tmpl +++ b/mmv1/templates/terraform/property_documentation.html.markdown.tmpl @@ -36,6 +36,9 @@ {{- if $.Sensitive }} **Note**: This property is sensitive and will not be displayed in the plan. {{- end }} + {{- if $.WriteOnly }} + **Note**: This property is write-only and will not be read from the API. + {{- end }} {{- if and (not $.FlattenObject) $.NestedProperties }} Structure is [documented below](#nested_{{ underscore $.Name }}). {{- end }} diff --git a/mmv1/templates/terraform/resource.html.markdown.tmpl b/mmv1/templates/terraform/resource.html.markdown.tmpl index 1ae18803e773..521a36c51447 100644 --- a/mmv1/templates/terraform/resource.html.markdown.tmpl +++ b/mmv1/templates/terraform/resource.html.markdown.tmpl @@ -70,6 +70,11 @@ To get more information about {{$.Name}}, see: values will be stored in the raw state as plain text: {{ $.SensitivePropsToString }}. [Read more about sensitive data in state](https://www.terraform.io/language/state/sensitive-data). {{ end }} +{{- if $.WriteOnlyProps }} +~> **Warning:** All arguments including the following potentially write-only +values will be stored in the raw state as plain text: {{ $.WriteOnlyPropsToString }}. +[Read more about sensitive data in state](https://www.terraform.io/language/state/sensitive-data). +{{ end }} {{- if $.Examples }} {{- range $e := $.Examples }} {{- if not $e.ExcludeDocs }} @@ -96,7 +101,7 @@ The following arguments are supported: {{ "" }} {{ "" }} {{- range $p := $.RootProperties }} - {{- if $p.Required }} + {{- if and $p.Required (not $p.WriteOnly) }} {{- trimTemplate "property_documentation.html.markdown.tmpl" $p -}} {{- end }} {{- end }} @@ -110,7 +115,7 @@ The following arguments are supported: {{ "" }} {{ "" }} {{- range $p := $.RootProperties }} - {{- if and (not $p.Required) (not $p.Output) }} + {{- if and (not $p.Required) (not $p.Output) (not $p.WriteOnly) }} {{- trimTemplate "property_documentation.html.markdown.tmpl" $p -}} {{- end }} {{- end }} @@ -134,6 +139,21 @@ The following arguments are supported: {{- end}} {{- end }} {{- "" }} + +{{- if $.WriteOnlyProps }} +## Ephemeral Attributes Reference + +The following write-only attributes are supported: +{{ range $p := $.RootProperties }} + {{- if $p.WriteOnly }} +{{- trimTemplate "property_documentation.html.markdown.tmpl" $p }} + {{- end}} +{{- end }} +{{ range $p := $.AllUserProperties }} +{{- trimTemplate "nested_property_write_only_documentation.html.markdown.tmpl" $p }} +{{- end }} +{{- end }} + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: diff --git a/mmv1/templates/terraform/schema_property.go.tmpl b/mmv1/templates/terraform/schema_property.go.tmpl index 44f14792be9c..180e49cf6312 100644 --- a/mmv1/templates/terraform/schema_property.go.tmpl +++ b/mmv1/templates/terraform/schema_property.go.tmpl @@ -161,6 +161,9 @@ Default value: {{ .ItemType.DefaultValue -}} {{ if .Sensitive -}} Sensitive: true, {{ end -}} +{{ if .WriteOnly -}} + WriteOnly: true, +{{ end -}} {{ if not (eq .DefaultValue nil ) -}} Default: {{ .GoLiteral .DefaultValue -}}, {{ end -}} diff --git a/tpgtools/property.go b/tpgtools/property.go index 50cb4ae3acb9..2ea32ecfdcdd 100644 --- a/tpgtools/property.go +++ b/tpgtools/property.go @@ -67,6 +67,7 @@ type Property struct { Optional bool Computed bool Sensitive bool + WriteOnly bool ForceNew bool Description string diff --git a/tpgtools/templates/resource.go.tmpl b/tpgtools/templates/resource.go.tmpl index b65085ba771f..e4af20a9a561 100644 --- a/tpgtools/templates/resource.go.tmpl +++ b/tpgtools/templates/resource.go.tmpl @@ -117,6 +117,9 @@ func Resource{{$.PathType}}() *schema.Resource { {{- if $p.Sensitive}} Sensitive: true, {{- end }} + {{- if $p.WriteOnly }} + WriteOnly: true, + {{- end }} {{- if $p.DiffSuppressFunc }} DiffSuppressFunc: {{$p.DiffSuppressFunc}}, {{- end }} @@ -180,6 +183,9 @@ func {{$.PathType}}{{$v.PackagePath}}Schema() *schema.Resource { {{- if $p.Sensitive }} Sensitive: true, {{- end }} + {{- if $p.WriteOnly }} + WriteOnly: true, + {{- end }} {{- if $p.DiffSuppressFunc }} DiffSuppressFunc: {{$p.DiffSuppressFunc}}, {{- end }}