...

Source file src/sigs.k8s.io/kustomize/kyaml/yaml/datamap.go

Documentation: sigs.k8s.io/kustomize/kyaml/yaml

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package yaml
     5  
     6  import (
     7  	"encoding/base64"
     8  	"sort"
     9  	"strings"
    10  	"unicode/utf8"
    11  )
    12  
    13  // SortedMapKeys returns a sorted slice of keys to the given map.
    14  // Writing this function never gets old.
    15  func SortedMapKeys(m map[string]string) []string {
    16  	keys := make([]string, len(m))
    17  	i := 0
    18  	for k := range m {
    19  		keys[i] = k
    20  		i++
    21  	}
    22  	sort.Strings(keys)
    23  	return keys
    24  }
    25  
    26  func (rn *RNode) LoadMapIntoConfigMapData(m map[string]string) error {
    27  	for _, k := range SortedMapKeys(m) {
    28  		fldName, vrN := makeConfigMapValueRNode(m[k])
    29  		if _, err := rn.Pipe(
    30  			LookupCreate(MappingNode, fldName),
    31  			SetField(k, vrN)); err != nil {
    32  			return err
    33  		}
    34  	}
    35  	return nil
    36  }
    37  
    38  func (rn *RNode) LoadMapIntoConfigMapBinaryData(m map[string]string) error {
    39  	for _, k := range SortedMapKeys(m) {
    40  		_, vrN := makeConfigMapValueRNode(m[k])
    41  		// we know this is binary data
    42  		fldName := BinaryDataField
    43  		if _, err := rn.Pipe(
    44  			LookupCreate(MappingNode, fldName),
    45  			SetField(k, vrN)); err != nil {
    46  			return err
    47  		}
    48  	}
    49  	return nil
    50  }
    51  
    52  func makeConfigMapValueRNode(s string) (field string, rN *RNode) {
    53  	yN := &Node{Kind: ScalarNode}
    54  	yN.Tag = NodeTagString
    55  	if utf8.ValidString(s) {
    56  		field = DataField
    57  		yN.Value = s
    58  	} else {
    59  		field = BinaryDataField
    60  		yN.Value = encodeBase64(s)
    61  	}
    62  	if strings.Contains(yN.Value, "\n") {
    63  		yN.Style = LiteralStyle
    64  	}
    65  	return field, NewRNode(yN)
    66  }
    67  
    68  func (rn *RNode) LoadMapIntoSecretData(m map[string]string) error {
    69  	mapNode, err := rn.Pipe(LookupCreate(MappingNode, DataField))
    70  	if err != nil {
    71  		return err
    72  	}
    73  	for _, k := range SortedMapKeys(m) {
    74  		vrN := makeSecretValueRNode(m[k])
    75  		if _, err := mapNode.Pipe(SetField(k, vrN)); err != nil {
    76  			return err
    77  		}
    78  	}
    79  	return nil
    80  }
    81  
    82  // In a secret, all data is base64 encoded, regardless of its conformance
    83  // or lack thereof to UTF-8.
    84  func makeSecretValueRNode(s string) *RNode {
    85  	yN := &Node{Kind: ScalarNode}
    86  	// Purposely don't use YAML tags to identify the data as being plain text or
    87  	// binary.  It kubernetes Secrets the values in the `data` map are expected
    88  	// to be base64 encoded, and in ConfigMaps that same can be said for the
    89  	// values in the `binaryData` field.
    90  	yN.Tag = NodeTagString
    91  	yN.Value = encodeBase64(s)
    92  	if strings.Contains(yN.Value, "\n") {
    93  		yN.Style = LiteralStyle
    94  	}
    95  	return NewRNode(yN)
    96  }
    97  
    98  // encodeBase64 encodes s as base64 that is broken up into multiple lines
    99  // as appropriate for the resulting length.
   100  func encodeBase64(s string) string {
   101  	const lineLen = 70
   102  	encLen := base64.StdEncoding.EncodedLen(len(s))
   103  	lines := encLen/lineLen + 1
   104  	buf := make([]byte, encLen*2+lines)
   105  	in := buf[0:encLen]
   106  	out := buf[encLen:]
   107  	base64.StdEncoding.Encode(in, []byte(s))
   108  	k := 0
   109  	for i := 0; i < len(in); i += lineLen {
   110  		j := i + lineLen
   111  		if j > len(in) {
   112  			j = len(in)
   113  		}
   114  		k += copy(out[k:], in[i:j])
   115  		if lines > 1 {
   116  			out[k] = '\n'
   117  			k++
   118  		}
   119  	}
   120  	return string(out[:k])
   121  }
   122  

View as plain text