mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
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:
commit
a26da7a1c4
@ -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)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user