From ec64ef705b96f0ffb5fc3f3c6198ebc9ec31e138 Mon Sep 17 00:00:00 2001 From: jregan Date: Wed, 25 Nov 2020 07:03:12 -0800 Subject: [PATCH] Add metadata getters and setters to RNode. These setters completely remove the field if the argument is empty, rather than setting the field to an empty value, mimicing apimachinery behavior. --- kyaml/yaml/rnode.go | 82 +++++++++++++++++++++++++++++++ kyaml/yaml/rnode_test.go | 101 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) diff --git a/kyaml/yaml/rnode.go b/kyaml/yaml/rnode.go index 810597212..8b73938f9 100644 --- a/kyaml/yaml/rnode.go +++ b/kyaml/yaml/rnode.go @@ -333,6 +333,88 @@ func (rn *RNode) SetYNode(node *yaml.Node) { *rn.value = *node } +// GetNamespace gets the metadata namespace field. +func (rn *RNode) GetNamespace() (string, error) { + meta, err := rn.GetMeta() + if err != nil { + return "", err + } + return meta.Namespace, nil +} + +// SetNamespace tries to set the metadata namespace field. +func (rn *RNode) SetNamespace(ns string) error { + meta, err := rn.Pipe(Lookup(MetadataField)) + if err != nil { + return err + } + if ns == "" { + if rn == nil { + return nil + } + return meta.PipeE(Clear(NamespaceField)) + } + return rn.SetMapField( + NewScalarRNode(ns), MetadataField, NamespaceField) +} + +// GetAnnotations gets the metadata annotations field. +func (rn *RNode) GetAnnotations() (map[string]string, error) { + meta, err := rn.GetMeta() + if err != nil { + return nil, err + } + return meta.Annotations, nil +} + +// SetAnnotations tries to set the metadata annotations field. +func (rn *RNode) SetAnnotations(m map[string]string) error { + meta, err := rn.Pipe(Lookup(MetadataField)) + if err != nil { + return err + } + if len(m) == 0 { + if meta == nil { + return nil + } + return meta.PipeE(Clear(AnnotationsField)) + } + return rn.SetMapField( + NewMapRNode(&m), MetadataField, AnnotationsField) +} + +// GetLabels gets the metadata labels field. +func (rn *RNode) GetLabels() (map[string]string, error) { + meta, err := rn.GetMeta() + if err != nil { + return nil, err + } + return meta.Labels, nil +} + +// SetLabels sets the metadata labels field. +func (rn *RNode) SetLabels(m map[string]string) error { + meta, err := rn.Pipe(Lookup(MetadataField)) + if err != nil { + return err + } + if len(m) == 0 { + if meta == nil { + return nil + } + return meta.PipeE(Clear(LabelsField)) + } + return rn.SetMapField( + NewMapRNode(&m), MetadataField, LabelsField) +} + +func (rn *RNode) SetMapField(value *RNode, path ...string) error { + return rn.PipeE( + LookupCreate(yaml.MappingNode, path[0:len(path)-1]...), + SetField(path[len(path)-1], value), + ) +} + // 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 25804a705..c208c6eb4 100644 --- a/kyaml/yaml/rnode_test.go +++ b/kyaml/yaml/rnode_test.go @@ -751,3 +751,104 @@ func TestRNodeIsNilOrEmpty(t *testing.T) { t.Fatalf("non-empty list should not be empty") } } + +const deploymentJSON = ` +{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "homer", + "namespace": "simpsons", + "labels": { + "fruit": "apple", + "veggie": "carrot" + }, + "annotations": { + "area": "51", + "greeting": "Take me to your leader." + } + } +} +` + +func getNamespaceOrDie(t *testing.T, n *RNode) string { + m, err := n.GetNamespace() + assert.NoError(t, err) + return m +} + +func TestRNodeSetNamespace(t *testing.T) { + n := NewRNode(nil) + assert.Equal(t, "", getNamespaceOrDie(t, n)) + assert.NoError(t, n.SetNamespace("")) + assert.Equal(t, "", getNamespaceOrDie(t, n)) + if err := n.UnmarshalJSON([]byte(deploymentJSON)); err != nil { + t.Fatalf("unexpected unmarshaljson err: %v", err) + } + assert.NoError(t, n.SetNamespace("flanders")) + assert.Equal(t, "flanders", getNamespaceOrDie(t, n)) +} + +func getLabelsOrDie(t *testing.T, n *RNode) map[string]string { + m, err := n.GetLabels() + assert.NoError(t, err) + return m +} + +func TestRNodeSetLabels(t *testing.T) { + n := NewRNode(nil) + assert.Equal(t, 0, len(getLabelsOrDie(t, n))) + assert.NoError(t, n.SetLabels(map[string]string{})) + assert.Equal(t, 0, len(getLabelsOrDie(t, n))) + + n = NewRNode(nil) + if err := n.UnmarshalJSON([]byte(deploymentJSON)); err != nil { + t.Fatalf("unexpected unmarshaljson err: %v", err) + } + labels := getLabelsOrDie(t, n) + assert.Equal(t, 2, len(labels)) + assert.Equal(t, "apple", labels["fruit"]) + assert.Equal(t, "carrot", labels["veggie"]) + assert.NoError(t, n.SetLabels(map[string]string{ + "label1": "foo", + "label2": "bar", + })) + labels = getLabelsOrDie(t, n) + assert.Equal(t, 2, len(labels)) + assert.Equal(t, "foo", labels["label1"]) + assert.Equal(t, "bar", labels["label2"]) + assert.NoError(t, n.SetLabels(map[string]string{})) + assert.Equal(t, 0, len(getLabelsOrDie(t, n))) +} + +func getAnnotationsOrDie(t *testing.T, n *RNode) map[string]string { + m, err := n.GetAnnotations() + assert.NoError(t, err) + return m +} + +func TestRNodeGetAnnotations(t *testing.T) { + n := NewRNode(nil) + assert.Equal(t, 0, len(getAnnotationsOrDie(t, n))) + assert.NoError(t, n.SetAnnotations(map[string]string{})) + assert.Equal(t, 0, len(getAnnotationsOrDie(t, n))) + + n = NewRNode(nil) + if err := n.UnmarshalJSON([]byte(deploymentJSON)); err != nil { + t.Fatalf("unexpected unmarshaljson err: %v", err) + } + annotations := getAnnotationsOrDie(t, n) + assert.Equal(t, 2, len(annotations)) + assert.Equal(t, "51", annotations["area"]) + assert.Equal(t, "Take me to your leader.", annotations["greeting"]) + assert.NoError(t, n.SetAnnotations(map[string]string{ + "annotation1": "foo", + "annotation2": "bar", + })) + annotations = getAnnotationsOrDie(t, n) + assert.Equal(t, 2, len(annotations)) + assert.Equal(t, "foo", annotations["annotation1"]) + assert.Equal(t, "bar", annotations["annotation2"]) + assert.NoError(t, n.SetAnnotations(map[string]string{})) + assert.Equal(t, 0, len(getAnnotationsOrDie(t, n))) +}