mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Add inter-pod-affinity integration tests and remove corresponding e2e tests
Signed-off-by: vikaschoudhary16 <choudharyvikas16@gmail.com>
This commit is contained in:
parent
744455c69d
commit
189129c71d
@ -383,259 +383,6 @@ var _ = SIGDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
Expect(labelPod.Spec.NodeName).To(Equal(nodeName))
|
Expect(labelPod.Spec.NodeName).To(Equal(nodeName))
|
||||||
})
|
})
|
||||||
|
|
||||||
// labelSelector Operator is DoesNotExist but values are there in requiredDuringSchedulingIgnoredDuringExecution
|
|
||||||
// part of podAffinity, so validation fails.
|
|
||||||
It("validates that a pod with an invalid podAffinity is rejected because of the LabelSelectorRequirement is invalid", func() {
|
|
||||||
By("Trying to launch a pod with an invalid pod Affinity data.")
|
|
||||||
podName := "without-label-" + string(uuid.NewUUID())
|
|
||||||
_, err := cs.CoreV1().Pods(ns).Create(initPausePod(f, pausePodConfig{
|
|
||||||
Name: podName,
|
|
||||||
Labels: map[string]string{"name": "without-label"},
|
|
||||||
Affinity: &v1.Affinity{
|
|
||||||
PodAffinity: &v1.PodAffinity{
|
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
|
||||||
{
|
|
||||||
LabelSelector: &metav1.LabelSelector{
|
|
||||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
|
||||||
{
|
|
||||||
Key: "security",
|
|
||||||
Operator: metav1.LabelSelectorOpDoesNotExist,
|
|
||||||
Values: []string{"securityscan"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TopologyKey: "kubernetes.io/hostname",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
|
|
||||||
if err == nil || !errors.IsInvalid(err) {
|
|
||||||
framework.Failf("Expect error of invalid, got : %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test Nodes does not have any pod, hence it should be impossible to schedule a Pod with pod affinity.
|
|
||||||
It("validates that Inter-pod-Affinity is respected if not matching", func() {
|
|
||||||
By("Trying to schedule Pod with nonempty Pod Affinity.")
|
|
||||||
framework.WaitForStableCluster(cs, masterNodes)
|
|
||||||
podName := "without-label-" + string(uuid.NewUUID())
|
|
||||||
conf := pausePodConfig{
|
|
||||||
Name: podName,
|
|
||||||
Affinity: &v1.Affinity{
|
|
||||||
PodAffinity: &v1.PodAffinity{
|
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
|
||||||
{
|
|
||||||
LabelSelector: &metav1.LabelSelector{
|
|
||||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
|
||||||
{
|
|
||||||
Key: "service",
|
|
||||||
Operator: metav1.LabelSelectorOpIn,
|
|
||||||
Values: []string{"securityscan", "value2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TopologyKey: "kubernetes.io/hostname",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
WaitForSchedulerAfterAction(f, createPausePodAction(f, conf), podName, false)
|
|
||||||
verifyResult(cs, 0, 1, ns)
|
|
||||||
})
|
|
||||||
|
|
||||||
// test the pod affinity successful matching scenario.
|
|
||||||
It("validates that InterPodAffinity is respected if matching", func() {
|
|
||||||
nodeName, _ := runAndKeepPodWithLabelAndGetNodeName(f)
|
|
||||||
|
|
||||||
By("Trying to apply a random label on the found node.")
|
|
||||||
k := "e2e.inter-pod-affinity.kubernetes.io/zone"
|
|
||||||
v := "china-e2etest"
|
|
||||||
framework.AddOrUpdateLabelOnNode(cs, nodeName, k, v)
|
|
||||||
framework.ExpectNodeHasLabel(cs, nodeName, k, v)
|
|
||||||
defer framework.RemoveLabelOffNode(cs, nodeName, k)
|
|
||||||
|
|
||||||
By("Trying to launch the pod, now with podAffinity.")
|
|
||||||
labelPodName := "with-podaffinity-" + string(uuid.NewUUID())
|
|
||||||
createPausePod(f, pausePodConfig{
|
|
||||||
Name: labelPodName,
|
|
||||||
Affinity: &v1.Affinity{
|
|
||||||
PodAffinity: &v1.PodAffinity{
|
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
|
||||||
{
|
|
||||||
LabelSelector: &metav1.LabelSelector{
|
|
||||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
|
||||||
{
|
|
||||||
Key: "security",
|
|
||||||
Operator: metav1.LabelSelectorOpIn,
|
|
||||||
Values: []string{"S1", "value2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TopologyKey: k,
|
|
||||||
Namespaces: []string{ns},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// check that pod got scheduled. We intentionally DO NOT check that the
|
|
||||||
// pod is running because this will create a race condition with the
|
|
||||||
// kubelet and the scheduler: the scheduler might have scheduled a pod
|
|
||||||
// already when the kubelet does not know about its new label yet. The
|
|
||||||
// kubelet will then refuse to launch the pod.
|
|
||||||
framework.ExpectNoError(framework.WaitForPodNotPending(cs, ns, labelPodName))
|
|
||||||
labelPod, err := cs.CoreV1().Pods(ns).Get(labelPodName, metav1.GetOptions{})
|
|
||||||
framework.ExpectNoError(err)
|
|
||||||
Expect(labelPod.Spec.NodeName).To(Equal(nodeName))
|
|
||||||
})
|
|
||||||
|
|
||||||
// test when the pod anti affinity rule is not satisfied, the pod would stay pending.
|
|
||||||
It("validates that InterPodAntiAffinity is respected if matching 2", func() {
|
|
||||||
// launch pods to find nodes which can launch a pod. We intentionally do
|
|
||||||
// not just take the node list and choose the first and the second of them.
|
|
||||||
// Depending on the cluster and the scheduler it might be that a "normal" pod
|
|
||||||
// cannot be scheduled onto it.
|
|
||||||
By("Launching two pods on two distinct nodes to get two node names")
|
|
||||||
CreateHostPortPods(f, "host-port", 2, true)
|
|
||||||
defer framework.DeleteRCAndPods(f.ClientSet, f.InternalClientset, ns, "host-port")
|
|
||||||
podList, err := cs.CoreV1().Pods(ns).List(metav1.ListOptions{})
|
|
||||||
framework.ExpectNoError(err)
|
|
||||||
Expect(len(podList.Items)).To(Equal(2))
|
|
||||||
nodeNames := []string{podList.Items[0].Spec.NodeName, podList.Items[1].Spec.NodeName}
|
|
||||||
Expect(nodeNames[0]).ToNot(Equal(nodeNames[1]))
|
|
||||||
|
|
||||||
By("Applying a random label to both nodes.")
|
|
||||||
k := "e2e.inter-pod-affinity.kubernetes.io/zone"
|
|
||||||
v := "china-e2etest"
|
|
||||||
for _, nodeName := range nodeNames {
|
|
||||||
framework.AddOrUpdateLabelOnNode(cs, nodeName, k, v)
|
|
||||||
framework.ExpectNodeHasLabel(cs, nodeName, k, v)
|
|
||||||
defer framework.RemoveLabelOffNode(cs, nodeName, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
By("Trying to launch another pod on the first node with the service label.")
|
|
||||||
podName := "with-label-" + string(uuid.NewUUID())
|
|
||||||
|
|
||||||
runPausePod(f, pausePodConfig{
|
|
||||||
Name: podName,
|
|
||||||
Labels: map[string]string{"service": "S1"},
|
|
||||||
NodeSelector: map[string]string{k: v}, // only launch on our two nodes
|
|
||||||
})
|
|
||||||
|
|
||||||
By("Trying to launch another pod, now with podAntiAffinity with same Labels.")
|
|
||||||
labelPodName := "with-podantiaffinity-" + string(uuid.NewUUID())
|
|
||||||
conf := pausePodConfig{
|
|
||||||
Name: labelPodName,
|
|
||||||
Labels: map[string]string{"service": "Diff"},
|
|
||||||
NodeSelector: map[string]string{k: v}, // only launch on our two nodes, contradicting the podAntiAffinity
|
|
||||||
Affinity: &v1.Affinity{
|
|
||||||
PodAntiAffinity: &v1.PodAntiAffinity{
|
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
|
||||||
{
|
|
||||||
LabelSelector: &metav1.LabelSelector{
|
|
||||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
|
||||||
{
|
|
||||||
Key: "service",
|
|
||||||
Operator: metav1.LabelSelectorOpIn,
|
|
||||||
Values: []string{"S1", "value2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TopologyKey: k,
|
|
||||||
Namespaces: []string{ns},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
WaitForSchedulerAfterAction(f, createPausePodAction(f, conf), labelPodName, false)
|
|
||||||
verifyResult(cs, 3, 1, ns)
|
|
||||||
})
|
|
||||||
|
|
||||||
// test the pod affinity successful matching scenario with multiple Label Operators.
|
|
||||||
It("validates that InterPodAffinity is respected if matching with multiple Affinities", func() {
|
|
||||||
nodeName, _ := runAndKeepPodWithLabelAndGetNodeName(f)
|
|
||||||
|
|
||||||
By("Trying to apply a random label on the found node.")
|
|
||||||
k := "e2e.inter-pod-affinity.kubernetes.io/zone"
|
|
||||||
v := "kubernetes-e2e"
|
|
||||||
framework.AddOrUpdateLabelOnNode(cs, nodeName, k, v)
|
|
||||||
framework.ExpectNodeHasLabel(cs, nodeName, k, v)
|
|
||||||
defer framework.RemoveLabelOffNode(cs, nodeName, k)
|
|
||||||
|
|
||||||
By("Trying to launch the pod, now with multiple pod affinities with diff LabelOperators.")
|
|
||||||
labelPodName := "with-podaffinity-" + string(uuid.NewUUID())
|
|
||||||
createPausePod(f, pausePodConfig{
|
|
||||||
Name: labelPodName,
|
|
||||||
Affinity: &v1.Affinity{
|
|
||||||
PodAffinity: &v1.PodAffinity{
|
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
|
||||||
{
|
|
||||||
LabelSelector: &metav1.LabelSelector{
|
|
||||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
|
||||||
{
|
|
||||||
Key: "security",
|
|
||||||
Operator: metav1.LabelSelectorOpIn,
|
|
||||||
Values: []string{"S1", "value2"},
|
|
||||||
}, {
|
|
||||||
Key: "security",
|
|
||||||
Operator: metav1.LabelSelectorOpNotIn,
|
|
||||||
Values: []string{"S2"},
|
|
||||||
}, {
|
|
||||||
Key: "security",
|
|
||||||
Operator: metav1.LabelSelectorOpExists,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TopologyKey: k,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// check that pod got scheduled. We intentionally DO NOT check that the
|
|
||||||
// pod is running because this will create a race condition with the
|
|
||||||
// kubelet and the scheduler: the scheduler might have scheduled a pod
|
|
||||||
// already when the kubelet does not know about its new label yet. The
|
|
||||||
// kubelet will then refuse to launch the pod.
|
|
||||||
framework.ExpectNoError(framework.WaitForPodNotPending(cs, ns, labelPodName))
|
|
||||||
labelPod, err := cs.CoreV1().Pods(ns).Get(labelPodName, metav1.GetOptions{})
|
|
||||||
framework.ExpectNoError(err)
|
|
||||||
Expect(labelPod.Spec.NodeName).To(Equal(nodeName))
|
|
||||||
})
|
|
||||||
|
|
||||||
// test the pod affinity and anti affinity successful matching scenario.
|
|
||||||
It("validates that InterPod Affinity and AntiAffinity is respected if matching", func() {
|
|
||||||
nodeName, _ := runAndKeepPodWithLabelAndGetNodeName(f)
|
|
||||||
|
|
||||||
By("Trying to apply a random label on the found node.")
|
|
||||||
k := "e2e.inter-pod-affinity.kubernetes.io/zone"
|
|
||||||
v := "e2e-testing"
|
|
||||||
framework.AddOrUpdateLabelOnNode(cs, nodeName, k, v)
|
|
||||||
framework.ExpectNodeHasLabel(cs, nodeName, k, v)
|
|
||||||
defer framework.RemoveLabelOffNode(cs, nodeName, k)
|
|
||||||
|
|
||||||
By("Trying to launch the pod, now with Pod affinity and anti affinity.")
|
|
||||||
pod := createPodWithPodAffinity(f, k)
|
|
||||||
|
|
||||||
// check that pod got scheduled. We intentionally DO NOT check that the
|
|
||||||
// pod is running because this will create a race condition with the
|
|
||||||
// kubelet and the scheduler: the scheduler might have scheduled a pod
|
|
||||||
// already when the kubelet does not know about its new label yet. The
|
|
||||||
// kubelet will then refuse to launch the pod.
|
|
||||||
framework.ExpectNoError(framework.WaitForPodNotPending(cs, ns, pod.Name))
|
|
||||||
labelPod, err := cs.Core().Pods(ns).Get(pod.Name, metav1.GetOptions{})
|
|
||||||
framework.ExpectNoError(err)
|
|
||||||
Expect(labelPod.Spec.NodeName).To(Equal(nodeName))
|
|
||||||
})
|
|
||||||
|
|
||||||
// 1. Run a pod to get an available node, then delete the pod
|
// 1. Run a pod to get an available node, then delete the pod
|
||||||
// 2. Taint the node with a random taint
|
// 2. Taint the node with a random taint
|
||||||
// 3. Try to relaunch the pod with tolerations tolerate the taints on node,
|
// 3. Try to relaunch the pod with tolerations tolerate the taints on node,
|
||||||
|
@ -14,6 +14,7 @@ go_test(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"extender_test.go",
|
"extender_test.go",
|
||||||
"main_test.go",
|
"main_test.go",
|
||||||
|
"predicates_test.go",
|
||||||
"priorities_test.go",
|
"priorities_test.go",
|
||||||
"scheduler_test.go",
|
"scheduler_test.go",
|
||||||
],
|
],
|
||||||
@ -37,6 +38,7 @@ go_test(
|
|||||||
"//test/integration/framework:go_default_library",
|
"//test/integration/framework:go_default_library",
|
||||||
"//test/utils:go_default_library",
|
"//test/utils:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||||
|
868
test/integration/scheduler/predicates_test.go
Normal file
868
test/integration/scheduler/predicates_test.go
Normal file
@ -0,0 +1,868 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 scheduler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
|
testutils "k8s.io/kubernetes/test/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file tests the scheduler predicates functionality.
|
||||||
|
|
||||||
|
// TestInterPodAffinity verifies that scheduler's inter pod affinity and
|
||||||
|
// anti-affinity predicate functions works correctly.
|
||||||
|
func TestInterPodAffinity(t *testing.T) {
|
||||||
|
context := initTest(t, "inter-pod-affinity")
|
||||||
|
defer cleanupTest(t, context)
|
||||||
|
// Add a few nodes.
|
||||||
|
nodes, err := createNodes(context.clientSet, "testnode", nil, 2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot create nodes: %v", err)
|
||||||
|
}
|
||||||
|
// Add labels to the nodes.
|
||||||
|
labels1 := map[string]string{
|
||||||
|
"region": "r1",
|
||||||
|
"zone": "z11",
|
||||||
|
}
|
||||||
|
for _, node := range nodes {
|
||||||
|
if err = testutils.AddLabelsToNode(context.clientSet, node.Name, labels1); err != nil {
|
||||||
|
t.Fatalf("Cannot add labels to node: %v", err)
|
||||||
|
}
|
||||||
|
if err = waitForNodeLabels(context.clientSet, node.Name, labels1); err != nil {
|
||||||
|
t.Fatalf("Adding labels to node didn't succeed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cs := context.clientSet
|
||||||
|
podLabel := map[string]string{"service": "securityscan"}
|
||||||
|
podLabel2 := map[string]string{"security": "S1"}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
pod *v1.Pod
|
||||||
|
pods []*v1.Pod
|
||||||
|
node *v1.Node
|
||||||
|
fits bool
|
||||||
|
errorType string
|
||||||
|
test string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel2,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||||
|
Values: []string{"securityscan"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: false,
|
||||||
|
errorType: "invalidPod",
|
||||||
|
test: "validates that a pod with an invalid podAffinity is rejected because of the LabelSelectorRequirement is invalid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel2,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: false,
|
||||||
|
test: "validates that Inter-pod-Affinity is respected if not matching",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel2,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: true,
|
||||||
|
test: "validates that InterPodAffinity is respected if matching. requiredDuringSchedulingIgnoredDuringExecution in PodAffinity using In operator that matches the existing pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel2,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
|
Values: []string{"securityscan3", "value3"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{{Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel}}},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: true,
|
||||||
|
test: "validates that InterPodAffinity is respected if matching. requiredDuringSchedulingIgnoredDuringExecution in PodAffinity using not in operator in labelSelector that matches the existing pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel2,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
Namespaces: []string{"diff-namespace"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{{Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel, Namespace: "ns"}}},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: false,
|
||||||
|
test: "validates that inter-pod-affinity is respected when pods have different Namespaces",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"antivirusscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{{Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name}, ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel}}},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: false,
|
||||||
|
test: "Doesn't satisfy the PodAffinity because of unmatching labelSelector with the existing pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel2,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpExists,
|
||||||
|
}, {
|
||||||
|
Key: "wrongkey",
|
||||||
|
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
}, {
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan"},
|
||||||
|
}, {
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
|
Values: []string{"WrongValue"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{{Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name}, ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel}}},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: true,
|
||||||
|
test: "validates that InterPodAffinity is respected if matching with multiple affinities in multiple RequiredDuringSchedulingIgnoredDuringExecution ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Labels: podLabel2,
|
||||||
|
Name: "fakename",
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpExists,
|
||||||
|
}, {
|
||||||
|
Key: "wrongkey",
|
||||||
|
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
}, {
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan2"},
|
||||||
|
}, {
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
|
Values: []string{"WrongValue"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{{Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name}, ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel}}},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: false,
|
||||||
|
test: "The labelSelector requirements(items of matchExpressions) are ANDed, the pod cannot schedule onto the node because one of the matchExpression items doesn't match.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel2,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"antivirusscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "node",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{{Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name}, ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel}}},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: true,
|
||||||
|
test: "validates that InterPod Affinity and AntiAffinity is respected if matching",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel2,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"antivirusscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "node",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{
|
||||||
|
{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name,
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"antivirusscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "node",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: true,
|
||||||
|
test: "satisfies the PodAffinity and PodAntiAffinity and PodAntiAffinity symmetry with the existing pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel2,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "zone",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{{Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name}, ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel}}},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: false,
|
||||||
|
test: "satisfies the PodAffinity but doesn't satisfies the PodAntiAffinity with the existing pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"antivirusscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "node",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{
|
||||||
|
{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
NodeName: nodes[0].Name,
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value3"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "zone",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: false,
|
||||||
|
test: "satisfies the PodAffinity and PodAntiAffinity but doesn't satisfies PodAntiAffinity symmetry with the existing pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{{Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: "machine2"}, ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel}}},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: false,
|
||||||
|
test: "pod matches its own Label in PodAffinity and that matches the existing pod Labels",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename",
|
||||||
|
Labels: podLabel,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}}},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{
|
||||||
|
{
|
||||||
|
Spec: v1.PodSpec{NodeName: nodes[0].Name,
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "zone",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fakename2",
|
||||||
|
Labels: podLabel},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: false,
|
||||||
|
test: "Verify that PodAntiAffinity of an existing pod is respected when PodAntiAffinity symmetry is not satisfied with the existing pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fake-name",
|
||||||
|
Labels: podLabel,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}}},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{
|
||||||
|
{
|
||||||
|
Spec: v1.PodSpec{NodeName: nodes[0].Name,
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "zone",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "fake-name2",
|
||||||
|
Labels: podLabel},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
node: nodes[0],
|
||||||
|
fits: true,
|
||||||
|
test: "Verify that PodAntiAffinity from existing pod is respected when pod statisfies PodAntiAffinity symmetry with the existing pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "fake-name2"},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeSelector: map[string]string{"region": "r1"},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "foo",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"abc"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pods: []*v1.Pod{
|
||||||
|
{Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{{Name: "container", Image: framework.GetPauseImageName(cs)}},
|
||||||
|
NodeName: nodes[0].Name}, ObjectMeta: metav1.ObjectMeta{Name: "fakename", Labels: map[string]string{"foo": "abc"}}},
|
||||||
|
},
|
||||||
|
fits: false,
|
||||||
|
test: "nodes[0] and nodes[1] have same topologyKey and label value. nodes[0] has an existing pod that matches the inter pod affinity rule. The new pod can not be scheduled onto either of the two nodes.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
for _, pod := range test.pods {
|
||||||
|
var nsName string
|
||||||
|
if pod.Namespace != "" {
|
||||||
|
nsName = pod.Namespace
|
||||||
|
} else {
|
||||||
|
nsName = context.ns.Name
|
||||||
|
}
|
||||||
|
createdPod, err := cs.Core().Pods(nsName).Create(pod)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test Failed: error, %v, while creating pod during test: %v", err, test.test)
|
||||||
|
}
|
||||||
|
err = wait.Poll(time.Second, wait.ForeverTestTimeout, podScheduled(cs, createdPod.Namespace, createdPod.Name))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test Failed: error, %v, while waiting for pod during test, %v", err, test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testPod, err := cs.Core().Pods(context.ns.Name).Create(test.pod)
|
||||||
|
if err != nil {
|
||||||
|
if !(test.errorType == "invalidPod" && errors.IsInvalid(err)) {
|
||||||
|
t.Fatalf("Test Failed: error, %v, while creating pod during test: %v", err, test.test)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = wait.Poll(time.Second, wait.ForeverTestTimeout, podScheduled(cs, testPod.Namespace, testPod.Name))
|
||||||
|
if err != nil && err != wait.ErrWaitTimeout {
|
||||||
|
t.Errorf("Test Failed: error, %v, while waiting for pod to get scheduled, %v", err, test.test)
|
||||||
|
}
|
||||||
|
if (err == nil) != test.fits {
|
||||||
|
t.Errorf("Test Failed: %v, err %v, test.fits %v", test.test, err, test.fits)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pod := range test.pods {
|
||||||
|
var nsName string
|
||||||
|
if pod.Namespace != "" {
|
||||||
|
nsName = pod.Namespace
|
||||||
|
} else {
|
||||||
|
nsName = context.ns.Name
|
||||||
|
}
|
||||||
|
err = cs.Core().Pods(nsName).Delete(pod.Name, metav1.NewDeleteOptions(0))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test Failed: error, %v, while deleting pod during test: %v", err, test.test)
|
||||||
|
}
|
||||||
|
err = wait.Poll(time.Second, wait.ForeverTestTimeout, podDeleted(cs, nsName, pod.Name))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test Failed: error, %v, while waiting for pod to get deleted, %v", err, test.test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = cs.Core().Pods(context.ns.Name).Delete(test.pod.Name, metav1.NewDeleteOptions(0))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test Failed: error, %v, while deleting pod during test: %v", err, test.test)
|
||||||
|
}
|
||||||
|
err = wait.Poll(time.Second, wait.ForeverTestTimeout, podDeleted(cs, context.ns.Name, test.pod.Name))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test Failed: error, %v, while waiting for pod to get deleted, %v", err, test.test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -282,6 +282,17 @@ func runPausePod(cs clientset.Interface, conf *pausePodConfig) (*v1.Pod, error)
|
|||||||
return pod, nil
|
return pod, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// podDeleted returns true if a pod is not found in the given namespace.
|
||||||
|
func podDeleted(c clientset.Interface, podNamespace, podName string) wait.ConditionFunc {
|
||||||
|
return func() (bool, error) {
|
||||||
|
_, err := c.Core().Pods(podNamespace).Get(podName, metav1.GetOptions{})
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// podScheduled returns true if a node is assigned to the given pod.
|
// podScheduled returns true if a node is assigned to the given pod.
|
||||||
func podScheduled(c clientset.Interface, podNamespace, podName string) wait.ConditionFunc {
|
func podScheduled(c clientset.Interface, podNamespace, podName string) wait.ConditionFunc {
|
||||||
return func() (bool, error) {
|
return func() (bool, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user