Merge pull request #43114 from enisoc/deployment-upgrade-test

Automatic merge from submit-queue

Fix Deployment upgrade test.

**What this PR does / why we need it**:

When the upgrade test operates on Deployments in a pre-1.6 cluster (i.e. during the Setup phase), it needs to use the v1.5 deployment/util logic. In particular, the v1.5 logic does not filter children to only those with a matching ControllerRef.

**Which issue this PR fixes**:

Fixes #42738

**Special notes for your reviewer**:

**Release note**:
```release-note
```
cc @kubernetes/sig-apps-pr-reviews
This commit is contained in:
Kubernetes Submit Queue 2017-03-15 07:03:19 -07:00 committed by GitHub
commit 0afdcfcaf6
3 changed files with 148 additions and 58 deletions

View File

@ -494,11 +494,33 @@ func getReplicaSetFraction(rs extensions.ReplicaSet, d extensions.Deployment) in
// Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets.
// The third returned value is the new replica set, and it may be nil if it doesn't exist yet.
func GetAllReplicaSets(deployment *extensions.Deployment, c clientset.Interface) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, *extensions.ReplicaSet, error) {
rsList, err := listReplicaSets(deployment, c)
rsList, err := ListReplicaSets(deployment, rsListFromClient(c))
if err != nil {
return nil, nil, nil, err
}
podList, err := listPods(deployment, rsList, c)
podList, err := ListPods(deployment, rsList, podListFromClient(c))
if err != nil {
return nil, nil, nil, err
}
oldRSes, allOldRSes, err := FindOldReplicaSets(deployment, rsList, podList)
if err != nil {
return nil, nil, nil, err
}
newRS, err := FindNewReplicaSet(deployment, rsList)
if err != nil {
return nil, nil, nil, err
}
return oldRSes, allOldRSes, newRS, nil
}
// GetAllReplicaSetsV15 is a compatibility function that behaves the way
// GetAllReplicaSets() used to in v1.5.x.
func GetAllReplicaSetsV15(deployment *extensions.Deployment, c clientset.Interface) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, *extensions.ReplicaSet, error) {
rsList, err := ListReplicaSetsV15(deployment, rsListFromClient(c))
if err != nil {
return nil, nil, nil, err
}
podList, err := ListPodsV15(deployment, podListFromClient(c))
if err != nil {
return nil, nil, nil, err
}
@ -516,11 +538,11 @@ func GetAllReplicaSets(deployment *extensions.Deployment, c clientset.Interface)
// GetOldReplicaSets returns the old replica sets targeted by the given Deployment; get PodList and ReplicaSetList from client interface.
// Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets.
func GetOldReplicaSets(deployment *extensions.Deployment, c clientset.Interface) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, error) {
rsList, err := listReplicaSets(deployment, c)
rsList, err := ListReplicaSets(deployment, rsListFromClient(c))
if err != nil {
return nil, nil, err
}
podList, err := listPods(deployment, rsList, c)
podList, err := ListPods(deployment, rsList, podListFromClient(c))
if err != nil {
return nil, nil, err
}
@ -530,35 +552,43 @@ func GetOldReplicaSets(deployment *extensions.Deployment, c clientset.Interface)
// GetNewReplicaSet returns a replica set that matches the intent of the given deployment; get ReplicaSetList from client interface.
// Returns nil if the new replica set doesn't exist yet.
func GetNewReplicaSet(deployment *extensions.Deployment, c clientset.Interface) (*extensions.ReplicaSet, error) {
rsList, err := listReplicaSets(deployment, c)
rsList, err := ListReplicaSets(deployment, rsListFromClient(c))
if err != nil {
return nil, err
}
return FindNewReplicaSet(deployment, rsList)
}
// listReplicaSets lists all RSes the given deployment targets with the given client interface.
func listReplicaSets(deployment *extensions.Deployment, c clientset.Interface) ([]*extensions.ReplicaSet, error) {
return ListReplicaSets(deployment,
func(namespace string, options metav1.ListOptions) ([]*extensions.ReplicaSet, error) {
rsList, err := c.Extensions().ReplicaSets(namespace).List(options)
if err != nil {
return nil, err
}
ret := []*extensions.ReplicaSet{}
for i := range rsList.Items {
ret = append(ret, &rsList.Items[i])
}
return ret, err
})
// GetNewReplicaSetV15 is a compatibility function that behaves the way
// GetNewReplicaSet() used to in v1.5.x.
func GetNewReplicaSetV15(deployment *extensions.Deployment, c clientset.Interface) (*extensions.ReplicaSet, error) {
rsList, err := ListReplicaSetsV15(deployment, rsListFromClient(c))
if err != nil {
return nil, err
}
return FindNewReplicaSet(deployment, rsList)
}
// listReplicaSets lists all Pods the given deployment targets with the given client interface.
func listPods(deployment *extensions.Deployment, rsList []*extensions.ReplicaSet, c clientset.Interface) (*v1.PodList, error) {
return ListPods(deployment, rsList,
func(namespace string, options metav1.ListOptions) (*v1.PodList, error) {
return c.Core().Pods(namespace).List(options)
})
// rsListFromClient returns an rsListFunc that wraps the given client.
func rsListFromClient(c clientset.Interface) rsListFunc {
return func(namespace string, options metav1.ListOptions) ([]*extensions.ReplicaSet, error) {
rsList, err := c.Extensions().ReplicaSets(namespace).List(options)
if err != nil {
return nil, err
}
ret := []*extensions.ReplicaSet{}
for i := range rsList.Items {
ret = append(ret, &rsList.Items[i])
}
return ret, err
}
}
// podListFromClient returns a podListFunc that wraps the given client.
func podListFromClient(c clientset.Interface) podListFunc {
return func(namespace string, options metav1.ListOptions) (*v1.PodList, error) {
return c.Core().Pods(namespace).List(options)
}
}
// TODO: switch this to full namespacers
@ -593,6 +623,18 @@ func ListReplicaSets(deployment *extensions.Deployment, getRSList rsListFunc) ([
return owned, nil
}
// ListReplicaSetsV15 is a compatibility function that behaves the way
// ListReplicaSets() used to in v1.5.x.
func ListReplicaSetsV15(deployment *extensions.Deployment, getRSList rsListFunc) ([]*extensions.ReplicaSet, error) {
namespace := deployment.Namespace
selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
if err != nil {
return nil, err
}
options := metav1.ListOptions{LabelSelector: selector.String()}
return getRSList(namespace, options)
}
// ListReplicaSets returns a slice of RSes the given deployment targets.
// Note that this does NOT attempt to reconcile ControllerRef (adopt/orphan),
// because only the controller itself should do that.
@ -656,6 +698,18 @@ func ListPods(deployment *extensions.Deployment, rsList []*extensions.ReplicaSet
return owned, nil
}
// ListPodsV15 is a compatibility function that behaves the way
// ListPods() used to in v1.5.x.
func ListPodsV15(deployment *extensions.Deployment, getPodList podListFunc) (*v1.PodList, error) {
namespace := deployment.Namespace
selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
if err != nil {
return nil, err
}
options := metav1.ListOptions{LabelSelector: selector.String()}
return getPodList(namespace, options)
}
// EqualIgnoreHash returns true if two given podTemplateSpec are equal, ignoring the diff in value of Labels[pod-template-hash]
// We ignore pod-template-hash because the hash result would be different upon podTemplateSpec API changes
// (e.g. the addition of a new field will cause the hash code to change)

View File

@ -3141,6 +3141,16 @@ func NewDeployment(deploymentName string, replicas int32, podLabels map[string]s
// Note that the status should stay valid at all times unless shortly after a scaling event or the deployment is just created.
// To verify that the deployment status is valid and wait for the rollout to finish, use WaitForDeploymentStatus instead.
func WaitForDeploymentStatusValid(c clientset.Interface, d *extensions.Deployment) error {
return waitForDeploymentStatusValid(c, d, false)
}
// WaitForDeploymentStatusValidV15 is a compatibility function that behaves the
// way WaitForDeploymentStatusValid() did in v1.5.x.
func WaitForDeploymentStatusValidV15(c clientset.Interface, d *extensions.Deployment) error {
return waitForDeploymentStatusValid(c, d, true)
}
func waitForDeploymentStatusValid(c clientset.Interface, d *extensions.Deployment, v15Compatible bool) error {
var (
oldRSs, allOldRSs, allRSs []*extensions.ReplicaSet
newRS *extensions.ReplicaSet
@ -3154,7 +3164,11 @@ func WaitForDeploymentStatusValid(c clientset.Interface, d *extensions.Deploymen
if err != nil {
return false, err
}
oldRSs, allOldRSs, newRS, err = deploymentutil.GetAllReplicaSets(deployment, c)
if v15Compatible {
oldRSs, allOldRSs, newRS, err = deploymentutil.GetAllReplicaSetsV15(deployment, c)
} else {
oldRSs, allOldRSs, newRS, err = deploymentutil.GetAllReplicaSets(deployment, c)
}
if err != nil {
return false, err
}
@ -3200,7 +3214,7 @@ func WaitForDeploymentStatusValid(c clientset.Interface, d *extensions.Deploymen
if err == wait.ErrWaitTimeout {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS)
logPodsOfDeployment(c, deployment)
logPodsOfDeployment(c, deployment, allRSs, v15Compatible)
err = fmt.Errorf("%s", reason)
}
if err != nil {
@ -3212,6 +3226,16 @@ func WaitForDeploymentStatusValid(c clientset.Interface, d *extensions.Deploymen
// Waits for the deployment to reach desired state.
// Returns an error if the deployment's rolling update strategy (max unavailable or max surge) is broken at any times.
func WaitForDeploymentStatus(c clientset.Interface, d *extensions.Deployment) error {
return waitForDeploymentStatus(c, d, false)
}
// WaitForDeploymentStatusV15 is a compatibility function that behaves the way
// WaitForDeploymentStatus() did in v1.5.x.
func WaitForDeploymentStatusV15(c clientset.Interface, d *extensions.Deployment) error {
return waitForDeploymentStatus(c, d, true)
}
func waitForDeploymentStatus(c clientset.Interface, d *extensions.Deployment, v15Compatible bool) error {
var (
oldRSs, allOldRSs, allRSs []*extensions.ReplicaSet
newRS *extensions.ReplicaSet
@ -3224,7 +3248,11 @@ func WaitForDeploymentStatus(c clientset.Interface, d *extensions.Deployment) er
if err != nil {
return false, err
}
oldRSs, allOldRSs, newRS, err = deploymentutil.GetAllReplicaSets(deployment, c)
if v15Compatible {
oldRSs, allOldRSs, newRS, err = deploymentutil.GetAllReplicaSetsV15(deployment, c)
} else {
oldRSs, allOldRSs, newRS, err = deploymentutil.GetAllReplicaSets(deployment, c)
}
if err != nil {
return false, err
}
@ -3243,13 +3271,13 @@ func WaitForDeploymentStatus(c clientset.Interface, d *extensions.Deployment) er
maxCreated := *(deployment.Spec.Replicas) + deploymentutil.MaxSurge(*deployment)
if totalCreated > maxCreated {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS)
logPodsOfDeployment(c, deployment)
logPodsOfDeployment(c, deployment, allRSs, v15Compatible)
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)
logPodsOfDeployment(c, deployment, allRSs, v15Compatible)
return false, fmt.Errorf("total pods available: %d, less than the min required: %d", deployment.Status.AvailableReplicas, minAvailable)
}
@ -3259,7 +3287,7 @@ func WaitForDeploymentStatus(c clientset.Interface, d *extensions.Deployment) er
if err == wait.ErrWaitTimeout {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS)
logPodsOfDeployment(c, deployment)
logPodsOfDeployment(c, deployment, allRSs, v15Compatible)
}
if err != nil {
return fmt.Errorf("error waiting for deployment %q status to match expectation: %v", d.Name, err)
@ -3342,6 +3370,16 @@ func WatchRecreateDeployment(c clientset.Interface, d *extensions.Deployment) er
// WaitForDeploymentRevisionAndImage waits for the deployment's and its new RS's revision and container image to match the given revision and image.
// Note that deployment revision and its new RS revision should be updated shortly, so we only wait for 1 minute here to fail early.
func WaitForDeploymentRevisionAndImage(c clientset.Interface, ns, deploymentName string, revision, image string) error {
return waitForDeploymentRevisionAndImage(c, ns, deploymentName, revision, image, false)
}
// WaitForDeploymentRevisionAndImageV15 is a compatibility function that behaves
// the way WaitForDeploymentRevisionAndImage() did in v1.5.x.
func WaitForDeploymentRevisionAndImageV15(c clientset.Interface, ns, deploymentName string, revision, image string) error {
return waitForDeploymentRevisionAndImage(c, ns, deploymentName, revision, image, true)
}
func waitForDeploymentRevisionAndImage(c clientset.Interface, ns, deploymentName string, revision, image string, v15Compatible bool) error {
var deployment *extensions.Deployment
var newRS *extensions.ReplicaSet
var reason string
@ -3352,7 +3390,11 @@ func WaitForDeploymentRevisionAndImage(c clientset.Interface, ns, deploymentName
return false, err
}
// The new ReplicaSet needs to be non-nil and contain the pod-template-hash label
newRS, err = deploymentutil.GetNewReplicaSet(deployment, c)
if v15Compatible {
newRS, err = deploymentutil.GetNewReplicaSetV15(deployment, c)
} else {
newRS, err = deploymentutil.GetNewReplicaSet(deployment, c)
}
if err != nil {
return false, err
}
@ -3499,33 +3541,24 @@ func WaitForDeploymentWithCondition(c clientset.Interface, ns, deploymentName, r
_, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, c)
if err == nil {
logReplicaSetsOfDeployment(deployment, allOldRSs, newRS)
logPodsOfDeployment(c, deployment, append(allOldRSs, newRS), false)
}
logPodsOfDeployment(c, deployment)
}
return pollErr
}
func logPodsOfDeployment(c clientset.Interface, deployment *extensions.Deployment) {
func logPodsOfDeployment(c clientset.Interface, deployment *extensions.Deployment, rsList []*extensions.ReplicaSet, v15Compatible bool) {
minReadySeconds := deployment.Spec.MinReadySeconds
rsList, err := deploymentutil.ListReplicaSets(deployment,
func(namespace string, options metav1.ListOptions) ([]*extensions.ReplicaSet, error) {
rsList, err := c.Extensions().ReplicaSets(namespace).List(options)
if err != nil {
return nil, err
}
ret := make([]*extensions.ReplicaSet, 0, len(rsList.Items))
for i := range rsList.Items {
ret = append(ret, &rsList.Items[i])
}
return ret, nil
})
if err != nil {
Logf("Failed to list ReplicaSets of Deployment %s: %v", deployment.Name, err)
podListFunc := func(namespace string, options metav1.ListOptions) (*v1.PodList, error) {
return c.Core().Pods(namespace).List(options)
}
var podList *v1.PodList
var err error
if v15Compatible {
podList, err = deploymentutil.ListPodsV15(deployment, podListFunc)
} else {
podList, err = deploymentutil.ListPods(deployment, rsList, podListFunc)
}
podList, err := deploymentutil.ListPods(deployment, rsList,
func(namespace string, options metav1.ListOptions) (*v1.PodList, error) {
return c.Core().Pods(namespace).List(options)
})
if err != nil {
Logf("Failed to list Pods of Deployment %s: %v", deployment.Name, err)
return

View File

@ -56,13 +56,13 @@ func (t *DeploymentUpgradeTest) Setup(f *framework.Framework) {
// Wait for it to be updated to revision 1
By(fmt.Sprintf("Waiting deployment %q to be updated to revision 1", deploymentName))
err = framework.WaitForDeploymentRevisionAndImage(c, ns, deploymentName, "1", nginxImage)
err = framework.WaitForDeploymentRevisionAndImageV15(c, ns, deploymentName, "1", nginxImage)
framework.ExpectNoError(err)
By(fmt.Sprintf("Waiting deployment %q to complete", deploymentName))
framework.ExpectNoError(framework.WaitForDeploymentStatusValid(c, deployment))
framework.ExpectNoError(framework.WaitForDeploymentStatusValidV15(c, deployment))
rs, err := deploymentutil.GetNewReplicaSet(deployment, c)
rs, err := deploymentutil.GetNewReplicaSetV15(deployment, c)
framework.ExpectNoError(err)
if rs == nil {
framework.ExpectNoError(fmt.Errorf("expected a new replica set for deployment %q, found none", deployment.Name))
@ -84,12 +84,12 @@ func (t *DeploymentUpgradeTest) Setup(f *framework.Framework) {
// Wait for it to be updated to revision 2
By(fmt.Sprintf("Waiting deployment %q to be updated to revision 2", deploymentName))
framework.ExpectNoError(framework.WaitForDeploymentRevisionAndImage(c, ns, deploymentName, "2", nginxImage))
framework.ExpectNoError(framework.WaitForDeploymentRevisionAndImageV15(c, ns, deploymentName, "2", nginxImage))
By(fmt.Sprintf("Waiting deployment %q to complete", deploymentName))
framework.ExpectNoError(framework.WaitForDeploymentStatus(c, deployment))
framework.ExpectNoError(framework.WaitForDeploymentStatusV15(c, deployment))
rs, err = deploymentutil.GetNewReplicaSet(deployment, c)
rs, err = deploymentutil.GetNewReplicaSetV15(deployment, c)
framework.ExpectNoError(err)
if rs == nil {
framework.ExpectNoError(fmt.Errorf("expected a new replica set for deployment %q", deployment.Name))
@ -118,6 +118,9 @@ func (t *DeploymentUpgradeTest) Test(f *framework.Framework, done <-chan struct{
framework.ExpectNoError(err)
t.updatedD = deployment
By(fmt.Sprintf("Waiting for deployment %q to complete adoption", deployment.Name))
framework.ExpectNoError(framework.WaitForDeploymentStatus(c, deployment))
By(fmt.Sprintf("Checking that replica sets for deployment %q are the same as prior to the upgrade", t.updatedD.Name))
_, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(t.updatedD, c)
framework.ExpectNoError(err)