Skip to content

Commit

Permalink
fix: applying fields to the ArgoCD map may result in inconsistent ord…
Browse files Browse the repository at this point in the history
…ers (#217)

Fixes #211
  • Loading branch information
hanxiaop authored Jul 11, 2024
1 parent 4988580 commit d89b41a
Showing 1 changed file with 82 additions and 7 deletions.
89 changes: 82 additions & 7 deletions akp/types/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ package types

import (
"context"
"encoding/json"
"fmt"
"sort"

"github.com/hashicorp/terraform-plugin-framework/diag"
tftypes "github.com/hashicorp/terraform-plugin-framework/types"
"google.golang.org/protobuf/types/known/structpb"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/akuity/terraform-provider-akp/akp/marshal"
)

func ToConfigMapTFModel(ctx context.Context, diagnostics *diag.Diagnostics, data *structpb.Struct, oldCM tftypes.Map) tftypes.Map {
Expand All @@ -19,12 +19,21 @@ func ToConfigMapTFModel(ctx context.Context, diagnostics *diag.Diagnostics, data
return oldCM
}
}
m := map[string]string{}
err := marshal.RemarshalTo(data, &m)
if err != nil {
diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get ConfigMap data. %s", err))
return tftypes.MapNull(tftypes.StringType)
m := data.AsMap()
for k, v := range m {
switch t := v.(type) {
case string:
sortedValue, err := sortJSONString(t)
if err != nil {
diagnostics.AddError("Client Error", fmt.Sprintf("Unable to sort JSON keys for key %s. %s", k, err))
return tftypes.MapNull(tftypes.StringType)
}
m[k] = sortedValue
default:
m[k] = v
}
}

newData, diag := tftypes.MapValueFrom(ctx, tftypes.StringType, &m)
diagnostics.Append(diag...)
return newData
Expand All @@ -33,6 +42,16 @@ func ToConfigMapTFModel(ctx context.Context, diagnostics *diag.Diagnostics, data
func ToConfigMapAPIModel(ctx context.Context, diagnostics *diag.Diagnostics, name string, m tftypes.Map) *v1.ConfigMap {
var data map[string]string
diagnostics.Append(m.ElementsAs(ctx, &data, true)...)
for k, v := range data {
if json.Valid([]byte(v)) {
sortedValue, err := sortJSONString(v)
if err != nil {
diagnostics.AddError("Client Error", fmt.Sprintf("Unable to sort JSON keys for key %s. %s", k, err))
return nil
}
data[k] = sortedValue
}
}
return &v1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
Expand All @@ -44,3 +63,59 @@ func ToConfigMapAPIModel(ctx context.Context, diagnostics *diag.Diagnostics, nam
Data: data,
}
}

func sortJSONKeys(value any) (any, error) {
switch v := value.(type) {
case map[string]any:
sortedMap := make(map[string]any)
keys := make([]string, 0, len(v))
for k := range v {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
sortedValue, err := sortJSONKeys(v[k])
if err != nil {
return nil, err
}
sortedMap[k] = sortedValue
}
return sortedMap, nil
case []any:
sortedArray := make([]any, len(v))
for i, item := range v {
sortedValue, err := sortJSONKeys(item)
if err != nil {
return nil, err
}
sortedArray[i] = sortedValue
}
return sortedArray, nil
default:
return v, nil
}
}

func sortJSONString(jsonStr string) (string, error) {
if !json.Valid([]byte(jsonStr)) {
return jsonStr, nil
}

var data any
err := json.Unmarshal([]byte(jsonStr), &data)
if err != nil {
return "", err
}

sortedData, err := sortJSONKeys(data)
if err != nil {
return "", err
}

sortedJSON, err := json.Marshal(sortedData)
if err != nil {
return "", err
}

return string(sortedJSON), nil
}

0 comments on commit d89b41a

Please sign in to comment.