wrap JSON strings as jsonencode calls on generate-config-out (#1595)

Signed-off-by: ollevche <ollevche@gmail.com>
Signed-off-by: Oleksandr Levchenkov  <ollevche@gmail.com>
This commit is contained in:
Oleksandr Levchenkov 2024-05-10 18:37:40 +03:00 committed by GitHub
parent 82a6797894
commit b7098f50cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 108 additions and 1 deletions

View File

@ -6,6 +6,7 @@ NEW FEATURES:
ENHANCEMENTS:
* Added `tofu test -json` types to website Machine-Readable UI documentation ([1408](https://github.com/opentofu/opentofu/issues/1408))
* Made `tofu plan` with `generate-config-out` flag replace JSON strings with `jsonencode` functions calls. ([#1595](https://github.com/opentofu/opentofu/pull/1595))
BUG FIXES:
* Fixed crash in gcs backend when using certain commands ([#1618](https://github.com/opentofu/opentofu/pull/1618))

View File

@ -6,6 +6,7 @@
package genconfig
import (
"errors"
"fmt"
"sort"
"strings"
@ -13,6 +14,7 @@ import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/json"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
@ -160,7 +162,7 @@ func writeConfigAttributesFromExisting(addr addrs.AbsResourceInstance, buf *stri
if attrS.Sensitive || val.IsMarked() {
buf.WriteString("null # sensitive")
} else {
tok := hclwrite.TokensForValue(val)
tok := tryWrapAsJsonEncodeFunctionCall(val)
if _, err := tok.WriteTo(buf); err != nil {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
@ -592,3 +594,40 @@ func omitUnknowns(val cty.Value) cty.Value {
panic(fmt.Sprintf("omitUnknowns cannot handle %#v", val))
}
}
func tryWrapAsJsonEncodeFunctionCall(v cty.Value) hclwrite.Tokens {
tokens, err := wrapAsJSONEncodeFunctionCall(v)
if err != nil {
return hclwrite.TokensForValue(v)
}
return tokens
}
func wrapAsJSONEncodeFunctionCall(v cty.Value) (hclwrite.Tokens, error) {
if v.IsNull() || v.Type() != cty.String || !v.IsKnown() {
return nil, errors.New("value cannot be treated as JSON string")
}
s := []byte(strings.TrimSpace(v.AsString()))
if len(s) == 0 {
return nil, errors.New("empty value")
}
if s[0] != '{' && s[0] != '[' {
return nil, errors.New("value is not a JSON object, nor a JSON array")
}
t, err := json.ImpliedType(s)
if err != nil {
return nil, fmt.Errorf("cannot define implied cty type (possibly not a JSON string): %w", err)
}
v, err = json.Unmarshal(s, t)
if err != nil {
return nil, fmt.Errorf("cannot unmarshal using implied type (possible not a JSON string): %w", err)
}
tokens := hclwrite.TokensForFunctionCall("jsonencode", hclwrite.TokensForValue(v))
return tokens, nil
}

View File

@ -423,6 +423,73 @@ resource "tfcoremock_simple_resource" "empty" {
list = null
map = null
single = null
}`,
},
"jsonencode_wrapping": {
schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"juststr": {
Type: cty.String,
Optional: true,
},
"jsonobj": {
Type: cty.String,
Optional: true,
},
"jsonarr": {
Type: cty.String,
Optional: true,
},
"sensitivejsonobj": {
Type: cty.String,
Optional: true,
Sensitive: true,
},
"secrets": {
Type: cty.Object(map[string]cty.Type{
"main": cty.String,
"secondary": cty.String,
}),
Optional: true,
Sensitive: true,
},
},
},
addr: addrs.AbsResourceInstance{
Module: nil,
Resource: addrs.ResourceInstance{
Resource: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "tfcoremock_simple_resource",
Name: "example",
},
Key: nil,
},
},
provider: addrs.LocalProviderConfig{
LocalName: "tfcoremock",
},
value: cty.ObjectVal(map[string]cty.Value{
"juststr": cty.StringVal("{a=b}"),
"jsonobj": cty.StringVal(`{"SomeDate":"2012-10-17"}`),
"jsonarr": cty.StringVal(`[{"a": 1}]`),
"sensitivejsonobj": cty.StringVal(`{"SomePassword":"dontstealplease"}`),
"secrets": cty.ObjectVal(map[string]cty.Value{
"main": cty.StringVal(`{"v":"mypass"}`),
"secondary": cty.StringVal(`{"v":"mybackup"}`),
}),
}),
expected: `
resource "tfcoremock_simple_resource" "example" {
jsonarr = jsonencode([{
a = 1
}])
jsonobj = jsonencode({
SomeDate = "2012-10-17"
})
juststr = "{a=b}"
secrets = null # sensitive
sensitivejsonobj = null # sensitive
}`,
},
}