Commit 1ca6120a authored by Janet Kuo's avatar Janet Kuo

Move deployment e2e test for rollback with no revision to integration

parent 4de496d4
...@@ -360,7 +360,7 @@ func TestSampleAPIServer(f *framework.Framework, image string) { ...@@ -360,7 +360,7 @@ func TestSampleAPIServer(f *framework.Framework, image string) {
// kubectl get deployments -n <aggregated-api-namespace> && status == Running // kubectl get deployments -n <aggregated-api-namespace> && status == Running
// NOTE: aggregated apis should generally be set up in there own namespace (<aggregated-api-namespace>). As the test framework // NOTE: aggregated apis should generally be set up in there own namespace (<aggregated-api-namespace>). As the test framework
// is setting up a new namespace, we are just using that. // is setting up a new namespace, we are just using that.
err = framework.WaitForDeploymentStatusValid(client, deployment) err = framework.WaitForDeploymentComplete(client, deployment)
// We seem to need to do additional waiting until the extension api service is actually up. // We seem to need to do additional waiting until the extension api service is actually up.
err = wait.Poll(100*time.Millisecond, 30*time.Second, func() (bool, error) { err = wait.Poll(100*time.Millisecond, 30*time.Second, func() (bool, error) {
......
...@@ -70,7 +70,6 @@ go_library( ...@@ -70,7 +70,6 @@ go_library(
"//pkg/master/ports:go_default_library", "//pkg/master/ports:go_default_library",
"//pkg/ssh:go_default_library", "//pkg/ssh:go_default_library",
"//pkg/util/file:go_default_library", "//pkg/util/file:go_default_library",
"//pkg/util/labels:go_default_library",
"//pkg/util/system:go_default_library", "//pkg/util/system:go_default_library",
"//pkg/util/taints:go_default_library", "//pkg/util/taints:go_default_library",
"//pkg/util/version:go_default_library", "//pkg/util/version:go_default_library",
......
...@@ -31,7 +31,6 @@ import ( ...@@ -31,7 +31,6 @@ import (
extensionsinternal "k8s.io/kubernetes/pkg/apis/extensions" extensionsinternal "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
labelsutil "k8s.io/kubernetes/pkg/util/labels"
testutils "k8s.io/kubernetes/test/utils" testutils "k8s.io/kubernetes/test/utils"
) )
...@@ -131,69 +130,17 @@ func NewDeployment(deploymentName string, replicas int32, podLabels map[string]s ...@@ -131,69 +130,17 @@ func NewDeployment(deploymentName string, replicas int32, podLabels map[string]s
} }
} }
// Waits for the deployment status to become valid (i.e. max unavailable and max surge aren't violated anymore). // Waits for the deployment to complete, and don't check if rolling update strategy is broken.
// Note that the status should stay valid at all times unless shortly after a scaling event or the deployment is just created. // Rolling update strategy is used only during a rolling update, and can be violated in other situations,
// To verify that the deployment status is valid and wait for the rollout to finish, use WaitForDeploymentStatus instead. // such as shortly after a scaling event or the deployment is just created.
func WaitForDeploymentStatusValid(c clientset.Interface, d *extensions.Deployment) error { func WaitForDeploymentComplete(c clientset.Interface, d *extensions.Deployment) error {
return testutils.WaitForDeploymentStatusValid(c, d, Logf, Poll, pollLongTimeout) return testutils.WaitForDeploymentComplete(c, d, Logf, Poll, pollLongTimeout)
} }
// Waits for the deployment to reach desired state. // Waits for the deployment to complete, and check rolling update strategy isn't broken at any times.
// Returns an error if the deployment's rolling update strategy (max unavailable or max surge) is broken at any times. // Rolling update strategy should not be broken during a rolling update.
func WaitForDeploymentStatus(c clientset.Interface, d *extensions.Deployment) error { func WaitForDeploymentCompleteAndCheckRolling(c clientset.Interface, d *extensions.Deployment) error {
var ( return testutils.WaitForDeploymentCompleteAndCheckRolling(c, d, Logf, Poll, pollLongTimeout)
oldRSs, allOldRSs, allRSs []*extensions.ReplicaSet
newRS *extensions.ReplicaSet
deployment *extensions.Deployment
)
err := wait.Poll(Poll, 5*time.Minute, func() (bool, error) {
var err error
deployment, err = c.Extensions().Deployments(d.Namespace).Get(d.Name, metav1.GetOptions{})
if err != nil {
return false, err
}
oldRSs, allOldRSs, newRS, err = deploymentutil.GetAllReplicaSets(deployment, c.ExtensionsV1beta1())
if err != nil {
return false, err
}
if newRS == nil {
// New RS hasn't been created yet.
return false, nil
}
allRSs = append(oldRSs, newRS)
// The old/new ReplicaSets need to contain the pod-template-hash label
for i := range allRSs {
if !labelsutil.SelectorHasLabel(allRSs[i].Spec.Selector, extensions.DefaultDeploymentUniqueLabelKey) {
return false, nil
}
}
totalCreated := deploymentutil.GetReplicaCountForReplicaSets(allRSs)
maxCreated := *(deployment.Spec.Replicas) + deploymentutil.MaxSurge(*deployment)
if totalCreated > maxCreated {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS)
logPodsOfDeployment(c, deployment, allRSs)
return false, fmt.Errorf("total pods created: %d, more than the max allowed: %d", totalCreated, maxCreated)
}
minAvailable := deploymentutil.MinAvailable(deployment)
if deployment.Status.AvailableReplicas < minAvailable {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS)
logPodsOfDeployment(c, deployment, allRSs)
return false, fmt.Errorf("total pods available: %d, less than the min required: %d", deployment.Status.AvailableReplicas, minAvailable)
}
// When the deployment status and its underlying resources reach the desired state, we're done
return deploymentutil.DeploymentComplete(deployment, &deployment.Status), nil
})
if err == wait.ErrWaitTimeout {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS)
logPodsOfDeployment(c, deployment, allRSs)
}
if err != nil {
return fmt.Errorf("error waiting for deployment %q status to match expectation: %v", d.Name, err)
}
return nil
} }
// WaitForDeploymentUpdatedReplicasLTE waits for given deployment to be observed by the controller and has at least a number of updatedReplicas // WaitForDeploymentUpdatedReplicasLTE waits for given deployment to be observed by the controller and has at least a number of updatedReplicas
...@@ -217,21 +164,7 @@ func WaitForDeploymentUpdatedReplicasLTE(c clientset.Interface, ns, deploymentNa ...@@ -217,21 +164,7 @@ func WaitForDeploymentUpdatedReplicasLTE(c clientset.Interface, ns, deploymentNa
// WaitForDeploymentRollbackCleared waits for given deployment either started rolling back or doesn't need to rollback. // WaitForDeploymentRollbackCleared waits for given deployment either started rolling back or doesn't need to rollback.
// Note that rollback should be cleared shortly, so we only wait for 1 minute here to fail early. // Note that rollback should be cleared shortly, so we only wait for 1 minute here to fail early.
func WaitForDeploymentRollbackCleared(c clientset.Interface, ns, deploymentName string) error { func WaitForDeploymentRollbackCleared(c clientset.Interface, ns, deploymentName string) error {
err := wait.Poll(Poll, 1*time.Minute, func() (bool, error) { return testutils.WaitForDeploymentRollbackCleared(c, ns, deploymentName, Poll, pollShortTimeout)
deployment, err := c.Extensions().Deployments(ns).Get(deploymentName, metav1.GetOptions{})
if err != nil {
return false, err
}
// Rollback not set or is kicked off
if deployment.Spec.RollbackTo == nil {
return true, nil
}
return false, nil
})
if err != nil {
return fmt.Errorf("error waiting for deployment %s rollbackTo to be cleared: %v", deploymentName, err)
}
return nil
} }
// WatchRecreateDeployment watches Recreate deployments and ensures no new pods will run at the same time with // WatchRecreateDeployment watches Recreate deployments and ensures no new pods will run at the same time with
...@@ -290,10 +223,6 @@ func logPodsOfDeployment(c clientset.Interface, deployment *extensions.Deploymen ...@@ -290,10 +223,6 @@ func logPodsOfDeployment(c clientset.Interface, deployment *extensions.Deploymen
testutils.LogPodsOfDeployment(c, deployment, rsList, Logf) testutils.LogPodsOfDeployment(c, deployment, rsList, Logf)
} }
func WaitForDeploymentCompletes(c clientset.Interface, deployment *extensions.Deployment) error {
return testutils.WaitForDeploymentCompletes(c, deployment, Logf, Poll, pollLongTimeout)
}
func WaitForDeploymentRevision(c clientset.Interface, d *extensions.Deployment, targetRevision string) error { func WaitForDeploymentRevision(c clientset.Interface, d *extensions.Deployment, targetRevision string) error {
err := wait.PollImmediate(Poll, pollLongTimeout, func() (bool, error) { err := wait.PollImmediate(Poll, pollLongTimeout, func() (bool, error) {
deployment, err := c.ExtensionsV1beta1().Deployments(d.Namespace).Get(d.Name, metav1.GetOptions{}) deployment, err := c.ExtensionsV1beta1().Deployments(d.Namespace).Get(d.Name, metav1.GetOptions{})
...@@ -308,3 +237,8 @@ func WaitForDeploymentRevision(c clientset.Interface, d *extensions.Deployment, ...@@ -308,3 +237,8 @@ func WaitForDeploymentRevision(c clientset.Interface, d *extensions.Deployment,
} }
return nil return nil
} }
// CheckDeploymentRevisionAndImage checks if the input deployment's and its new replica set's revision and image are as expected.
func CheckDeploymentRevisionAndImage(c clientset.Interface, ns, deploymentName, revision, image string) error {
return testutils.CheckDeploymentRevisionAndImage(c, ns, deploymentName, revision, image)
}
...@@ -63,7 +63,7 @@ func (t *DeploymentUpgradeTest) Setup(f *framework.Framework) { ...@@ -63,7 +63,7 @@ func (t *DeploymentUpgradeTest) Setup(f *framework.Framework) {
framework.ExpectNoError(err) framework.ExpectNoError(err)
By(fmt.Sprintf("Waiting deployment %q to complete", deploymentName)) By(fmt.Sprintf("Waiting deployment %q to complete", deploymentName))
framework.ExpectNoError(framework.WaitForDeploymentCompletes(c, deployment)) framework.ExpectNoError(framework.WaitForDeploymentComplete(c, deployment))
By(fmt.Sprintf("Getting replicaset revision 1 of deployment %q", deploymentName)) By(fmt.Sprintf("Getting replicaset revision 1 of deployment %q", deploymentName))
rsSelector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector) rsSelector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector)
...@@ -87,7 +87,7 @@ func (t *DeploymentUpgradeTest) Setup(f *framework.Framework) { ...@@ -87,7 +87,7 @@ func (t *DeploymentUpgradeTest) Setup(f *framework.Framework) {
framework.ExpectNoError(err) framework.ExpectNoError(err)
By(fmt.Sprintf("Waiting deployment %q to complete", deploymentName)) By(fmt.Sprintf("Waiting deployment %q to complete", deploymentName))
framework.ExpectNoError(framework.WaitForDeploymentCompletes(c, deployment)) framework.ExpectNoError(framework.WaitForDeploymentComplete(c, deployment))
By(fmt.Sprintf("Getting replicasets revision 1 and 2 of deployment %q", deploymentName)) By(fmt.Sprintf("Getting replicasets revision 1 and 2 of deployment %q", deploymentName))
rsList, err = rsClient.List(metav1.ListOptions{LabelSelector: rsSelector.String()}) rsList, err = rsClient.List(metav1.ListOptions{LabelSelector: rsSelector.String()})
...@@ -153,7 +153,7 @@ func (t *DeploymentUpgradeTest) Test(f *framework.Framework, done <-chan struct{ ...@@ -153,7 +153,7 @@ func (t *DeploymentUpgradeTest) Test(f *framework.Framework, done <-chan struct{
Expect(deployment.Annotations[deploymentutil.RevisionAnnotation]).To(Equal("2")) Expect(deployment.Annotations[deploymentutil.RevisionAnnotation]).To(Equal("2"))
By(fmt.Sprintf("Waiting for deployment %q to complete adoption", deploymentName)) By(fmt.Sprintf("Waiting for deployment %q to complete adoption", deploymentName))
framework.ExpectNoError(framework.WaitForDeploymentCompletes(c, deployment)) framework.ExpectNoError(framework.WaitForDeploymentComplete(c, deployment))
// Verify the upgraded deployment is active by scaling up the deployment by 1 // Verify the upgraded deployment is active by scaling up the deployment by 1
By(fmt.Sprintf("Scaling up replicaset of deployment %q by 1", deploymentName)) By(fmt.Sprintf("Scaling up replicaset of deployment %q by 1", deploymentName))
...@@ -163,7 +163,7 @@ func (t *DeploymentUpgradeTest) Test(f *framework.Framework, done <-chan struct{ ...@@ -163,7 +163,7 @@ func (t *DeploymentUpgradeTest) Test(f *framework.Framework, done <-chan struct{
framework.ExpectNoError(err) framework.ExpectNoError(err)
By(fmt.Sprintf("Waiting for deployment %q to complete after scaling", deploymentName)) By(fmt.Sprintf("Waiting for deployment %q to complete after scaling", deploymentName))
framework.ExpectNoError(framework.WaitForDeploymentCompletes(c, deployment)) framework.ExpectNoError(framework.WaitForDeploymentComplete(c, deployment))
} }
// Teardown cleans up any remaining resources. // Teardown cleans up any remaining resources.
......
...@@ -59,8 +59,9 @@ func TestNewDeployment(t *testing.T) { ...@@ -59,8 +59,9 @@ func TestNewDeployment(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// Make sure the Deployment status becomes valid while manually marking Deployment pods as ready at the same time // Make sure the Deployment completes while manually marking Deployment pods as ready at the same time.
if err := tester.waitForDeploymentStatusValidAndMarkPodsReady(); err != nil { // Use soft check because this deployment was just created and rolling update strategy might be violated.
if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -187,8 +188,9 @@ func TestPausedDeployment(t *testing.T) { ...@@ -187,8 +188,9 @@ func TestPausedDeployment(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// Make sure the Deployment status becomes valid while manually marking Deployment pods as ready at the same time // Make sure the Deployment completes while manually marking Deployment pods as ready at the same time.
if err := tester.waitForDeploymentStatusValidAndMarkPodsReady(); err != nil { // Use soft check because this deployment was just created and rolling update strategy might be violated.
if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -271,8 +273,9 @@ func TestScalePausedDeployment(t *testing.T) { ...@@ -271,8 +273,9 @@ func TestScalePausedDeployment(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// Make sure the Deployment status becomes valid while manually marking Deployment pods as ready at the same time // Make sure the Deployment completes while manually marking Deployment pods as ready at the same time.
if err := tester.waitForDeploymentStatusValidAndMarkPodsReady(); err != nil { // Use soft check because this deployment was just created and rolling update strategy might be violated.
if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -315,8 +318,9 @@ func TestScalePausedDeployment(t *testing.T) { ...@@ -315,8 +318,9 @@ func TestScalePausedDeployment(t *testing.T) {
t.Errorf("expected new replicaset replicas = %d, got %d", newReplicas, *rs.Spec.Replicas) t.Errorf("expected new replicaset replicas = %d, got %d", newReplicas, *rs.Spec.Replicas)
} }
// Make sure the Deployment status becomes valid while manually marking Deployment pods as ready at the same time // Make sure the Deployment completes while manually marking Deployment pods as ready at the same time.
if err := tester.waitForDeploymentStatusValidAndMarkPodsReady(); err != nil { // Use soft check because this deployment was just scaled and rolling update strategy might be violated.
if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
...@@ -381,3 +385,116 @@ func TestDeploymentHashCollision(t *testing.T) { ...@@ -381,3 +385,116 @@ func TestDeploymentHashCollision(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
} }
// Deployment supports rollback even when there's old replica set without revision.
func TestRollbackDeploymentRSNoRevision(t *testing.T) {
s, closeFn, rm, dc, informers, c := dcSetup(t)
defer closeFn()
name := "test-rollback-no-revision-deployment"
ns := framework.CreateTestingNamespace(name, s, t)
defer framework.DeleteTestingNamespace(ns, s, t)
// Create an old RS without revision
rsName := "test-rollback-no-revision-controller"
rsReplicas := int32(1)
rs := newReplicaSet(rsName, ns.Name, rsReplicas)
rs.Annotations = make(map[string]string)
rs.Annotations["make"] = "difference"
rs.Spec.Template.Spec.Containers[0].Image = "different-image"
_, err := c.ExtensionsV1beta1().ReplicaSets(ns.Name).Create(rs)
if err != nil {
t.Fatalf("failed to create replicaset %s: %v", rsName, err)
}
replicas := int32(1)
tester := &deploymentTester{t: t, c: c, deployment: newDeployment(name, ns.Name, replicas)}
oriImage := tester.deployment.Spec.Template.Spec.Containers[0].Image
// Create a deployment which have different template than the replica set created above.
if tester.deployment, err = c.ExtensionsV1beta1().Deployments(ns.Name).Create(tester.deployment); err != nil {
t.Fatalf("failed to create deployment %s: %v", tester.deployment.Name, err)
}
// Start informer and controllers
stopCh := make(chan struct{})
defer close(stopCh)
informers.Start(stopCh)
go rm.Run(5, stopCh)
go dc.Run(5, stopCh)
// Wait for the Deployment to be updated to revision 1
if err = tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil {
t.Fatal(err)
}
// 1. Rollback to the last revision
// Since there's only 1 revision in history, it should still be revision 1
revision := int64(0)
rollback := newDeploymentRollback(tester.deployment.Name, nil, revision)
if err = c.ExtensionsV1beta1().Deployments(ns.Name).Rollback(rollback); err != nil {
t.Fatalf("failed to roll back deployment %s to last revision: %v", tester.deployment.Name, err)
}
// Wait for the deployment to start rolling back
if err = tester.waitForDeploymentRollbackCleared(); err != nil {
t.Fatalf("failed to roll back deployment %s to last revision: %v", tester.deployment.Name, err)
}
// TODO: report RollbackRevisionNotFound in deployment status and check it here
// The pod template shouldn't change since there's no last revision
// Check if the deployment is still revision 1 and still has the old pod template
err = tester.checkDeploymentRevisionAndImage("1", oriImage)
if err != nil {
t.Fatal(err)
}
// 2. Update the deployment to revision 2.
updatedImage := "update"
tester.deployment, err = tester.updateDeployment(func(update *v1beta1.Deployment) {
update.Spec.Template.Spec.Containers[0].Name = updatedImage
update.Spec.Template.Spec.Containers[0].Image = updatedImage
})
if err != nil {
t.Fatalf("failed updating deployment %s: %v", tester.deployment.Name, err)
}
// Use observedGeneration to determine if the controller noticed the pod template update.
// Wait for the controller to notice the resume.
if err = tester.waitForObservedDeployment(tester.deployment.Generation); err != nil {
t.Fatal(err)
}
// Wait for it to be updated to revision 2
if err = tester.waitForDeploymentRevisionAndImage("2", updatedImage); err != nil {
t.Fatal(err)
}
// Wait for the Deployment to complete while manually marking Deployment pods as ready at the same time
if err = tester.waitForDeploymentCompleteAndCheckRollingAndMarkPodsReady(); err != nil {
t.Fatal(err)
}
// 3. Update the deploymentRollback to rollback to revision 1
revision = int64(1)
rollback = newDeploymentRollback(tester.deployment.Name, nil, revision)
if err = c.ExtensionsV1beta1().Deployments(ns.Name).Rollback(rollback); err != nil {
t.Fatalf("failed to roll back deployment %s to revision %d: %v", tester.deployment.Name, revision, err)
}
// Wait for the deployment to start rolling back
if err = tester.waitForDeploymentRollbackCleared(); err != nil {
t.Fatalf("failed to roll back deployment %s to revision %d: %v", tester.deployment.Name, revision, err)
}
// TODO: report RollbackDone in deployment status and check it here
// The pod template should be updated to the one in revision 1
// Wait for it to be updated to revision 3
if err = tester.waitForDeploymentRevisionAndImage("3", oriImage); err != nil {
t.Fatal(err)
}
// Wait for the Deployment to complete while manually marking Deployment pods as ready at the same time
if err = tester.waitForDeploymentCompleteAndCheckRollingAndMarkPodsReady(); err != nil {
t.Fatal(err)
}
}
...@@ -41,8 +41,8 @@ const ( ...@@ -41,8 +41,8 @@ const (
pollInterval = 100 * time.Millisecond pollInterval = 100 * time.Millisecond
pollTimeout = 60 * time.Second pollTimeout = 60 * time.Second
fakeImageName = "fake-name" fakeContainerName = "fake-name"
fakeImage = "fakeimage" fakeImage = "fakeimage"
) )
var pauseFn = func(update *v1beta1.Deployment) { var pauseFn = func(update *v1beta1.Deployment) {
...@@ -87,7 +87,7 @@ func newDeployment(name, ns string, replicas int32) *v1beta1.Deployment { ...@@ -87,7 +87,7 @@ func newDeployment(name, ns string, replicas int32) *v1beta1.Deployment {
Spec: v1.PodSpec{ Spec: v1.PodSpec{
Containers: []v1.Container{ Containers: []v1.Container{
{ {
Name: fakeImageName, Name: fakeContainerName,
Image: fakeImage, Image: fakeImage,
}, },
}, },
...@@ -97,6 +97,46 @@ func newDeployment(name, ns string, replicas int32) *v1beta1.Deployment { ...@@ -97,6 +97,46 @@ func newDeployment(name, ns string, replicas int32) *v1beta1.Deployment {
} }
} }
func newReplicaSet(name, ns string, replicas int32) *v1beta1.ReplicaSet {
return &v1beta1.ReplicaSet{
TypeMeta: metav1.TypeMeta{
Kind: "ReplicaSet",
APIVersion: "extensions/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: ns,
Name: name,
},
Spec: v1beta1.ReplicaSetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: testLabels(),
},
Replicas: &replicas,
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: testLabels(),
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: fakeContainerName,
Image: fakeImage,
},
},
},
},
},
}
}
func newDeploymentRollback(name string, annotations map[string]string, revision int64) *v1beta1.DeploymentRollback {
return &v1beta1.DeploymentRollback{
Name: name,
UpdatedAnnotations: annotations,
RollbackTo: v1beta1.RollbackConfig{Revision: revision},
}
}
// dcSetup sets up necessities for Deployment integration test, including master, apiserver, informers, and clientset // dcSetup sets up necessities for Deployment integration test, including master, apiserver, informers, and clientset
func dcSetup(t *testing.T) (*httptest.Server, framework.CloseFunc, *replicaset.ReplicaSetController, *deployment.DeploymentController, informers.SharedInformerFactory, clientset.Interface) { func dcSetup(t *testing.T) (*httptest.Server, framework.CloseFunc, *replicaset.ReplicaSetController, *deployment.DeploymentController, informers.SharedInformerFactory, clientset.Interface) {
masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig := framework.NewIntegrationTestMasterConfig()
...@@ -198,18 +238,42 @@ func (d *deploymentTester) markAllPodsReady() { ...@@ -198,18 +238,42 @@ func (d *deploymentTester) markAllPodsReady() {
} }
} }
func (d *deploymentTester) waitForDeploymentStatusValid() error { // Waits for the deployment to complete, and check rolling update strategy isn't broken at any times.
return testutil.WaitForDeploymentStatusValid(d.c, d.deployment, d.t.Logf, pollInterval, pollTimeout) // Rolling update strategy should not be broken during a rolling update.
func (d *deploymentTester) waitForDeploymentCompleteAndCheckRolling() error {
return testutil.WaitForDeploymentCompleteAndCheckRolling(d.c, d.deployment, d.t.Logf, pollInterval, pollTimeout)
} }
// waitForDeploymentStatusValidAndMarkPodsReady waits for the Deployment status to become valid // Waits for the deployment to complete, and don't check if rolling update strategy is broken.
// Rolling update strategy is used only during a rolling update, and can be violated in other situations,
// such as shortly after a scaling event or the deployment is just created.
func (d *deploymentTester) waitForDeploymentComplete() error {
return testutil.WaitForDeploymentComplete(d.c, d.deployment, d.t.Logf, pollInterval, pollTimeout)
}
// waitForDeploymentCompleteAndCheckRollingAndMarkPodsReady waits for the Deployment to complete
// while marking all Deployment pods as ready at the same time. // while marking all Deployment pods as ready at the same time.
func (d *deploymentTester) waitForDeploymentStatusValidAndMarkPodsReady() error { // Uses hard check to make sure rolling update strategy is not violated at any times.
func (d *deploymentTester) waitForDeploymentCompleteAndCheckRollingAndMarkPodsReady() error {
// Manually mark all Deployment pods as ready in a separate goroutine // Manually mark all Deployment pods as ready in a separate goroutine
go d.markAllPodsReady() go d.markAllPodsReady()
// Make sure the Deployment status is valid while Deployment pods are becoming ready // Wait for the Deployment status to complete while Deployment pods are becoming ready
err := d.waitForDeploymentStatusValid() err := d.waitForDeploymentCompleteAndCheckRolling()
if err != nil {
return fmt.Errorf("failed to wait for Deployment %s to complete: %v", d.deployment.Name, err)
}
return nil
}
// waitForDeploymentCompleteAndMarkPodsReady waits for the Deployment to complete
// while marking all Deployment pods as ready at the same time.
func (d *deploymentTester) waitForDeploymentCompleteAndMarkPodsReady() error {
// Manually mark all Deployment pods as ready in a separate goroutine
go d.markAllPodsReady()
// Wait for the Deployment status to complete using soft check, while Deployment pods are becoming ready
err := d.waitForDeploymentComplete()
if err != nil { if err != nil {
return fmt.Errorf("failed to wait for Deployment status %s: %v", d.deployment.Name, err) return fmt.Errorf("failed to wait for Deployment status %s: %v", d.deployment.Name, err)
} }
...@@ -260,3 +324,13 @@ func (d *deploymentTester) expectNewReplicaSet() (*v1beta1.ReplicaSet, error) { ...@@ -260,3 +324,13 @@ func (d *deploymentTester) expectNewReplicaSet() (*v1beta1.ReplicaSet, error) {
func (d *deploymentTester) updateReplicaSet(name string, applyUpdate testutil.UpdateReplicaSetFunc) (*v1beta1.ReplicaSet, error) { func (d *deploymentTester) updateReplicaSet(name string, applyUpdate testutil.UpdateReplicaSetFunc) (*v1beta1.ReplicaSet, error) {
return testutil.UpdateReplicaSetWithRetries(d.c, d.deployment.Namespace, name, applyUpdate, d.t.Logf, pollInterval, pollTimeout) return testutil.UpdateReplicaSetWithRetries(d.c, d.deployment.Namespace, name, applyUpdate, d.t.Logf, pollInterval, pollTimeout)
} }
// waitForDeploymentRollbackCleared waits for deployment either started rolling back or doesn't need to rollback.
func (d *deploymentTester) waitForDeploymentRollbackCleared() error {
return testutil.WaitForDeploymentRollbackCleared(d.c, d.deployment.Namespace, d.deployment.Name, pollInterval, pollTimeout)
}
// checkDeploymentRevisionAndImage checks if the input deployment's and its new replica set's revision and image are as expected.
func (d *deploymentTester) checkDeploymentRevisionAndImage(revision, image string) error {
return testutil.CheckDeploymentRevisionAndImage(d.c, d.deployment.Namespace, d.deployment.Name, revision, image)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment