Skip to content

Commit 519472c

Browse files
myname4423Funinu
andauthored
Allow deployment rollback when in the process of cannary/partition (#91)
add comment an improvement for canary rollback during another rollback Signed-off-by: yunbo <yunbo10124scut@gmail.com> Co-authored-by: yunbo <yunbo10124scut@gmail.com>
1 parent ce1b663 commit 519472c

File tree

2 files changed

+86
-6
lines changed

2 files changed

+86
-6
lines changed

pkg/internal/polymorphichelpers/rollback.go

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
kruiseclientsets "github.com/openkruise/kruise-api/client/clientset/versioned"
2929
internalapps "github.com/openkruise/kruise-tools/pkg/internal/apps"
3030

31+
utils "github.com/openkruise/kruise-tools/pkg/utils"
3132
appsv1 "k8s.io/api/apps/v1"
3233
corev1 "k8s.io/api/core/v1"
3334
apiequality "k8s.io/apimachinery/pkg/api/equality"
@@ -143,9 +144,6 @@ func (r *DeploymentRollbacker) Rollback(obj runtime.Object, updatedAnnotations m
143144
if dryRunStrategy == cmdutil.DryRunClient {
144145
return printTemplate(&rsForRevision.Spec.Template)
145146
}
146-
if deployment.Spec.Paused {
147-
return "", fmt.Errorf("you cannot rollback a paused deployment; resume it first with 'kubectl rollout resume deployment/%s' and try again", name)
148-
}
149147

150148
// Skip if the revision already matches current Deployment
151149
if equalIgnoreHash(&rsForRevision.Spec.Template, &deployment.Spec.Template) {
@@ -157,13 +155,18 @@ func (r *DeploymentRollbacker) Rollback(obj runtime.Object, updatedAnnotations m
157155

158156
// compute deployment annotations
159157
annotations := map[string]string{}
160-
for k := range annotationsToSkip {
161-
if v, ok := deployment.Annotations[k]; ok {
158+
159+
// In the same vein as annotationsToSkip, which records annotations to exclude,
160+
// IsKruiseRolloutsAnnotation checks whether an annotation is generated by kruise-rollout.
161+
// Annotations identified as generated by kruise-rollout
162+
// will be skipped when copying from ReplicaSet annotations to Deployment annotations.
163+
for k, v := range deployment.Annotations {
164+
if annotationsToSkip[k] || utils.IsKruiseRolloutsAnnotation(&k) {
162165
annotations[k] = v
163166
}
164167
}
165168
for k, v := range rsForRevision.Annotations {
166-
if !annotationsToSkip[k] {
169+
if !annotationsToSkip[k] && !utils.IsKruiseRolloutsAnnotation(&k) {
167170
annotations[k] = v
168171
}
169172
}
@@ -270,6 +273,50 @@ func deploymentRevision(deployment *appsv1.Deployment, c kubernetes.Interface, t
270273
return nil, revisionNotFoundErr(toRevision)
271274
}
272275

276+
// even a deployment is paused, rollout history can update if the current rollout progress is
277+
// actually a rollback, for example:
278+
279+
// Step1. Initially, there's only one revision for the deployment:
280+
// REVISION CHANGE-CAUSE
281+
// 1 <none>
282+
// before the first canary release is completed, the rollout history won't update since the original deployment
283+
// is paused. If someone decides to rollback during this release (before it is completed),
284+
// we should return the latestReplicaSet instead of the previousReplicaSet.
285+
286+
// Step2. After a canary release completed, the rollout history will be like:
287+
// REVISION CHANGE-CAUSE
288+
// 1 <none>
289+
// 2 <none>
290+
291+
// Step3. Someone decides to rollback after this release using rollout undo.
292+
// It is ok, and it will be seen as a new canary release.
293+
// However, the rollout history will update though the original deployment is paused, because
294+
// the "new" canary revision can be found from the rollout history, which will be like:
295+
// REVISION CHANGE-CAUSE
296+
// 2 <none>
297+
// 3 <none>
298+
299+
// Step4. Someone decides to rollback during this rollback progress (before it is completed),
300+
// that means rolling back to the revision referred in the Step2.
301+
// We should return the previousReplicaSet instead of the latestReplicaSet.
302+
if utils.InCanaryProgress(deployment) {
303+
if latestReplicaSet == nil {
304+
return nil, fmt.Errorf("no rollout history found for deployment %q", deployment.Name)
305+
}
306+
// only one revison found, then return it, equalIgnoreHash will be called later in Rollback function
307+
if previousReplicaSet == nil {
308+
return latestReplicaSet, nil
309+
}
310+
// possibly attempting to rollback during a rollback progress, so we return previousReplicaSet,
311+
// since the rollout history is updated
312+
if equalIgnoreHash(&latestReplicaSet.Spec.Template, &deployment.Spec.Template) {
313+
return previousReplicaSet, nil
314+
}
315+
// attempting to rollback during a normal publication,
316+
// so we return latestReplicaSet since the rollout history hasn't updated
317+
return latestReplicaSet, nil
318+
}
319+
273320
if previousReplicaSet == nil {
274321
return nil, fmt.Errorf("no rollout history found for deployment %q", deployment.Name)
275322
}

pkg/utils/misc.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package utils
2+
3+
import (
4+
"strings"
5+
6+
appsv1 "k8s.io/api/apps/v1"
7+
)
8+
9+
const InRolloutProgressingAnnotation = "rollouts.kruise.io/in-progressing"
10+
const DeploymentStrategyAnnotation = "rollouts.kruise.io/deployment-strategy"
11+
12+
func IsKruiseRolloutsAnnotation(s *string) bool {
13+
if s == nil {
14+
return false
15+
}
16+
const prefix = "rollouts.kruise.io/"
17+
return strings.Contains(*s, prefix)
18+
}
19+
20+
func InCanaryProgress(deployment *appsv1.Deployment) bool {
21+
if !deployment.Spec.Paused {
22+
return false
23+
}
24+
//if deployment has InRolloutProgressingAnnotation, it is under kruise-rollout control
25+
if _, ok := deployment.Annotations[InRolloutProgressingAnnotation]; !ok {
26+
return false
27+
}
28+
// only if deployment strategy is 'partition', webhook would add DeploymentStrategyAnnotation
29+
if _, ok := deployment.Annotations[DeploymentStrategyAnnotation]; ok {
30+
return false
31+
}
32+
return true
33+
}

0 commit comments

Comments
 (0)