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