From b3fc306f6a9bb942f1d48c34cf58442e91612bae Mon Sep 17 00:00:00 2001 From: monopole Date: Thu, 14 Jan 2021 10:10:10 -0800 Subject: [PATCH] Move some code to make it reusable without import cycles. --- api/filters/annotations/annotations.go | 2 +- api/filters/filtersutil/filtersutil.go | 21 ---- api/filters/labels/labels.go | 2 +- api/internal/generators/configmap.go | 12 +- api/internal/generators/secret.go | 12 +- api/internal/generators/utils.go | 65 +---------- kyaml/yaml/datamap.go | 105 ++++++++++++++++++ .../yaml/datamap_test.go | 10 +- 8 files changed, 122 insertions(+), 107 deletions(-) delete mode 100644 api/filters/filtersutil/filtersutil.go create mode 100644 kyaml/yaml/datamap.go rename api/filters/filtersutil/filtersutil_test.go => kyaml/yaml/datamap_test.go (76%) diff --git a/api/filters/annotations/annotations.go b/api/filters/annotations/annotations.go index d54a8f41d..cd0e3b4d5 100644 --- a/api/filters/annotations/annotations.go +++ b/api/filters/annotations/annotations.go @@ -24,7 +24,7 @@ type Filter struct { var _ kio.Filter = Filter{} func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { - keys := filtersutil.SortedMapKeys(f.Annotations) + keys := yaml.SortedMapKeys(f.Annotations) _, err := kio.FilterAll(yaml.FilterFunc( func(node *yaml.RNode) (*yaml.RNode, error) { for _, k := range keys { diff --git a/api/filters/filtersutil/filtersutil.go b/api/filters/filtersutil/filtersutil.go deleted file mode 100644 index cbbab0652..000000000 --- a/api/filters/filtersutil/filtersutil.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package filtersutil - -import ( - "sort" -) - -// SortedMapKeys returns a sorted slice of keys to the given map. -// Writing this function never gets old. -func SortedMapKeys(m map[string]string) []string { - keys := make([]string, len(m)) - i := 0 - for k := range m { - keys[i] = k - i++ - } - sort.Strings(keys) - return keys -} diff --git a/api/filters/labels/labels.go b/api/filters/labels/labels.go index 802d966db..92f298bfe 100644 --- a/api/filters/labels/labels.go +++ b/api/filters/labels/labels.go @@ -25,7 +25,7 @@ type Filter struct { var _ kio.Filter = Filter{} func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { - keys := filtersutil.SortedMapKeys(f.Labels) + keys := yaml.SortedMapKeys(f.Labels) _, err := kio.FilterAll(yaml.FilterFunc( func(node *yaml.RNode) (*yaml.RNode, error) { for _, k := range keys { diff --git a/api/internal/generators/configmap.go b/api/internal/generators/configmap.go index d09cbb5b5..19a0e2832 100644 --- a/api/internal/generators/configmap.go +++ b/api/internal/generators/configmap.go @@ -4,7 +4,6 @@ package generators import ( - "sigs.k8s.io/kustomize/api/filters/filtersutil" "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/yaml" @@ -38,14 +37,9 @@ func MakeConfigMap( if err != nil { return nil, err } - for _, k := range filtersutil.SortedMapKeys(m) { - fldName, vrN := makeConfigMapValueRNode(m[k]) - if _, err = rn.Pipe( - yaml.LookupCreate(yaml.MappingNode, fldName), - yaml.SetField(k, vrN)); err != nil { - return nil, err - } + if err = rn.LoadMapIntoConfigMapData(m); err != nil { + return nil, err } copyLabelsAndAnnotations(rn, args.Options) - return rn, err + return rn, nil } diff --git a/api/internal/generators/secret.go b/api/internal/generators/secret.go index d8e14f88f..a46f497db 100644 --- a/api/internal/generators/secret.go +++ b/api/internal/generators/secret.go @@ -4,7 +4,6 @@ package generators import ( - "sigs.k8s.io/kustomize/api/filters/filtersutil" "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/yaml" @@ -51,14 +50,9 @@ func MakeSecret( if err != nil { return nil, err } - for _, k := range filtersutil.SortedMapKeys(m) { - vrN := makeSecretValueRNode(m[k]) - if _, err = rn.Pipe( - yaml.LookupCreate(yaml.MappingNode, yaml.DataField), - yaml.SetField(k, vrN)); err != nil { - return nil, err - } + if err = rn.LoadMapIntoSecretData(m); err != nil { + return nil, err } copyLabelsAndAnnotations(rn, args.Options) - return rn, err + return rn, nil } diff --git a/api/internal/generators/utils.go b/api/internal/generators/utils.go index 1b2cff3fb..d1630fc84 100644 --- a/api/internal/generators/utils.go +++ b/api/internal/generators/utils.go @@ -4,13 +4,9 @@ package generators import ( - "encoding/base64" "fmt" - "strings" - "unicode/utf8" "github.com/go-errors/errors" - "sigs.k8s.io/kustomize/api/filters/filtersutil" "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/yaml" @@ -66,13 +62,13 @@ func copyLabelsAndAnnotations( if opts == nil { return nil } - for _, k := range filtersutil.SortedMapKeys(opts.Labels) { + for _, k := range yaml.SortedMapKeys(opts.Labels) { v := opts.Labels[k] if _, err := rn.Pipe(yaml.SetLabel(k, v)); err != nil { return err } } - for _, k := range filtersutil.SortedMapKeys(opts.Annotations) { + for _, k := range yaml.SortedMapKeys(opts.Annotations) { v := opts.Annotations[k] if _, err := rn.Pipe(yaml.SetAnnotation(k, v)); err != nil { return err @@ -80,60 +76,3 @@ func copyLabelsAndAnnotations( } return nil } - -// In a secret, all data is base64 encoded, regardless of its conformance -// or lack thereof to UTF-8. -func makeSecretValueRNode(s string) *yaml.RNode { - yN := &yaml.Node{Kind: yaml.ScalarNode} - // Purposely don't use YAML tags to identify the data as being plain text or - // binary. It kubernetes Secrets the values in the `data` map are expected - // to be base64 encoded, and in ConfigMaps that same can be said for the - // values in the `binaryData` field. - yN.Tag = yaml.NodeTagString - yN.Value = encodeBase64(s) - if strings.Contains(yN.Value, "\n") { - yN.Style = yaml.LiteralStyle - } - return yaml.NewRNode(yN) -} - -func makeConfigMapValueRNode(s string) (field string, rN *yaml.RNode) { - yN := &yaml.Node{Kind: yaml.ScalarNode} - yN.Tag = yaml.NodeTagString - if utf8.ValidString(s) { - field = yaml.DataField - yN.Value = s - } else { - field = yaml.BinaryDataField - yN.Value = encodeBase64(s) - } - if strings.Contains(yN.Value, "\n") { - yN.Style = yaml.LiteralStyle - } - return field, yaml.NewRNode(yN) -} - -// encodeBase64 encodes s as base64 that is broken up into multiple lines -// as appropriate for the resulting length. -func encodeBase64(s string) string { - const lineLen = 70 - encLen := base64.StdEncoding.EncodedLen(len(s)) - lines := encLen/lineLen + 1 - buf := make([]byte, encLen*2+lines) - in := buf[0:encLen] - out := buf[encLen:] - base64.StdEncoding.Encode(in, []byte(s)) - k := 0 - for i := 0; i < len(in); i += lineLen { - j := i + lineLen - if j > len(in) { - j = len(in) - } - k += copy(out[k:], in[i:j]) - if lines > 1 { - out[k] = '\n' - k++ - } - } - return string(out[:k]) -} diff --git a/kyaml/yaml/datamap.go b/kyaml/yaml/datamap.go new file mode 100644 index 000000000..b3e7d5683 --- /dev/null +++ b/kyaml/yaml/datamap.go @@ -0,0 +1,105 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package yaml + +import ( + "encoding/base64" + "sort" + "strings" + "unicode/utf8" +) + +// SortedMapKeys returns a sorted slice of keys to the given map. +// Writing this function never gets old. +func SortedMapKeys(m map[string]string) []string { + keys := make([]string, len(m)) + i := 0 + for k := range m { + keys[i] = k + i++ + } + sort.Strings(keys) + return keys +} + +func (rn *RNode) LoadMapIntoConfigMapData(m map[string]string) error { + for _, k := range SortedMapKeys(m) { + fldName, vrN := makeConfigMapValueRNode(m[k]) + if _, err := rn.Pipe( + LookupCreate(MappingNode, fldName), + SetField(k, vrN)); err != nil { + return err + } + } + return nil +} + +func makeConfigMapValueRNode(s string) (field string, rN *RNode) { + yN := &Node{Kind: ScalarNode} + yN.Tag = NodeTagString + if utf8.ValidString(s) { + field = DataField + yN.Value = s + } else { + field = BinaryDataField + yN.Value = encodeBase64(s) + } + if strings.Contains(yN.Value, "\n") { + yN.Style = LiteralStyle + } + return field, NewRNode(yN) +} + +func (rn *RNode) LoadMapIntoSecretData(m map[string]string) error { + for _, k := range SortedMapKeys(m) { + vrN := makeSecretValueRNode(m[k]) + if _, err := rn.Pipe( + LookupCreate(MappingNode, DataField), + SetField(k, vrN)); err != nil { + return err + } + } + return nil +} + +// In a secret, all data is base64 encoded, regardless of its conformance +// or lack thereof to UTF-8. +func makeSecretValueRNode(s string) *RNode { + yN := &Node{Kind: ScalarNode} + // Purposely don't use YAML tags to identify the data as being plain text or + // binary. It kubernetes Secrets the values in the `data` map are expected + // to be base64 encoded, and in ConfigMaps that same can be said for the + // values in the `binaryData` field. + yN.Tag = NodeTagString + yN.Value = encodeBase64(s) + if strings.Contains(yN.Value, "\n") { + yN.Style = LiteralStyle + } + return NewRNode(yN) +} + +// encodeBase64 encodes s as base64 that is broken up into multiple lines +// as appropriate for the resulting length. +func encodeBase64(s string) string { + const lineLen = 70 + encLen := base64.StdEncoding.EncodedLen(len(s)) + lines := encLen/lineLen + 1 + buf := make([]byte, encLen*2+lines) + in := buf[0:encLen] + out := buf[encLen:] + base64.StdEncoding.Encode(in, []byte(s)) + k := 0 + for i := 0; i < len(in); i += lineLen { + j := i + lineLen + if j > len(in) { + j = len(in) + } + k += copy(out[k:], in[i:j]) + if lines > 1 { + out[k] = '\n' + k++ + } + } + return string(out[:k]) +} diff --git a/api/filters/filtersutil/filtersutil_test.go b/kyaml/yaml/datamap_test.go similarity index 76% rename from api/filters/filtersutil/filtersutil_test.go rename to kyaml/yaml/datamap_test.go index eb1618482..72f684daa 100644 --- a/api/filters/filtersutil/filtersutil_test.go +++ b/kyaml/yaml/datamap_test.go @@ -1,10 +1,13 @@ -package filtersutil_test +// Copyright 2021 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package yaml_test import ( "testing" "github.com/stretchr/testify/assert" - "sigs.k8s.io/kustomize/api/filters/filtersutil" + "sigs.k8s.io/kustomize/kyaml/yaml" ) func TestSortedKeys(t *testing.T) { @@ -23,9 +26,10 @@ func TestSortedKeys(t *testing.T) { expected: []string{"a", "b", "c"}}, } for tn, tc := range testCases { + tc := tc t.Run(tn, func(t *testing.T) { if !assert.Equal(t, - filtersutil.SortedMapKeys(tc.input), + yaml.SortedMapKeys(tc.input), tc.expected) { t.FailNow() }