Refactor disruption e2e test and add some eviction test cases.
This commit is contained in:
		@@ -23,14 +23,24 @@ import (
 | 
				
			|||||||
	. "github.com/onsi/ginkgo"
 | 
						. "github.com/onsi/ginkgo"
 | 
				
			||||||
	. "github.com/onsi/gomega"
 | 
						. "github.com/onsi/gomega"
 | 
				
			||||||
	release_1_4 "k8s.io/client-go/1.4/kubernetes"
 | 
						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"
 | 
						"k8s.io/client-go/1.4/pkg/api/unversioned"
 | 
				
			||||||
	api "k8s.io/client-go/1.4/pkg/api/v1"
 | 
						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"
 | 
						policy "k8s.io/client-go/1.4/pkg/apis/policy/v1alpha1"
 | 
				
			||||||
	"k8s.io/client-go/1.4/pkg/util/intstr"
 | 
						"k8s.io/client-go/1.4/pkg/util/intstr"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/wait"
 | 
						"k8s.io/kubernetes/pkg/util/wait"
 | 
				
			||||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
						"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() {
 | 
					var _ = framework.KubeDescribe("DisruptionController", func() {
 | 
				
			||||||
	f := framework.NewDefaultFramework("disruption")
 | 
						f := framework.NewDefaultFramework("disruption")
 | 
				
			||||||
	var ns string
 | 
						var ns string
 | 
				
			||||||
@@ -55,7 +65,7 @@ var _ = framework.KubeDescribe("DisruptionController", func() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Since disruptionAllowed starts out false, if we see it ever become true,
 | 
							// Since disruptionAllowed starts out false, if we see it ever become true,
 | 
				
			||||||
		// that means the controller is working.
 | 
							// 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")
 | 
								pdb, err := cs.Policy().PodDisruptionBudgets(ns).Get("foo")
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return false, err
 | 
									return false, err
 | 
				
			||||||
@@ -66,73 +76,107 @@ var _ = framework.KubeDescribe("DisruptionController", func() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	It("should allow an eviction when there is no PDB", func() {
 | 
						evictionCases := []struct {
 | 
				
			||||||
		createPodsOrDie(cs, ns, 1)
 | 
							description    string
 | 
				
			||||||
 | 
							minAvailable   intstr.IntOrString
 | 
				
			||||||
		pod, err := cs.Pods(ns).Get("pod-0")
 | 
							podCount       int
 | 
				
			||||||
		Expect(err).NotTo(HaveOccurred())
 | 
							replicaSetSize int32
 | 
				
			||||||
 | 
							shouldDeny     bool
 | 
				
			||||||
		e := &policy.Eviction{
 | 
							exclusive      bool
 | 
				
			||||||
			ObjectMeta: api.ObjectMeta{
 | 
						}{
 | 
				
			||||||
				Name:      pod.Name,
 | 
							{
 | 
				
			||||||
				Namespace: ns,
 | 
								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)
 | 
								if c.minAvailable.String() != "" {
 | 
				
			||||||
		Expect(err).NotTo(HaveOccurred())
 | 
									createPodDisruptionBudgetOrDie(cs, ns, c.minAvailable)
 | 
				
			||||||
	})
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	It("should not allow an eviction when too few pods", func() {
 | 
								// Locate a running pod.
 | 
				
			||||||
		createPodDisruptionBudgetOrDie(cs, ns, intstr.FromInt(2))
 | 
								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
 | 
									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 {
 | 
								} 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) {
 | 
					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)
 | 
							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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user