test: e2e tests for perma-failed deployments

This commit is contained in:
Michail Kargakis 2016-09-15 17:58:19 +02:00
parent a5029bf373
commit de8214ad4d
3 changed files with 200 additions and 4 deletions

View File

@ -18,6 +18,7 @@ package e2e
import (
"fmt"
"math/rand"
"strings"
"time"
@ -95,6 +96,12 @@ var _ = framework.KubeDescribe("Deployment", func() {
It("overlapping deployment should not fight with each other", func() {
testOverlappingDeployment(f)
})
It("lack of progress should be reported in the deployment status", func() {
testFailedDeployment(f)
})
It("iterative rollouts should eventually progress", func() {
testIterativeDeployments(f)
})
// TODO: add tests that cover deployment.Spec.MinReadySeconds once we solved clock-skew issues
// See https://github.com/kubernetes/kubernetes/issues/29229
})
@ -418,8 +425,8 @@ func testRollingUpdateDeploymentEvents(f *framework.Framework) {
newRS, err := deploymentutil.GetNewReplicaSet(deployment, c)
Expect(err).NotTo(HaveOccurred())
Expect(newRS).NotTo(Equal(nil))
Expect(events.Items[0].Message).Should(Equal(fmt.Sprintf("Scaled up replica set %s to 1", newRS.Name)))
Expect(events.Items[1].Message).Should(Equal(fmt.Sprintf("Scaled down replica set %s to 0", rsName)))
Expect(events.Items[0].Message).Should(Equal(fmt.Sprintf("Created new replica set %q and scaled up to 1", newRS.Name)))
Expect(events.Items[1].Message).Should(Equal(fmt.Sprintf("Scaled down replica set %q to 0", rsName)))
}
func testRecreateDeployment(f *framework.Framework) {
@ -470,8 +477,8 @@ func testRecreateDeployment(f *framework.Framework) {
newRS, err := deploymentutil.GetNewReplicaSet(deployment, c)
Expect(err).NotTo(HaveOccurred())
Expect(newRS).NotTo(Equal(nil))
Expect(events.Items[0].Message).Should(Equal(fmt.Sprintf("Scaled down replica set %s to 0", rsName)))
Expect(events.Items[1].Message).Should(Equal(fmt.Sprintf("Scaled up replica set %s to 3", newRS.Name)))
Expect(events.Items[0].Message).Should(Equal(fmt.Sprintf("Scaled down replica set %q to 0", rsName)))
Expect(events.Items[1].Message).Should(Equal(fmt.Sprintf("Created new replica set %q and scaled up to 3", newRS.Name)))
}
// testDeploymentCleanUpPolicy tests that deployment supports cleanup policy
@ -1316,3 +1323,173 @@ func testOverlappingDeployment(f *framework.Framework) {
err = framework.WaitForDeploymentRevisionAndImage(c, ns, deployOverlapping.Name, "2", redisImage)
Expect(err).NotTo(HaveOccurred(), "The second deployment failed to update to revision 2")
}
func testFailedDeployment(f *framework.Framework) {
ns := f.Namespace.Name
c := f.ClientSet
podLabels := map[string]string{"name": nginxImageName}
replicas := int32(1)
// Create a nginx deployment.
deploymentName := "nginx"
nonExistentImage := "nginx:not-there"
thirty := int32(30)
d := newDeployment(deploymentName, replicas, podLabels, nginxImageName, nonExistentImage, extensions.RecreateDeploymentStrategyType, nil)
d.Spec.ProgressDeadlineSeconds = &thirty
framework.Logf("Creating deployment %q with progressDeadlineSeconds set to %ds and a non-existent image", deploymentName, thirty)
deployment, err := c.Extensions().Deployments(ns).Create(d)
Expect(err).NotTo(HaveOccurred())
framework.Logf("Waiting for deployment %q to be observed by the controller", deploymentName)
Expect(framework.WaitForObservedDeployment(c, ns, deploymentName, deployment.Generation)).NotTo(HaveOccurred())
framework.Logf("Waiting for deployment %q status", deploymentName)
Expect(framework.WaitForDeploymentStatus(c, deployment)).NotTo(HaveOccurred())
framework.Logf("Checking deployment %q for a timeout condition", deploymentName)
Expect(framework.WaitForDeploymentWithCondition(c, ns, deploymentName, deploymentutil.TimedOutReason, extensions.DeploymentProgressing)).NotTo(HaveOccurred())
framework.Logf("Updating deployment %q with a good image", deploymentName)
deployment, err = framework.UpdateDeploymentWithRetries(c, ns, deployment.Name, func(update *extensions.Deployment) {
update.Spec.Template.Spec.Containers[0].Image = nginxImage
})
Expect(err).NotTo(HaveOccurred())
framework.Logf("Waiting for deployment %q to be observed by the controller", deploymentName)
Expect(framework.WaitForObservedDeployment(c, ns, deploymentName, deployment.Generation)).NotTo(HaveOccurred())
framework.Logf("Waiting for deployment %q status", deploymentName)
Expect(framework.WaitForDeploymentStatus(c, deployment)).NotTo(HaveOccurred())
framework.Logf("Checking deployment %q for a complete condition", deploymentName)
Expect(framework.WaitForDeploymentWithCondition(c, ns, deploymentName, deploymentutil.NewRSAvailableReason, extensions.DeploymentProgressing)).NotTo(HaveOccurred())
}
func randomScale(d *extensions.Deployment, i int) {
switch r := rand.Float32(); {
case r < 0.3:
framework.Logf("%02d: scaling up", i)
d.Spec.Replicas++
case r < 0.6:
if d.Spec.Replicas > 1 {
framework.Logf("%02d: scaling down", i)
d.Spec.Replicas--
}
}
}
func testIterativeDeployments(f *framework.Framework) {
ns := f.Namespace.Name
c := f.ClientSet
podLabels := map[string]string{"name": nginxImageName}
replicas := int32(6)
zero := int64(0)
two := int32(2)
// Create a nginx deployment.
deploymentName := "nginx"
thirty := int32(30)
d := newDeployment(deploymentName, replicas, podLabels, nginxImageName, nginxImage, extensions.RollingUpdateDeploymentStrategyType, nil)
d.Spec.ProgressDeadlineSeconds = &thirty
d.Spec.RevisionHistoryLimit = &two
d.Spec.Template.Spec.TerminationGracePeriodSeconds = &zero
framework.Logf("Creating deployment %q", deploymentName)
deployment, err := c.Extensions().Deployments(ns).Create(d)
Expect(err).NotTo(HaveOccurred())
iterations := 20
for i := 0; i < iterations; i++ {
if r := rand.Float32(); r < 0.6 {
time.Sleep(time.Duration(float32(i) * r * float32(time.Second)))
}
switch n := rand.Float32(); {
case n < 0.2:
// trigger a new deployment
framework.Logf("%02d: triggering a new rollout for deployment %q", i, deployment.Name)
deployment, err = framework.UpdateDeploymentWithRetries(c, ns, deployment.Name, func(update *extensions.Deployment) {
newEnv := api.EnvVar{Name: "A", Value: fmt.Sprintf("%d", i)}
update.Spec.Template.Spec.Containers[0].Env = append(update.Spec.Template.Spec.Containers[0].Env, newEnv)
randomScale(update, i)
})
Expect(err).NotTo(HaveOccurred())
case n < 0.4:
// rollback to the previous version
framework.Logf("%02d: rolling back a rollout for deployment %q", i, deployment.Name)
deployment, err = framework.UpdateDeploymentWithRetries(c, ns, deployment.Name, func(update *extensions.Deployment) {
rollbackTo := &extensions.RollbackConfig{Revision: 0}
update.Spec.RollbackTo = rollbackTo
})
Expect(err).NotTo(HaveOccurred())
case n < 0.6:
// just scaling
framework.Logf("%02d: scaling deployment %q", i, deployment.Name)
deployment, err = framework.UpdateDeploymentWithRetries(c, ns, deployment.Name, func(update *extensions.Deployment) {
randomScale(update, i)
})
Expect(err).NotTo(HaveOccurred())
case n < 0.8:
// toggling the deployment
if deployment.Spec.Paused {
framework.Logf("%02d: pausing deployment %q", i, deployment.Name)
deployment, err = framework.UpdateDeploymentWithRetries(c, ns, deployment.Name, func(update *extensions.Deployment) {
update.Spec.Paused = true
randomScale(update, i)
})
Expect(err).NotTo(HaveOccurred())
} else {
framework.Logf("%02d: resuming deployment %q", i, deployment.Name)
deployment, err = framework.UpdateDeploymentWithRetries(c, ns, deployment.Name, func(update *extensions.Deployment) {
update.Spec.Paused = false
randomScale(update, i)
})
Expect(err).NotTo(HaveOccurred())
}
default:
// arbitrarily delete deployment pods
framework.Logf("%02d: arbitrarily deleting one or more deployment pods for deployment %q", i, deployment.Name)
selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector)
Expect(err).NotTo(HaveOccurred())
opts := api.ListOptions{LabelSelector: selector}
podList, err := c.Core().Pods(ns).List(opts)
Expect(err).NotTo(HaveOccurred())
if len(podList.Items) == 0 {
framework.Logf("%02d: no deployment pods to delete", i)
continue
}
for p := range podList.Items {
if rand.Float32() < 0.5 {
continue
}
name := podList.Items[p].Name
framework.Logf("%02d: deleting deployment pod %q", i, name)
Expect(c.Core().Pods(ns).Delete(name, nil)).NotTo(HaveOccurred())
}
}
}
// unpause the deployment if we end up pausing it
deployment, err = c.Extensions().Deployments(ns).Get(deployment.Name)
Expect(err).NotTo(HaveOccurred())
if deployment.Spec.Paused {
deployment, err = framework.UpdateDeploymentWithRetries(c, ns, deployment.Name, func(update *extensions.Deployment) {
update.Spec.Paused = false
})
}
framework.Logf("Waiting for deployment %q to be observed by the controller", deploymentName)
Expect(framework.WaitForObservedDeployment(c, ns, deploymentName, deployment.Generation)).NotTo(HaveOccurred())
framework.Logf("Waiting for deployment %q status", deploymentName)
Expect(framework.WaitForDeploymentStatusValid(c, deployment)).NotTo(HaveOccurred())
framework.Logf("Checking deployment %q for a complete condition", deploymentName)
Expect(framework.WaitForDeploymentWithCondition(c, ns, deploymentName, deploymentutil.NewRSAvailableReason, extensions.DeploymentProgressing)).NotTo(HaveOccurred())
}

View File

@ -3173,6 +3173,23 @@ func WaitForObservedDeployment(c clientset.Interface, ns, deploymentName string,
return deploymentutil.WaitForObservedDeployment(func() (*extensions.Deployment, error) { return c.Extensions().Deployments(ns).Get(deploymentName) }, desiredGeneration, Poll, 1*time.Minute)
}
func WaitForDeploymentWithCondition(c clientset.Interface, ns, deploymentName, reason string, condType extensions.DeploymentConditionType) error {
var conditions []extensions.DeploymentCondition
pollErr := wait.PollImmediate(time.Second, 1*time.Minute, func() (bool, error) {
deployment, err := c.Extensions().Deployments(ns).Get(deploymentName)
if err != nil {
return false, err
}
conditions = deployment.Status.Conditions
cond := deploymentutil.GetDeploymentCondition(deployment.Status, condType)
return cond != nil && cond.Reason == reason, nil
})
if pollErr == wait.ErrWaitTimeout {
pollErr = fmt.Errorf("deployment %q never updated with the desired condition and reason: %v", deploymentName, conditions)
}
return pollErr
}
func logPodsOfDeployment(c clientset.Interface, deployment *extensions.Deployment) {
minReadySeconds := deployment.Spec.MinReadySeconds
podList, err := deploymentutil.ListPods(deployment,

View File

@ -63,6 +63,8 @@ Deployment deployment should label adopted RSs and pods,pwittrock,0
Deployment deployment should support rollback,pwittrock,0
Deployment deployment should support rollback when there's replica set with no revision,pwittrock,0
Deployment deployment should support rollover,pwittrock,0
Deployment iterative rollouts should eventually progress,kargakis,0
Deployment lack of progress should be reported in the deployment status,kargakis,0
Deployment overlapping deployment should not fight with each other,kargakis,1
Deployment paused deployment should be able to scale,kargakis,1
Deployment paused deployment should be ignored by the controller,kargakis,0

1 name owner auto-assigned
63 Deployment deployment should support rollback pwittrock 0
64 Deployment deployment should support rollback when there's replica set with no revision pwittrock 0
65 Deployment deployment should support rollover pwittrock 0
66 Deployment iterative rollouts should eventually progress kargakis 0
67 Deployment lack of progress should be reported in the deployment status kargakis 0
68 Deployment overlapping deployment should not fight with each other kargakis 1
69 Deployment paused deployment should be able to scale kargakis 1
70 Deployment paused deployment should be ignored by the controller kargakis 0