EvenPodsSpread: refactor "chained" utils

- move "chanined" utils to pkg/scheduler/testing/utils.go so as to be re-used by all scheduler tests
This commit is contained in:
Wei Huang 2019-05-10 12:24:48 -07:00
parent 3dbef991a3
commit dce6686c9a
No known key found for this signature in database
GPG Key ID: BE5E9752F8B6E005
4 changed files with 342 additions and 290 deletions

View File

@ -25,7 +25,7 @@ import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
schedulertesting "k8s.io/kubernetes/pkg/scheduler/testing"
st "k8s.io/kubernetes/pkg/scheduler/testing"
)
// sortablePods lets us to sort pods.
@ -352,16 +352,16 @@ func TestPredicateMetadata_AddRemovePod(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
allPodLister := schedulertesting.FakePodLister(append(test.existingPods, test.addedPod))
allPodLister := st.FakePodLister(append(test.existingPods, test.addedPod))
// getMeta creates predicate meta data given the list of pods.
getMeta := func(lister schedulertesting.FakePodLister) (*predicateMetadata, map[string]*schedulernodeinfo.NodeInfo) {
getMeta := func(lister st.FakePodLister) (*predicateMetadata, map[string]*schedulernodeinfo.NodeInfo) {
nodeInfoMap := schedulernodeinfo.CreateNodeNameToInfoMap(lister, test.nodes)
// nodeList is a list of non-pointer nodes to feed to FakeNodeListInfo.
nodeList := []v1.Node{}
for _, n := range test.nodes {
nodeList = append(nodeList, *n)
}
_, precompute := NewServiceAffinityPredicate(lister, schedulertesting.FakeServiceLister(test.services), FakeNodeListInfo(nodeList), nil)
_, precompute := NewServiceAffinityPredicate(lister, st.FakeServiceLister(test.services), FakeNodeListInfo(nodeList), nil)
RegisterPredicateMetadataProducer("ServiceAffinityMetaProducer", precompute)
pmf := PredicateMetadataFactory{lister}
meta := pmf.GetMetadata(test.pendingPod, nodeInfoMap)
@ -372,7 +372,7 @@ func TestPredicateMetadata_AddRemovePod(t *testing.T) {
// are given to the metadata producer.
allPodsMeta, _ := getMeta(allPodLister)
// existingPodsMeta1 is meta data produced for test.existingPods (without test.addedPod).
existingPodsMeta1, nodeInfoMap := getMeta(schedulertesting.FakePodLister(test.existingPods))
existingPodsMeta1, nodeInfoMap := getMeta(st.FakePodLister(test.existingPods))
// Add test.addedPod to existingPodsMeta1 and make sure meta is equal to allPodsMeta
nodeInfo := nodeInfoMap[test.addedPod.Spec.NodeName]
if err := existingPodsMeta1.AddPod(test.addedPod, nodeInfo); err != nil {
@ -383,7 +383,7 @@ func TestPredicateMetadata_AddRemovePod(t *testing.T) {
}
// Remove the added pod and from existingPodsMeta1 an make sure it is equal
// to meta generated for existing pods.
existingPodsMeta2, _ := getMeta(schedulertesting.FakePodLister(test.existingPods))
existingPodsMeta2, _ := getMeta(st.FakePodLister(test.existingPods))
if err := existingPodsMeta1.RemovePod(test.addedPod); err != nil {
t.Errorf("error removing pod from meta: %v", err)
}
@ -936,14 +936,14 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
}{
{
name: "clean cluster with one spreadConstraint",
pod: makePod().name("p").label("foo", "").spreadConstraint(
1, "zone", hardSpread, makeLabelSelector().exists("foo").obj(),
).obj(),
pod: st.MakePod().Name("p").Label("foo", "").SpreadConstraint(
1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(),
).Obj(),
nodes: []*v1.Node{
makeNode().name("node-a").label("zone", "zone1").label("node", "node-a").obj(),
makeNode().name("node-b").label("zone", "zone1").label("node", "node-b").obj(),
makeNode().name("node-x").label("zone", "zone2").label("node", "node-x").obj(),
makeNode().name("node-y").label("zone", "zone2").label("node", "node-y").obj(),
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
},
injectPodPointers: map[topologyPair][]int{
// denotes no existing pod is matched on this zone pair, but still needed to be
@ -960,21 +960,21 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
},
{
name: "normal case with one spreadConstraint",
pod: makePod().name("p").label("foo", "").spreadConstraint(
1, "zone", hardSpread, makeLabelSelector().exists("foo").obj(),
).obj(),
pod: st.MakePod().Name("p").Label("foo", "").SpreadConstraint(
1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(),
).Obj(),
nodes: []*v1.Node{
makeNode().name("node-a").label("zone", "zone1").label("node", "node-a").obj(),
makeNode().name("node-b").label("zone", "zone1").label("node", "node-b").obj(),
makeNode().name("node-x").label("zone", "zone2").label("node", "node-x").obj(),
makeNode().name("node-y").label("zone", "zone2").label("node", "node-y").obj(),
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
},
existingPods: []*v1.Pod{
makePod().name("p-a1").node("node-a").label("foo", "").obj(),
makePod().name("p-a2").node("node-a").label("foo", "").obj(),
makePod().name("p-b1").node("node-b").label("foo", "").obj(),
makePod().name("p-y1").node("node-y").label("foo", "").obj(),
makePod().name("p-y2").node("node-y").label("foo", "").obj(),
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
},
injectPodPointers: map[topologyPair][]int{
// denotes existingPods[0,1,2]
@ -997,21 +997,21 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
},
{
name: "namespace mis-match doesn't count",
pod: makePod().name("p").label("foo", "").spreadConstraint(
1, "zone", hardSpread, makeLabelSelector().exists("foo").obj(),
).obj(),
pod: st.MakePod().Name("p").Label("foo", "").SpreadConstraint(
1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(),
).Obj(),
nodes: []*v1.Node{
makeNode().name("node-a").label("zone", "zone1").label("node", "node-a").obj(),
makeNode().name("node-b").label("zone", "zone1").label("node", "node-b").obj(),
makeNode().name("node-x").label("zone", "zone2").label("node", "node-x").obj(),
makeNode().name("node-y").label("zone", "zone2").label("node", "node-y").obj(),
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
},
existingPods: []*v1.Pod{
makePod().name("p-a1").node("node-a").label("foo", "").obj(),
makePod().name("p-a2").namespace("ns1").node("node-a").label("foo", "").obj(),
makePod().name("p-b1").node("node-b").label("foo", "").obj(),
makePod().name("p-y1").namespace("ns2").node("node-y").label("foo", "").obj(),
makePod().name("p-y2").node("node-y").label("foo", "").obj(),
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-a2").Namespace("ns1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
st.MakePod().Name("p-y1").Namespace("ns2").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
},
injectPodPointers: map[topologyPair][]int{
{key: "zone", value: "zone1"}: {0, 2},
@ -1030,24 +1030,24 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
},
{
name: "normal case with two spreadConstraints",
pod: makePod().name("p").label("foo", "").
spreadConstraint(1, "zone", hardSpread, makeLabelSelector().exists("foo").obj()).
spreadConstraint(1, "node", hardSpread, makeLabelSelector().exists("foo").obj()).
obj(),
pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
Obj(),
nodes: []*v1.Node{
makeNode().name("node-a").label("zone", "zone1").label("node", "node-a").obj(),
makeNode().name("node-b").label("zone", "zone1").label("node", "node-b").obj(),
makeNode().name("node-x").label("zone", "zone2").label("node", "node-x").obj(),
makeNode().name("node-y").label("zone", "zone2").label("node", "node-y").obj(),
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
},
existingPods: []*v1.Pod{
makePod().name("p-a1").node("node-a").label("foo", "").obj(),
makePod().name("p-a2").node("node-a").label("foo", "").obj(),
makePod().name("p-b1").node("node-b").label("foo", "").obj(),
makePod().name("p-y1").node("node-y").label("foo", "").obj(),
makePod().name("p-y2").node("node-y").label("foo", "").obj(),
makePod().name("p-y3").node("node-y").label("foo", "").obj(),
makePod().name("p-y4").node("node-y").label("foo", "").obj(),
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
},
injectPodPointers: map[topologyPair][]int{
{key: "zone", value: "zone1"}: {0, 1, 2},
@ -1074,25 +1074,25 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
},
{
name: "soft spreadConstraints should be bypassed",
pod: makePod().name("p").label("foo", "").
spreadConstraint(1, "zone", softSpread, makeLabelSelector().exists("foo").obj()).
spreadConstraint(1, "zone", hardSpread, makeLabelSelector().exists("foo").obj()).
spreadConstraint(1, "zone", softSpread, makeLabelSelector().exists("foo").obj()).
spreadConstraint(1, "node", hardSpread, makeLabelSelector().exists("foo").obj()).
obj(),
pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", softSpread, st.MakeLabelSelector().Exists("foo").Obj()).
SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
SpreadConstraint(1, "zone", softSpread, st.MakeLabelSelector().Exists("foo").Obj()).
SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
Obj(),
nodes: []*v1.Node{
makeNode().name("node-a").label("zone", "zone1").label("node", "node-a").obj(),
makeNode().name("node-b").label("zone", "zone1").label("node", "node-b").obj(),
makeNode().name("node-y").label("zone", "zone2").label("node", "node-y").obj(),
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
},
existingPods: []*v1.Pod{
makePod().name("p-a1").node("node-a").label("foo", "").obj(),
makePod().name("p-a2").node("node-a").label("foo", "").obj(),
makePod().name("p-b1").node("node-b").label("foo", "").obj(),
makePod().name("p-y1").node("node-y").label("foo", "").obj(),
makePod().name("p-y2").node("node-y").label("foo", "").obj(),
makePod().name("p-y3").node("node-y").label("foo", "").obj(),
makePod().name("p-y4").node("node-y").label("foo", "").obj(),
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
},
injectPodPointers: map[topologyPair][]int{
{key: "zone", value: "zone1"}: {0, 1, 2},
@ -1118,23 +1118,23 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
},
{
name: "different labelSelectors",
pod: makePod().name("p").label("foo", "").label("bar", "").
spreadConstraint(1, "zone", hardSpread, makeLabelSelector().exists("foo").obj()).
spreadConstraint(1, "node", hardSpread, makeLabelSelector().exists("bar").obj()).
obj(),
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("bar").Obj()).
Obj(),
nodes: []*v1.Node{
makeNode().name("node-a").label("zone", "zone1").label("node", "node-a").obj(),
makeNode().name("node-b").label("zone", "zone1").label("node", "node-b").obj(),
makeNode().name("node-y").label("zone", "zone2").label("node", "node-y").obj(),
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
},
existingPods: []*v1.Pod{
makePod().name("p-a1").node("node-a").label("foo", "").obj(),
makePod().name("p-a2").node("node-a").label("foo", "").label("bar", "").obj(),
makePod().name("p-b1").node("node-b").label("foo", "").obj(),
makePod().name("p-y1").node("node-y").label("foo", "").obj(),
makePod().name("p-y2").node("node-y").label("foo", "").label("bar", "").obj(),
makePod().name("p-y3").node("node-y").label("foo", "").obj(),
makePod().name("p-y4").node("node-y").label("foo", "").label("bar", "").obj(),
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Label("bar", "").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Label("bar", "").Obj(),
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Label("bar", "").Obj(),
},
injectPodPointers: map[topologyPair][]int{
{key: "zone", value: "zone1"}: {1},
@ -1156,25 +1156,25 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
},
{
name: "two spreadConstraints, and with podAffinity",
pod: makePod().name("p").label("foo", "").
nodeAffinityNotIn("node", []string{"node-x"}). // exclude node-x
spreadConstraint(1, "zone", hardSpread, makeLabelSelector().exists("foo").obj()).
spreadConstraint(1, "node", hardSpread, makeLabelSelector().exists("foo").obj()).
obj(),
pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityNotIn("node", []string{"node-x"}). // exclude node-x
SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj()).
Obj(),
nodes: []*v1.Node{
makeNode().name("node-a").label("zone", "zone1").label("node", "node-a").obj(),
makeNode().name("node-b").label("zone", "zone1").label("node", "node-b").obj(),
makeNode().name("node-x").label("zone", "zone2").label("node", "node-x").obj(),
makeNode().name("node-y").label("zone", "zone2").label("node", "node-y").obj(),
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
},
existingPods: []*v1.Pod{
makePod().name("p-a1").node("node-a").label("foo", "").obj(),
makePod().name("p-a2").node("node-a").label("foo", "").obj(),
makePod().name("p-b1").node("node-b").label("foo", "").obj(),
makePod().name("p-y1").node("node-y").label("foo", "").obj(),
makePod().name("p-y2").node("node-y").label("foo", "").obj(),
makePod().name("p-y3").node("node-y").label("foo", "").obj(),
makePod().name("p-y4").node("node-y").label("foo", "").obj(),
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
},
injectPodPointers: map[topologyPair][]int{
{key: "zone", value: "zone1"}: {0, 1, 2},

View File

@ -21,7 +21,6 @@ import (
"k8s.io/api/core/v1"
storagev1beta1 "k8s.io/api/storage/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/sets"
utilfeature "k8s.io/apiserver/pkg/util/feature"
@ -148,193 +147,3 @@ func isCSIMigrationOn(csiNode *storagev1beta1.CSINode, pluginName string) bool {
return mpaSet.Has(pluginName)
}
// utilities for building pod/node objects using a "chained" manner
type nodeSelectorWrapper struct{ v1.NodeSelector }
func makeNodeSelector() *nodeSelectorWrapper {
return &nodeSelectorWrapper{v1.NodeSelector{}}
}
// NOTE: each time we append a selectorTerm into `s`
// and overall all selecterTerms are ORed
func (s *nodeSelectorWrapper) in(key string, vals []string) *nodeSelectorWrapper {
expression := v1.NodeSelectorRequirement{
Key: key,
Operator: v1.NodeSelectorOpIn,
Values: vals,
}
selectorTerm := v1.NodeSelectorTerm{}
selectorTerm.MatchExpressions = append(selectorTerm.MatchExpressions, expression)
s.NodeSelectorTerms = append(s.NodeSelectorTerms, selectorTerm)
return s
}
func (s *nodeSelectorWrapper) notIn(key string, vals []string) *nodeSelectorWrapper {
expression := v1.NodeSelectorRequirement{
Key: key,
Operator: v1.NodeSelectorOpNotIn,
Values: vals,
}
selectorTerm := v1.NodeSelectorTerm{}
selectorTerm.MatchExpressions = append(selectorTerm.MatchExpressions, expression)
s.NodeSelectorTerms = append(s.NodeSelectorTerms, selectorTerm)
return s
}
func (s *nodeSelectorWrapper) obj() *v1.NodeSelector {
return &s.NodeSelector
}
type labelSelectorWrapper struct{ metav1.LabelSelector }
func makeLabelSelector() *labelSelectorWrapper {
return &labelSelectorWrapper{metav1.LabelSelector{}}
}
func (s *labelSelectorWrapper) label(k, v string) *labelSelectorWrapper {
if s.MatchLabels == nil {
s.MatchLabels = make(map[string]string)
}
s.MatchLabels[k] = v
return s
}
func (s *labelSelectorWrapper) in(key string, vals []string) *labelSelectorWrapper {
expression := metav1.LabelSelectorRequirement{
Key: key,
Operator: metav1.LabelSelectorOpIn,
Values: vals,
}
s.MatchExpressions = append(s.MatchExpressions, expression)
return s
}
func (s *labelSelectorWrapper) notIn(key string, vals []string) *labelSelectorWrapper {
expression := metav1.LabelSelectorRequirement{
Key: key,
Operator: metav1.LabelSelectorOpNotIn,
Values: vals,
}
s.MatchExpressions = append(s.MatchExpressions, expression)
return s
}
func (s *labelSelectorWrapper) exists(k string) *labelSelectorWrapper {
expression := metav1.LabelSelectorRequirement{
Key: k,
Operator: metav1.LabelSelectorOpExists,
}
s.MatchExpressions = append(s.MatchExpressions, expression)
return s
}
func (s *labelSelectorWrapper) notExist(k string) *labelSelectorWrapper {
expression := metav1.LabelSelectorRequirement{
Key: k,
Operator: metav1.LabelSelectorOpDoesNotExist,
}
s.MatchExpressions = append(s.MatchExpressions, expression)
return s
}
func (s *labelSelectorWrapper) obj() *metav1.LabelSelector {
return &s.LabelSelector
}
type podWrapper struct{ v1.Pod }
func makePod() *podWrapper {
return &podWrapper{v1.Pod{}}
}
func (p *podWrapper) obj() *v1.Pod {
return &p.Pod
}
func (p *podWrapper) name(s string) *podWrapper {
p.Name = s
return p
}
func (p *podWrapper) namespace(s string) *podWrapper {
p.Namespace = s
return p
}
func (p *podWrapper) node(s string) *podWrapper {
p.Spec.NodeName = s
return p
}
func (p *podWrapper) nodeSelector(m map[string]string) *podWrapper {
p.Spec.NodeSelector = m
return p
}
// represents HARD node affinity in particular
func (p *podWrapper) nodeAffinityIn(key string, vals []string) *podWrapper {
if p.Spec.Affinity == nil {
p.Spec.Affinity = &v1.Affinity{}
}
if p.Spec.Affinity.NodeAffinity == nil {
p.Spec.Affinity.NodeAffinity = &v1.NodeAffinity{}
}
nodeSelector := makeNodeSelector().in(key, vals).obj()
p.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution = nodeSelector
return p
}
func (p *podWrapper) nodeAffinityNotIn(key string, vals []string) *podWrapper {
if p.Spec.Affinity == nil {
p.Spec.Affinity = &v1.Affinity{}
}
if p.Spec.Affinity.NodeAffinity == nil {
p.Spec.Affinity.NodeAffinity = &v1.NodeAffinity{}
}
nodeSelector := makeNodeSelector().notIn(key, vals).obj()
p.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution = nodeSelector
return p
}
func (p *podWrapper) spreadConstraint(maxSkew int, tpKey string, mode v1.UnsatisfiableConstraintAction, selector *metav1.LabelSelector) *podWrapper {
c := v1.TopologySpreadConstraint{
MaxSkew: int32(maxSkew),
TopologyKey: tpKey,
WhenUnsatisfiable: mode,
LabelSelector: selector,
}
p.Spec.TopologySpreadConstraints = append(p.Spec.TopologySpreadConstraints, c)
return p
}
func (p *podWrapper) label(k, v string) *podWrapper {
if p.Labels == nil {
p.Labels = make(map[string]string)
}
p.Labels[k] = v
return p
}
type nodeWrapper struct{ v1.Node }
func makeNode() *nodeWrapper {
return &nodeWrapper{v1.Node{}}
}
func (n *nodeWrapper) obj() *v1.Node {
return &n.Node
}
func (n *nodeWrapper) name(s string) *nodeWrapper {
n.Name = s
return n
}
func (n *nodeWrapper) label(k, v string) *nodeWrapper {
if n.Labels == nil {
n.Labels = make(map[string]string)
}
n.Labels[k] = v
return n
}

View File

@ -0,0 +1,243 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// NodeSelectorWrapper wraps a NodeSelector inside.
type NodeSelectorWrapper struct{ v1.NodeSelector }
// MakeNodeSelector creates a NodeSelector wrapper.
func MakeNodeSelector() *NodeSelectorWrapper {
return &NodeSelectorWrapper{v1.NodeSelector{}}
}
// In injects a matchExpression (with an operator IN) as a selectorTerm
// to the inner nodeSelector.
// NOTE: appended selecterTerms are ORed.
func (s *NodeSelectorWrapper) In(key string, vals []string) *NodeSelectorWrapper {
expression := v1.NodeSelectorRequirement{
Key: key,
Operator: v1.NodeSelectorOpIn,
Values: vals,
}
selectorTerm := v1.NodeSelectorTerm{}
selectorTerm.MatchExpressions = append(selectorTerm.MatchExpressions, expression)
s.NodeSelectorTerms = append(s.NodeSelectorTerms, selectorTerm)
return s
}
// NotIn injects a matchExpression (with an operator NotIn) as a selectorTerm
// to the inner nodeSelector.
func (s *NodeSelectorWrapper) NotIn(key string, vals []string) *NodeSelectorWrapper {
expression := v1.NodeSelectorRequirement{
Key: key,
Operator: v1.NodeSelectorOpNotIn,
Values: vals,
}
selectorTerm := v1.NodeSelectorTerm{}
selectorTerm.MatchExpressions = append(selectorTerm.MatchExpressions, expression)
s.NodeSelectorTerms = append(s.NodeSelectorTerms, selectorTerm)
return s
}
// Obj returns the inner NodeSelector.
func (s *NodeSelectorWrapper) Obj() *v1.NodeSelector {
return &s.NodeSelector
}
// LabelSelectorWrapper wraps a LabelSelector inside.
type LabelSelectorWrapper struct{ metav1.LabelSelector }
// MakeLabelSelector creates a LabelSelector wrapper.
func MakeLabelSelector() *LabelSelectorWrapper {
return &LabelSelectorWrapper{metav1.LabelSelector{}}
}
// Label applies a {k,v} pair to the inner LabelSelector.
func (s *LabelSelectorWrapper) Label(k, v string) *LabelSelectorWrapper {
if s.MatchLabels == nil {
s.MatchLabels = make(map[string]string)
}
s.MatchLabels[k] = v
return s
}
// In injects a matchExpression (with an operator In) to the inner labelSelector.
func (s *LabelSelectorWrapper) In(key string, vals []string) *LabelSelectorWrapper {
expression := metav1.LabelSelectorRequirement{
Key: key,
Operator: metav1.LabelSelectorOpIn,
Values: vals,
}
s.MatchExpressions = append(s.MatchExpressions, expression)
return s
}
// NotIn injects a matchExpression (with an operator NotIn) to the inner labelSelector.
func (s *LabelSelectorWrapper) NotIn(key string, vals []string) *LabelSelectorWrapper {
expression := metav1.LabelSelectorRequirement{
Key: key,
Operator: metav1.LabelSelectorOpNotIn,
Values: vals,
}
s.MatchExpressions = append(s.MatchExpressions, expression)
return s
}
// Exists injects a matchExpression (with an operator Exists) to the inner labelSelector.
func (s *LabelSelectorWrapper) Exists(k string) *LabelSelectorWrapper {
expression := metav1.LabelSelectorRequirement{
Key: k,
Operator: metav1.LabelSelectorOpExists,
}
s.MatchExpressions = append(s.MatchExpressions, expression)
return s
}
// NotExist injects a matchExpression (with an operator NotExist) to the inner labelSelector.
func (s *LabelSelectorWrapper) NotExist(k string) *LabelSelectorWrapper {
expression := metav1.LabelSelectorRequirement{
Key: k,
Operator: metav1.LabelSelectorOpDoesNotExist,
}
s.MatchExpressions = append(s.MatchExpressions, expression)
return s
}
// Obj returns the inner LabelSelector.
func (s *LabelSelectorWrapper) Obj() *metav1.LabelSelector {
return &s.LabelSelector
}
// PodWrapper wraps a Pod inside.
type PodWrapper struct{ v1.Pod }
// MakePod creates a Pod wrapper.
func MakePod() *PodWrapper {
return &PodWrapper{v1.Pod{}}
}
// Obj returns the inner Pod.
func (p *PodWrapper) Obj() *v1.Pod {
return &p.Pod
}
// Name sets `s` as the name of the inner pod.
func (p *PodWrapper) Name(s string) *PodWrapper {
p.SetName(s)
return p
}
// Namespace sets `s` as the namespace of the inner pod.
func (p *PodWrapper) Namespace(s string) *PodWrapper {
p.SetNamespace(s)
return p
}
// Node sets `s` as the nodeName of the inner pod.
func (p *PodWrapper) Node(s string) *PodWrapper {
p.Spec.NodeName = s
return p
}
// NodeSelector sets `m` as the nodeSelector of the inner pod.
func (p *PodWrapper) NodeSelector(m map[string]string) *PodWrapper {
p.Spec.NodeSelector = m
return p
}
// NodeAffinityIn creates a HARD node affinity (with the operator In)
// and injects into the innner pod.
func (p *PodWrapper) NodeAffinityIn(key string, vals []string) *PodWrapper {
if p.Spec.Affinity == nil {
p.Spec.Affinity = &v1.Affinity{}
}
if p.Spec.Affinity.NodeAffinity == nil {
p.Spec.Affinity.NodeAffinity = &v1.NodeAffinity{}
}
nodeSelector := MakeNodeSelector().In(key, vals).Obj()
p.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution = nodeSelector
return p
}
// NodeAffinityNotIn creates a HARD node affinity (with the operator NotIn)
// and injects into the innner pod.
func (p *PodWrapper) NodeAffinityNotIn(key string, vals []string) *PodWrapper {
if p.Spec.Affinity == nil {
p.Spec.Affinity = &v1.Affinity{}
}
if p.Spec.Affinity.NodeAffinity == nil {
p.Spec.Affinity.NodeAffinity = &v1.NodeAffinity{}
}
nodeSelector := MakeNodeSelector().NotIn(key, vals).Obj()
p.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution = nodeSelector
return p
}
// SpreadConstraint constructs a TopologySpreadConstraint object and injects
// into the inner pod.
func (p *PodWrapper) SpreadConstraint(maxSkew int, tpKey string, mode v1.UnsatisfiableConstraintAction, selector *metav1.LabelSelector) *PodWrapper {
c := v1.TopologySpreadConstraint{
MaxSkew: int32(maxSkew),
TopologyKey: tpKey,
WhenUnsatisfiable: mode,
LabelSelector: selector,
}
p.Spec.TopologySpreadConstraints = append(p.Spec.TopologySpreadConstraints, c)
return p
}
// Label sets a {k,v} pair to the inner pod.
func (p *PodWrapper) Label(k, v string) *PodWrapper {
if p.Labels == nil {
p.Labels = make(map[string]string)
}
p.Labels[k] = v
return p
}
// NodeWrapper wraps a LabelSelector inside.
type NodeWrapper struct{ v1.Node }
// MakeNode creates a Node wrapper.
func MakeNode() *NodeWrapper {
return &NodeWrapper{v1.Node{}}
}
// Obj returns the inner Node.
func (n *NodeWrapper) Obj() *v1.Node {
return &n.Node
}
// Name sets `s` as the name of the inner pod.
func (n *NodeWrapper) Name(s string) *NodeWrapper {
n.SetName(s)
return n
}
// Label applies a {k,v} label pair to the inner node.
func (n *NodeWrapper) Label(k, v string) *NodeWrapper {
if n.Labels == nil {
n.Labels = make(map[string]string)
}
n.Labels[k] = v
return n
}

View File

@ -21,7 +21,7 @@ import (
"time"
v1 "k8s.io/api/core/v1"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/apis/scheduling"