From 35087ed0ccba7680d5c9aba05b07f8b8bdd2b77d Mon Sep 17 00:00:00 2001 From: jregan Date: Mon, 21 Dec 2020 07:18:51 -0800 Subject: [PATCH] Add RNode.Set/GetDataMap to ease configmap generation. --- kyaml/yaml/rnode.go | 29 ++++++++ kyaml/yaml/rnode_test.go | 142 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/kyaml/yaml/rnode.go b/kyaml/yaml/rnode.go index 5e65436aa..3165d723d 100644 --- a/kyaml/yaml/rnode.go +++ b/kyaml/yaml/rnode.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "log" "strconv" "strings" @@ -417,6 +418,34 @@ func (rn *RNode) SetMapField(value *RNode, path ...string) error { ) } +func (rn *RNode) GetDataMap() map[string]string { + n, err := rn.Pipe(Lookup(DataField)) + if err != nil { + return nil + } + result := map[string]string{} + _ = n.VisitFields(func(node *MapNode) error { + result[GetValue(node.Key)] = GetValue(node.Value) + return nil + }) + return result +} + +func (rn *RNode) SetDataMap(m map[string]string) { + if rn == nil { + log.Fatal("cannot set data map on nil Rnode") + } + if len(m) == 0 { + if err := rn.PipeE(Clear(DataField)); err != nil { + log.Fatal(err) + } + return + } + if err := rn.SetMapField(NewMapRNode(&m), DataField); err != nil { + log.Fatal(err) + } +} + // AppendToFieldPath appends a field name to the FieldPath. func (rn *RNode) AppendToFieldPath(parts ...string) { rn.fieldPath = append(rn.fieldPath, parts...) diff --git a/kyaml/yaml/rnode_test.go b/kyaml/yaml/rnode_test.go index 48d83d190..b6b6cf580 100644 --- a/kyaml/yaml/rnode_test.go +++ b/kyaml/yaml/rnode_test.go @@ -115,6 +115,148 @@ func TestRNodeNewStringRNodeBinary(t *testing.T) { } } +func TestRNodeGetDataMap(t *testing.T) { + emptyMap := map[string]string{} + testCases := map[string]struct { + theMap map[string]interface{} + expected map[string]string + }{ + "actuallyNil": { + theMap: nil, + expected: emptyMap, + }, + "empty": { + theMap: map[string]interface{}{}, + expected: emptyMap, + }, + "mostlyEmpty": { + theMap: map[string]interface{}{ + "hey": "there", + }, + expected: emptyMap, + }, + "noNameConfigMap": { + theMap: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + }, + expected: emptyMap, + }, + "configmap": { + theMap: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "winnie", + }, + "data": map[string]string{ + "wine": "cabernet", + "truck": "ford", + "rocket": "falcon9", + "planet": "mars", + "city": "brownsville", + }, + }, + // order irrelevant, because assert.Equals is smart about maps. + expected: map[string]string{ + "city": "brownsville", + "wine": "cabernet", + "planet": "mars", + "rocket": "falcon9", + "truck": "ford", + }, + }, + } + + for n := range testCases { + tc := testCases[n] + t.Run(n, func(t *testing.T) { + rn, err := FromMap(tc.theMap) + if !assert.NoError(t, err) { + t.FailNow() + } + m := rn.GetDataMap() + if !assert.Equal(t, tc.expected, m) { + t.FailNow() + } + }) + } +} + +func TestRNodeSetDataMap(t *testing.T) { + testCases := map[string]struct { + theMap map[string]interface{} + input map[string]string + expected map[string]string + }{ + "empty": { + theMap: map[string]interface{}{}, + input: map[string]string{ + "wine": "cabernet", + "truck": "ford", + }, + expected: map[string]string{ + "wine": "cabernet", + "truck": "ford", + }, + }, + "replace": { + theMap: map[string]interface{}{ + "foo": 3, + "data": map[string]string{ + "rocket": "falcon9", + "planet": "mars", + }, + }, + input: map[string]string{ + "wine": "cabernet", + "truck": "ford", + }, + expected: map[string]string{ + "wine": "cabernet", + "truck": "ford", + }, + }, + "clear1": { + theMap: map[string]interface{}{ + "foo": 3, + "data": map[string]string{ + "rocket": "falcon9", + "planet": "mars", + }, + }, + input: map[string]string{}, + expected: map[string]string{}, + }, + "clear2": { + theMap: map[string]interface{}{ + "foo": 3, + "data": map[string]string{ + "rocket": "falcon9", + "planet": "mars", + }, + }, + input: nil, + expected: map[string]string{}, + }, + } + + for n := range testCases { + tc := testCases[n] + t.Run(n, func(t *testing.T) { + rn, err := FromMap(tc.theMap) + if !assert.NoError(t, err) { + t.FailNow() + } + rn.SetDataMap(tc.input) + m := rn.GetDataMap() + if !assert.Equal(t, tc.expected, m) { + t.FailNow() + } + }) + } +} + func TestRNodeGetValidatedMetadata(t *testing.T) { testConfigMap := map[string]interface{}{ "apiVersion": "v1",