1
16
17 package deployment
18
19 import (
20 "context"
21 "fmt"
22 "strconv"
23
24 apps "k8s.io/api/apps/v1"
25 v1 "k8s.io/api/core/v1"
26 extensions "k8s.io/api/extensions/v1beta1"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/klog/v2"
29 deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
30 )
31
32
33 func (dc *DeploymentController) rollback(ctx context.Context, d *apps.Deployment, rsList []*apps.ReplicaSet) error {
34 logger := klog.FromContext(ctx)
35 newRS, allOldRSs, err := dc.getAllReplicaSetsAndSyncRevision(ctx, d, rsList, true)
36 if err != nil {
37 return err
38 }
39
40 allRSs := append(allOldRSs, newRS)
41 rollbackTo := getRollbackTo(d)
42
43 if rollbackTo.Revision == 0 {
44 if rollbackTo.Revision = deploymentutil.LastRevision(logger, allRSs); rollbackTo.Revision == 0 {
45
46 dc.emitRollbackWarningEvent(d, deploymentutil.RollbackRevisionNotFound, "Unable to find last revision.")
47
48 return dc.updateDeploymentAndClearRollbackTo(ctx, d)
49 }
50 }
51 for _, rs := range allRSs {
52 v, err := deploymentutil.Revision(rs)
53 if err != nil {
54 logger.V(4).Info("Unable to extract revision from deployment's replica set", "replicaSet", klog.KObj(rs), "err", err)
55 continue
56 }
57 if v == rollbackTo.Revision {
58 logger.V(4).Info("Found replica set with desired revision", "replicaSet", klog.KObj(rs), "revision", v)
59
60
61
62 performedRollback, err := dc.rollbackToTemplate(ctx, d, rs)
63 if performedRollback && err == nil {
64 dc.emitRollbackNormalEvent(d, fmt.Sprintf("Rolled back deployment %q to revision %d", d.Name, rollbackTo.Revision))
65 }
66 return err
67 }
68 }
69 dc.emitRollbackWarningEvent(d, deploymentutil.RollbackRevisionNotFound, "Unable to find the revision to rollback to.")
70
71 return dc.updateDeploymentAndClearRollbackTo(ctx, d)
72 }
73
74
75
76
77 func (dc *DeploymentController) rollbackToTemplate(ctx context.Context, d *apps.Deployment, rs *apps.ReplicaSet) (bool, error) {
78 logger := klog.FromContext(ctx)
79 performedRollback := false
80 if !deploymentutil.EqualIgnoreHash(&d.Spec.Template, &rs.Spec.Template) {
81 logger.V(4).Info("Rolling back deployment to old template spec", "deployment", klog.KObj(d), "templateSpec", rs.Spec.Template.Spec)
82 deploymentutil.SetFromReplicaSetTemplate(d, rs.Spec.Template)
83
84
85
86
87
88
89
90
91
92
93
94 deploymentutil.SetDeploymentAnnotationsTo(d, rs)
95 performedRollback = true
96 } else {
97 logger.V(4).Info("Rolling back to a revision that contains the same template as current deployment, skipping rollback...", "deployment", klog.KObj(d))
98 eventMsg := fmt.Sprintf("The rollback revision contains the same template as current deployment %q", d.Name)
99 dc.emitRollbackWarningEvent(d, deploymentutil.RollbackTemplateUnchanged, eventMsg)
100 }
101
102 return performedRollback, dc.updateDeploymentAndClearRollbackTo(ctx, d)
103 }
104
105 func (dc *DeploymentController) emitRollbackWarningEvent(d *apps.Deployment, reason, message string) {
106 dc.eventRecorder.Eventf(d, v1.EventTypeWarning, reason, message)
107 }
108
109 func (dc *DeploymentController) emitRollbackNormalEvent(d *apps.Deployment, message string) {
110 dc.eventRecorder.Eventf(d, v1.EventTypeNormal, deploymentutil.RollbackDone, message)
111 }
112
113
114
115
116 func (dc *DeploymentController) updateDeploymentAndClearRollbackTo(ctx context.Context, d *apps.Deployment) error {
117 logger := klog.FromContext(ctx)
118 logger.V(4).Info("Cleans up rollbackTo of deployment", "deployment", klog.KObj(d))
119 setRollbackTo(d, nil)
120 _, err := dc.client.AppsV1().Deployments(d.Namespace).Update(ctx, d, metav1.UpdateOptions{})
121 return err
122 }
123
124
125 func getRollbackTo(d *apps.Deployment) *extensions.RollbackConfig {
126
127 revision := d.Annotations[apps.DeprecatedRollbackTo]
128 if revision == "" {
129 return nil
130 }
131 revision64, err := strconv.ParseInt(revision, 10, 64)
132 if err != nil {
133
134 return nil
135 }
136 return &extensions.RollbackConfig{
137 Revision: revision64,
138 }
139 }
140
141
142 func setRollbackTo(d *apps.Deployment, rollbackTo *extensions.RollbackConfig) {
143 if rollbackTo == nil {
144 delete(d.Annotations, apps.DeprecatedRollbackTo)
145 return
146 }
147 if d.Annotations == nil {
148 d.Annotations = make(map[string]string)
149 }
150 d.Annotations[apps.DeprecatedRollbackTo] = strconv.FormatInt(rollbackTo.Revision, 10)
151 }
152
View as plain text