diff --git a/pkg/volume/util/util.go b/pkg/volume/util/util.go index b31c5f61330..a89260a7285 100644 --- a/pkg/volume/util/util.go +++ b/pkg/volume/util/util.go @@ -283,10 +283,12 @@ func checkVolumeNodeAffinity(pv *v1.PersistentVolume, nodeLabels map[string]stri if err != nil { return fmt.Errorf("Failed to parse MatchExpressions: %v", err) } - if !selector.Matches(labels.Set(nodeLabels)) { - return fmt.Errorf("NodeSelectorTerm %+v does not match node labels", term.MatchExpressions) + if selector.Matches(labels.Set(nodeLabels)) { + // Terms are ORed, so only one needs to match + return nil } } + return fmt.Errorf("No matching NodeSelectorTerms") } return nil } diff --git a/pkg/volume/util/util_test.go b/pkg/volume/util/util_test.go index 2ebed842fea..b2790796e5d 100644 --- a/pkg/volume/util/util_test.go +++ b/pkg/volume/util/util_test.go @@ -66,7 +66,53 @@ func TestCheckVolumeNodeAffinity(t *testing.T) { pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{}), }, { - name: "valid-constraints", + name: "select-nothing", + expectSuccess: false, + pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{Required: &v1.NodeSelector{}}), + }, + { + name: "select-nothing-empty-terms", + expectSuccess: false, + pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{ + Required: &v1.NodeSelector{ + NodeSelectorTerms: []v1.NodeSelectorTerm{ + { + MatchExpressions: []v1.NodeSelectorRequirement{}, + }, + }, + }, + }), + }, + { + name: "valid-multiple-terms", + expectSuccess: true, + pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{ + Required: &v1.NodeSelector{ + NodeSelectorTerms: []v1.NodeSelectorTerm{ + { + MatchExpressions: []v1.NodeSelectorRequirement{ + { + Key: "test-key3", + Operator: v1.NodeSelectorOpIn, + Values: []string{"test-value1", "test-value3"}, + }, + }, + }, + { + MatchExpressions: []v1.NodeSelectorRequirement{ + { + Key: "test-key2", + Operator: v1.NodeSelectorOpIn, + Values: []string{"test-value0", "test-value2"}, + }, + }, + }, + }, + }, + }), + }, + { + name: "valid-multiple-match-expressions", expectSuccess: true, pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{ Required: &v1.NodeSelector{ @@ -90,7 +136,7 @@ func TestCheckVolumeNodeAffinity(t *testing.T) { }), }, { - name: "invalid-key", + name: "invalid-multiple-match-expressions-key", expectSuccess: false, pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{ Required: &v1.NodeSelector{ @@ -114,7 +160,7 @@ func TestCheckVolumeNodeAffinity(t *testing.T) { }), }, { - name: "invalid-values", + name: "invalid-multiple-match-expressions-values", expectSuccess: false, pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{ Required: &v1.NodeSelector{ @@ -137,6 +183,34 @@ func TestCheckVolumeNodeAffinity(t *testing.T) { }, }), }, + { + name: "invalid-multiple-terms", + expectSuccess: false, + pv: testVolumeWithNodeAffinity(t, &v1.VolumeNodeAffinity{ + Required: &v1.NodeSelector{ + NodeSelectorTerms: []v1.NodeSelectorTerm{ + { + MatchExpressions: []v1.NodeSelectorRequirement{ + { + Key: "test-key3", + Operator: v1.NodeSelectorOpIn, + Values: []string{"test-value1", "test-value3"}, + }, + }, + }, + { + MatchExpressions: []v1.NodeSelectorRequirement{ + { + Key: "test-key2", + Operator: v1.NodeSelectorOpIn, + Values: []string{"test-value0", "test-value1"}, + }, + }, + }, + }, + }, + }), + }, } for _, c := range cases {