Merge pull request #32160 from mml/evict.test.extra

Automatic merge from submit-queue

Refactor disruption e2e test and add some eviction test cases.
This commit is contained in:
Kubernetes Submit Queue 2016-09-13 17:23:02 -07:00 committed by GitHub
commit a26da7a1c4

View File

@ -23,14 +23,24 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
release_1_4 "k8s.io/client-go/1.4/kubernetes"
apiapi "k8s.io/client-go/1.4/pkg/api"
"k8s.io/client-go/1.4/pkg/api/unversioned"
api "k8s.io/client-go/1.4/pkg/api/v1"
extensions "k8s.io/client-go/1.4/pkg/apis/extensions/v1beta1"
policy "k8s.io/client-go/1.4/pkg/apis/policy/v1alpha1"
"k8s.io/client-go/1.4/pkg/util/intstr"
"k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/test/e2e/framework"
)
// timeout is used for most polling/waiting activities
const timeout = 60 * time.Second
// schedulingTimeout is longer specifically because sometimes we need to wait
// awhile to guarantee that we've been patient waiting for something ordinary
// to happen: a pod to get scheduled and move into Ready
const schedulingTimeout = 5 * time.Minute
var _ = framework.KubeDescribe("DisruptionController", func() {
f := framework.NewDefaultFramework("disruption")
var ns string
@ -55,7 +65,7 @@ var _ = framework.KubeDescribe("DisruptionController", func() {
// Since disruptionAllowed starts out false, if we see it ever become true,
// that means the controller is working.
err := wait.PollImmediate(framework.Poll, 60*time.Second, func() (bool, error) {
err := wait.PollImmediate(framework.Poll, timeout, func() (bool, error) {
pdb, err := cs.Policy().PodDisruptionBudgets(ns).Get("foo")
if err != nil {
return false, err
@ -66,73 +76,107 @@ var _ = framework.KubeDescribe("DisruptionController", func() {
})
It("should allow an eviction when there is no PDB", func() {
createPodsOrDie(cs, ns, 1)
pod, err := cs.Pods(ns).Get("pod-0")
Expect(err).NotTo(HaveOccurred())
e := &policy.Eviction{
ObjectMeta: api.ObjectMeta{
Name: pod.Name,
Namespace: ns,
},
evictionCases := []struct {
description string
minAvailable intstr.IntOrString
podCount int
replicaSetSize int32
shouldDeny bool
exclusive bool
}{
{
description: "no PDB",
minAvailable: intstr.FromString(""),
podCount: 1,
shouldDeny: false,
}, {
description: "too few pods, absolute",
minAvailable: intstr.FromInt(2),
podCount: 1,
shouldDeny: true,
}, {
description: "enough pods, absolute",
minAvailable: intstr.FromInt(2),
podCount: 2,
shouldDeny: false,
}, {
description: "enough pods, replicaSet, percentage",
minAvailable: intstr.FromString("100%"),
replicaSetSize: 10,
exclusive: false,
shouldDeny: false,
}, {
description: "too few pods, replicaSet, percentage",
minAvailable: intstr.FromString("100%"),
replicaSetSize: 10,
exclusive: true,
shouldDeny: true,
},
}
for _, c := range evictionCases {
expectation := "should allow an eviction"
if c.shouldDeny {
expectation = "should not allow an eviction"
}
It(fmt.Sprintf("evictions: %s => %s", c.description, expectation), func() {
createPodsOrDie(cs, ns, c.podCount)
if c.replicaSetSize > 0 {
createReplicaSetOrDie(cs, ns, c.replicaSetSize, c.exclusive)
}
err = cs.Pods(ns).Evict(e)
Expect(err).NotTo(HaveOccurred())
})
if c.minAvailable.String() != "" {
createPodDisruptionBudgetOrDie(cs, ns, c.minAvailable)
}
It("should not allow an eviction when too few pods", func() {
createPodDisruptionBudgetOrDie(cs, ns, intstr.FromInt(2))
// Locate a running pod.
var pod api.Pod
err := wait.PollImmediate(framework.Poll, schedulingTimeout, func() (bool, error) {
podList, err := cs.Pods(ns).List(apiapi.ListOptions{})
if err != nil {
return false, err
}
createPodsOrDie(cs, ns, 1)
for i := range podList.Items {
if podList.Items[i].Status.Phase == api.PodRunning {
pod = podList.Items[i]
return true, nil
}
}
pod, err := cs.Pods(ns).Get("pod-0")
Expect(err).NotTo(HaveOccurred())
e := &policy.Eviction{
ObjectMeta: api.ObjectMeta{
Name: pod.Name,
Namespace: ns,
},
}
// Since disruptionAllowed starts out false, wait at least 60s hoping that
// this gives the controller enough time to have truly set the status.
time.Sleep(60 * time.Second)
err = cs.Pods(ns).Evict(e)
Expect(err).Should(MatchError("Cannot evict pod as it would violate the pod's disruption budget."))
})
It("should allow an eviction when enough pods", func() {
createPodDisruptionBudgetOrDie(cs, ns, intstr.FromInt(2))
createPodsOrDie(cs, ns, 2)
pod, err := cs.Pods(ns).Get("pod-0")
Expect(err).NotTo(HaveOccurred())
e := &policy.Eviction{
ObjectMeta: api.ObjectMeta{
Name: pod.Name,
Namespace: ns,
},
}
// Since disruptionAllowed starts out false, if an eviction is ever allowed,
// that means the controller is working.
err = wait.PollImmediate(framework.Poll, 60*time.Second, func() (bool, error) {
err = cs.Pods(ns).Evict(e)
if err != nil {
return false, nil
})
Expect(err).NotTo(HaveOccurred())
e := &policy.Eviction{
ObjectMeta: api.ObjectMeta{
Name: pod.Name,
Namespace: ns,
},
}
if c.shouldDeny {
// Since disruptionAllowed starts out false, wait at least 60s hoping that
// this gives the controller enough time to have truly set the status.
time.Sleep(timeout)
err = cs.Pods(ns).Evict(e)
Expect(err).Should(MatchError("Cannot evict pod as it would violate the pod's disruption budget."))
} else {
return true, nil
// Since disruptionAllowed starts out false, if an eviction is ever allowed,
// that means the controller is working.
err = wait.PollImmediate(framework.Poll, timeout, func() (bool, error) {
err = cs.Pods(ns).Evict(e)
if err != nil {
return false, nil
} else {
return true, nil
}
})
Expect(err).NotTo(HaveOccurred())
}
})
Expect(err).NotTo(HaveOccurred())
})
}
})
func createPodDisruptionBudgetOrDie(cs *release_1_4.Clientset, ns string, minAvailable intstr.IntOrString) {
@ -173,3 +217,39 @@ func createPodsOrDie(cs *release_1_4.Clientset, ns string, n int) {
framework.ExpectNoError(err, "Creating pod %q in namespace %q", pod.Name, ns)
}
}
func createReplicaSetOrDie(cs *release_1_4.Clientset, ns string, size int32, exclusive bool) {
container := api.Container{
Name: "busybox",
Image: "gcr.io/google_containers/echoserver:1.4",
}
if exclusive {
container.Ports = []api.ContainerPort{
{HostPort: 5555, ContainerPort: 5555},
}
}
rs := &extensions.ReplicaSet{
ObjectMeta: api.ObjectMeta{
Name: "rs",
Namespace: ns,
},
Spec: extensions.ReplicaSetSpec{
Replicas: &size,
Selector: &extensions.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"},
},
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: map[string]string{"foo": "bar"},
},
Spec: api.PodSpec{
Containers: []api.Container{container},
},
},
},
}
_, err := cs.Extensions().ReplicaSets(ns).Create(rs)
framework.ExpectNoError(err, "Creating replica set %q in namespace %q", rs.Name, ns)
}