Merge pull request #3277 from monopole/moreRNodeSetters

More RNode setters and WNode delegation
This commit is contained in:
Jeff Regan
2020-11-25 10:20:06 -08:00
committed by GitHub
6 changed files with 226 additions and 25 deletions

View File

@@ -174,36 +174,40 @@ func (wn *WNode) MatchesLabelSelector(string) (bool, error) {
// SetAnnotations implements ifc.Kunstructured.
func (wn *WNode) SetAnnotations(annotations map[string]string) {
wn.setField(yaml.NewMapRNode(&annotations), yaml.MetadataField, yaml.AnnotationsField)
if err := wn.node.SetAnnotations(annotations); err != nil {
log.Fatal(err) // interface doesn't allow error.
}
}
// SetGvk implements ifc.Kunstructured.
func (wn *WNode) SetGvk(gvk resid.Gvk) {
wn.setField(yaml.NewScalarRNode(gvk.Kind), yaml.KindField)
wn.setField(yaml.NewScalarRNode(fmt.Sprintf("%s/%s", gvk.Group, gvk.Version)), yaml.APIVersionField)
wn.setMapField(yaml.NewScalarRNode(gvk.Kind), yaml.KindField)
wn.setMapField(
yaml.NewScalarRNode(
fmt.Sprintf("%s/%s", gvk.Group, gvk.Version)), yaml.APIVersionField)
}
// SetLabels implements ifc.Kunstructured.
func (wn *WNode) SetLabels(labels map[string]string) {
wn.setField(yaml.NewMapRNode(&labels), yaml.MetadataField, yaml.LabelsField)
if err := wn.node.SetLabels(labels); err != nil {
log.Fatal(err) // interface doesn't allow error.
}
}
// SetName implements ifc.Kunstructured.
func (wn *WNode) SetName(name string) {
wn.setField(yaml.NewScalarRNode(name), yaml.MetadataField, yaml.NameField)
wn.setMapField(yaml.NewScalarRNode(name), yaml.MetadataField, yaml.NameField)
}
// SetNamespace implements ifc.Kunstructured.
func (wn *WNode) SetNamespace(ns string) {
wn.setField(yaml.NewScalarRNode(ns), yaml.MetadataField, yaml.NamespaceField)
if err := wn.node.SetNamespace(ns); err != nil {
log.Fatal(err) // interface doesn't allow error.
}
}
func (wn *WNode) setField(value *yaml.RNode, path ...string) {
err := wn.node.PipeE(
yaml.LookupCreate(yaml.MappingNode, path[0:len(path)-1]...),
yaml.SetField(path[len(path)-1], value),
)
if err != nil {
func (wn *WNode) setMapField(value *yaml.RNode, path ...string) {
if err := wn.node.SetMapField(value, path...); err != nil {
// Log and die since interface doesn't allow error.
log.Fatalf("failed to set field %v: %v", path, err)
}

View File

@@ -8,9 +8,8 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"sigs.k8s.io/kustomize/api/resid"
"gopkg.in/yaml.v3"
"sigs.k8s.io/kustomize/api/resid"
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
)

View File

@@ -11,6 +11,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/provider"
"sigs.k8s.io/kustomize/api/resid"
. "sigs.k8s.io/kustomize/api/resmap"
@@ -687,21 +688,25 @@ func makeMap2(b types.GenerationBehavior) ResMap {
}
func TestAbsorbAll(t *testing.T) {
metadata := map[string]interface{}{
"name": "cmap",
}
if !konfig.FlagEnableKyamlDefaultValue {
metadata["annotations"] = map[string]interface{}{}
metadata["labels"] = map[string]interface{}{}
}
expected := rmF.FromResource(rf.FromMapAndOption(
map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"annotations": map[string]interface{}{},
"labels": map[string]interface{}{},
"name": "cmap",
},
"metadata": metadata,
"data": map[string]interface{}{
"a": "u",
"b": "v",
"c": "w",
},
}, &types.GeneratorArgs{
},
&types.GeneratorArgs{
Behavior: "create",
}))
w := makeMap1()
@@ -718,9 +723,9 @@ func TestAbsorbAll(t *testing.T) {
w = makeMap1()
w2 = makeMap2(types.BehaviorUnspecified)
err := w.AbsorbAll(w2)
if err == nil {
t.Fatalf("expected error with unspecified behavior")
}
assert.Error(t, err)
assert.True(
t, strings.Contains(err.Error(), "behavior must be merge or replace"))
}
func TestToRNodeSlice(t *testing.T) {

View File

@@ -7,6 +7,8 @@ import (
"fmt"
"testing"
"sigs.k8s.io/kustomize/api/konfig"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/loader"
@@ -341,7 +343,15 @@ kind: List
name: "listWithAnchorReference",
input: []types.PatchStrategicMerge{patchList2},
expectedOut: []*Resource{testDeploymentA, testDeploymentB},
expectedErr: false,
// See https://github.com/kubernetes-sigs/kustomize/issues/3271
// This test should not have an error, but does when kyaml is used.
// The error using kyaml is:
// json: unsupported type: map[interface {}]interface {}
// probably arising from too many conversions between
// yaml, json, Resource, RNode, Unstructured etc.
// These conversions can be removed after closing
// https://github.com/kubernetes-sigs/kustomize/issues/2506
expectedErr: konfig.FlagEnableKyamlDefaultValue,
},
{
name: "listWithNoEntries",
@@ -363,7 +373,7 @@ kind: List
fmt.Sprintf("in test %s, got unexpected error: %v", test.name, err))
continue
}
assert.False(t, test.expectedErr, "expected no error")
assert.False(t, test.expectedErr, "expected no error in "+test.name)
assert.Equal(t, len(test.expectedOut), len(rs))
for i := range rs {
expYaml, err := test.expectedOut[i].AsYAML()

View File

@@ -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...)

View File

@@ -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)))
}