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 }}