Open aballiet opened 1 year ago
Here is a loom video showcasing the issue: https://www.loom.com/share/c498cb2085e542c89070b00e067a0c44?sid=dbd0ea7c-a50c-4887-a64d-20b55c7f7f7c
Please ensure it is resolved before removing the option keep_original_source = false
After digging a bit with @tchiotludo, this issue should be fixed by following using the CustomizeDiff function in the Terraform SDK to normalize and compare YAML content. This approach ensures consistent key ordering and structure during diff computations.
Here’s how you can implement this:
We can leverage setAttribute
function to do it, see doc here
ChatGPT code:
package provider
import (
"bytes"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"gopkg.in/yaml.v3"
"sort"
)
func normalizeYAML(input string) (string, error) {
var parsed map[string]interface{}
// Parse YAML
if err := yaml.Unmarshal([]byte(input), &parsed); err != nil {
return "", err
}
// Sort and serialize
normalized, err := marshalSorted(parsed)
if err != nil {
return "", err
}
return normalized, nil
}
func marshalSorted(data interface{}) (string, error) {
var buffer bytes.Buffer
// Custom sort implementation for YAML keys
encoder := yaml.NewEncoder(&buffer)
defer encoder.Close()
if err := encodeWithSortedKeys(encoder, data); err != nil {
return "", err
}
return buffer.String(), nil
}
func encodeWithSortedKeys(encoder *yaml.Encoder, data interface{}) error {
switch v := data.(type) {
case map[string]interface{}:
keys := make([]string, 0, len(v))
for k := range v {
keys = append(keys, k)
}
sort.Strings(keys)
ordered := make(map[string]interface{})
for _, k := range keys {
ordered[k] = v[k]
}
return encoder.Encode(ordered)
case []interface{}:
for _, item := range v {
if err := encodeWithSortedKeys(encoder, item); err != nil {
return err
}
}
default:
return encoder.Encode(v)
}
return nil
}
func CustomizeDiff(ctx resource.CustomizeDiffContext, req resource.CustomizeDiffRequest, resp *resource.CustomizeDiffResponse) {
var content types.String
// Read the "content" attribute
req.Config.GetAttribute(ctx, path.Root("content"), &content)
if content.IsNull() || content.IsUnknown() {
return
}
normalized, err := normalizeYAML(content.ValueString())
if err != nil {
resp.Diagnostics.AddError("YAML Normalization Error", "Failed to normalize YAML: "+err.Error())
return
}
// Store normalized content as a computed attribute or compare it for diffs
resp.Plan.SetAttribute(ctx, path.Root("normalized_content"), types.StringValue(normalized))
}
Expected Behavior
We expect to have a proper diff when applying changes to the
content
of a flow.Actual Behaviour
Currently output is unreadable.
Steps To Reproduce
terraform plan
and check diffYou can reproduce the experience with
keep_original_source = false
. In that case we will work as expected.Environment Information
Example flow
No response