-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
datamap.go
121 lines (112 loc) · 2.87 KB
/
datamap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// 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 (rn *RNode) LoadMapIntoConfigMapBinaryData(m map[string]string) error {
for _, k := range SortedMapKeys(m) {
_, vrN := makeConfigMapValueRNode(m[k])
// we know this is binary data
fldName := BinaryDataField
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 {
mapNode, err := rn.Pipe(LookupCreate(MappingNode, DataField))
if err != nil {
return err
}
for _, k := range SortedMapKeys(m) {
vrN := makeSecretValueRNode(m[k])
if _, err := mapNode.Pipe(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])
}