binary data nope

This commit is contained in:
jregan
2020-11-19 16:46:25 -08:00
parent eda7a9f8d6
commit b88e770b1d
12 changed files with 780 additions and 584 deletions

View File

@@ -23,6 +23,7 @@ const (
KindField = "kind"
MetadataField = "metadata"
DataField = "data"
BinaryDataField = "binaryData"
NameField = "name"
NamespaceField = "namespace"
LabelsField = "labels"

View File

@@ -4,10 +4,6 @@
package yaml
import (
"fmt"
"strings"
"unicode/utf8"
"gopkg.in/yaml.v3"
"sigs.k8s.io/kustomize/kyaml/errors"
)
@@ -44,46 +40,6 @@ func ClearEmptyAnnotations(rn *RNode) error {
return nil
}
// k8sDataSetter place key value pairs in either a 'data' or 'binaryData' field.
// Useful for creating ConfigMaps and Secrets.
type k8sDataSetter struct {
Key string `yaml:"key,omitempty"`
Value string `yaml:"value,omitempty"`
ProtectExisting bool `yaml:"protectExisting,omitempty"`
}
func (s k8sDataSetter) Filter(rn *RNode) (*RNode, error) {
if !utf8.Valid([]byte(s.Value)) {
// Core k8s ConfigMaps store k,v pairs with 'v' passing the above utf8
// test in a mapping field called "data" as a string. Pairs with a 'v'
// failing this test go into a field called binaryData as a []byte.
// TODO: support this distinction in kyaml with NodeTagBytes?
return nil, errors.Errorf(
"key '%s' appears to have non-utf8 data; "+
"binaryData field not yet supported", s.Key)
}
keyNode, err := rn.Pipe(Lookup(DataField, s.Key))
if err != nil {
return nil, err
}
if keyNode != nil && s.ProtectExisting {
return nil, fmt.Errorf(
"protecting existing %s='%s' against attempt to add new value '%s'",
s.Key, strings.TrimSpace(keyNode.MustString()), s.Value)
}
v := NewScalarRNode(s.Value)
v.YNode().Tag = NodeTagString
// TODO: use schema to determine node style and tag.
// FormatNonStringStyle(v.YNode(), *k8sSch)
_, err = rn.Pipe(
LookupCreate(yaml.MappingNode, DataField), SetField(s.Key, v))
return rn, err
}
func SetK8sData(key, value string) k8sDataSetter {
return k8sDataSetter{Key: key, Value: value, ProtectExisting: true}
}
// k8sMetaSetter sets a name at metadata.{key}.
// Creates metadata if does not exist.
type k8sMetaSetter struct {
@@ -92,11 +48,9 @@ type k8sMetaSetter struct {
}
func (s k8sMetaSetter) Filter(rn *RNode) (*RNode, error) {
v := NewScalarRNode(s.Value)
v.YNode().Tag = NodeTagString
_, err := rn.Pipe(
PathGetter{Path: []string{MetadataField}, Create: yaml.MappingNode},
FieldSetter{Name: s.Key, Value: v})
FieldSetter{Name: s.Key, Value: NewStringRNode(s.Value)})
return rn, err
}
@@ -117,20 +71,13 @@ type AnnotationSetter struct {
}
func (s AnnotationSetter) Filter(rn *RNode) (*RNode, error) {
v := NewStringRNode(s.Value)
// some tools get confused about the type if annotations are not quoted
v := NewScalarRNode(s.Value)
v.YNode().Tag = NodeTagString
v.YNode().Style = yaml.SingleQuotedStyle
if err := ClearEmptyAnnotations(rn); err != nil {
return nil, err
}
return rn.Pipe(
PathGetter{
Path: []string{MetadataField, AnnotationsField},
Create: yaml.MappingNode},
FieldSetter{Name: s.Key, Value: v})
return addMetadataNode(rn, AnnotationsField, s.Key, v)
}
func SetAnnotation(key, value string) AnnotationSetter {
@@ -172,14 +119,17 @@ type LabelSetter struct {
}
func (s LabelSetter) Filter(rn *RNode) (*RNode, error) {
v := NewStringRNode(s.Value)
// some tools get confused about the type if labels are not quoted
v := NewScalarRNode(s.Value)
v.YNode().Tag = NodeTagString
v.YNode().Style = yaml.SingleQuotedStyle
return addMetadataNode(rn, LabelsField, s.Key, v)
}
func addMetadataNode(rn *RNode, field, key string, v *RNode) (*RNode, error) {
return rn.Pipe(
PathGetter{
Path: []string{MetadataField, LabelsField}, Create: yaml.MappingNode},
FieldSetter{Name: s.Key, Value: v})
Path: []string{MetadataField, field}, Create: yaml.MappingNode},
FieldSetter{Name: key, Value: v})
}
func SetLabel(key, value string) LabelSetter {

View File

@@ -9,56 +9,6 @@ import (
"github.com/stretchr/testify/assert"
)
var input = `apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Good Morning!"
enableRisky: "false"
`
func TestSetK8sData(t *testing.T) {
rn := MustParse(`apiVersion: v1
kind: ConfigMap
data:
altGreeting: "Good Morning!"
`)
_, err := rn.Pipe(
SetK8sData("foo", "bar"),
SetK8sData("fruit", "apple"),
SetK8sData("veggie", "celery"))
assert.NoError(t, err)
output := rn.MustString()
expected := `apiVersion: v1
kind: ConfigMap
data:
altGreeting: "Good Morning!"
foo: bar
fruit: apple
veggie: celery
`
if !assert.Equal(t, expected, output) {
t.FailNow()
}
}
func TestSetK8sDataForbidOverwrite(t *testing.T) {
rn := MustParse(`apiVersion: v1
kind: ConfigMap
data:
altGreeting: "Good Morning!"
`)
_, err := rn.Pipe(
SetK8sData("foo", "bar"),
SetK8sData("altGreeting", "hey"),
SetK8sData("veggie", "celery"))
assert.EqualError(
t, err, "protecting existing altGreeting='\"Good Morning!\"' "+
"against attempt to add new value 'hey'")
}
func TestSetMeta(t *testing.T) {
rn := MustParse(`apiVersion: v1
kind: ConfigMap
@@ -85,7 +35,14 @@ metadata:
}
func TestSetLabel1(t *testing.T) {
rn := MustParse(input)
rn := MustParse(`apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Good Morning!"
enableRisky: "false"
`)
_, err := rn.Pipe(SetLabel("foo", "bar"))
if err != nil {
t.Fatalf("unexpected error %v", err)
@@ -133,7 +90,14 @@ metadata:
}
func TestAnnotation(t *testing.T) {
rn := MustParse(input)
rn := MustParse(`apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Good Morning!"
enableRisky: "false"
`)
_, err := rn.Pipe(SetAnnotation("foo", "bar"))
if err != nil {
t.Fatalf("unexpected error %v", err)

View File

@@ -100,6 +100,15 @@ func NewScalarRNode(value string) *RNode {
}}
}
// NewStringRNode returns a new Scalar *RNode containing the provided string.
// If the string is non-utf8, it will be base64 encoded, and the tag
// will indicate binary data.
func NewStringRNode(value string) *RNode {
n := yaml.Node{Kind: yaml.ScalarNode}
n.SetString(value)
return NewRNode(&n)
}
// NewListRNode returns a new List *RNode containing the provided scalar values.
func NewListRNode(values ...string) *RNode {
seq := &RNode{value: &yaml.Node{Kind: yaml.SequenceNode}}

View File

@@ -90,6 +90,31 @@ func TestRNodeHasNilEntryInList(t *testing.T) {
}
}
func TestRNodeNewStringRNodeText(t *testing.T) {
rn := NewStringRNode("cat")
if !assert.Equal(t, `cat
`,
rn.MustString()) {
t.FailNow()
}
}
func TestRNodeNewStringRNodeBinary(t *testing.T) {
rn := NewStringRNode(string([]byte{
0xff, // non-utf8
0x68, // h
0x65, // e
0x6c, // l
0x6c, // l
0x6f, // o
}))
if !assert.Equal(t, `!!binary /2hlbGxv
`,
rn.MustString()) {
t.FailNow()
}
}
func TestRNodeGetValidatedMetadata(t *testing.T) {
testConfigMap := map[string]interface{}{
"apiVersion": "v1",