1
16
17 package deployment
18
19 import (
20 "context"
21 "fmt"
22 "reflect"
23 "time"
24
25 apps "k8s.io/api/apps/v1"
26 "k8s.io/api/core/v1"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/klog/v2"
29 "k8s.io/kubernetes/pkg/controller/deployment/util"
30 )
31
32
33
34
35
36 func (dc *DeploymentController) syncRolloutStatus(ctx context.Context, allRSs []*apps.ReplicaSet, newRS *apps.ReplicaSet, d *apps.Deployment) error {
37 newStatus := calculateStatus(allRSs, newRS, d)
38
39
40 if !util.HasProgressDeadline(d) {
41 util.RemoveDeploymentCondition(&newStatus, apps.DeploymentProgressing)
42 }
43
44
45
46
47 currentCond := util.GetDeploymentCondition(d.Status, apps.DeploymentProgressing)
48 isCompleteDeployment := newStatus.Replicas == newStatus.UpdatedReplicas && currentCond != nil && currentCond.Reason == util.NewRSAvailableReason
49
50
51 if util.HasProgressDeadline(d) && !isCompleteDeployment {
52 switch {
53 case util.DeploymentComplete(d, &newStatus):
54
55
56 msg := fmt.Sprintf("Deployment %q has successfully progressed.", d.Name)
57 if newRS != nil {
58 msg = fmt.Sprintf("ReplicaSet %q has successfully progressed.", newRS.Name)
59 }
60 condition := util.NewDeploymentCondition(apps.DeploymentProgressing, v1.ConditionTrue, util.NewRSAvailableReason, msg)
61 util.SetDeploymentCondition(&newStatus, *condition)
62
63 case util.DeploymentProgressing(d, &newStatus):
64
65
66 msg := fmt.Sprintf("Deployment %q is progressing.", d.Name)
67 if newRS != nil {
68 msg = fmt.Sprintf("ReplicaSet %q is progressing.", newRS.Name)
69 }
70 condition := util.NewDeploymentCondition(apps.DeploymentProgressing, v1.ConditionTrue, util.ReplicaSetUpdatedReason, msg)
71
72
73
74
75
76
77
78 if currentCond != nil {
79 if currentCond.Status == v1.ConditionTrue {
80 condition.LastTransitionTime = currentCond.LastTransitionTime
81 }
82 util.RemoveDeploymentCondition(&newStatus, apps.DeploymentProgressing)
83 }
84 util.SetDeploymentCondition(&newStatus, *condition)
85
86 case util.DeploymentTimedOut(ctx, d, &newStatus):
87
88
89 msg := fmt.Sprintf("Deployment %q has timed out progressing.", d.Name)
90 if newRS != nil {
91 msg = fmt.Sprintf("ReplicaSet %q has timed out progressing.", newRS.Name)
92 }
93 condition := util.NewDeploymentCondition(apps.DeploymentProgressing, v1.ConditionFalse, util.TimedOutReason, msg)
94 util.SetDeploymentCondition(&newStatus, *condition)
95 }
96 }
97
98
99
100 if replicaFailureCond := dc.getReplicaFailures(allRSs, newRS); len(replicaFailureCond) > 0 {
101
102 util.SetDeploymentCondition(&newStatus, replicaFailureCond[0])
103 } else {
104 util.RemoveDeploymentCondition(&newStatus, apps.DeploymentReplicaFailure)
105 }
106
107
108 if reflect.DeepEqual(d.Status, newStatus) {
109
110 dc.requeueStuckDeployment(ctx, d, newStatus)
111 return nil
112 }
113
114 newDeployment := d
115 newDeployment.Status = newStatus
116 _, err := dc.client.AppsV1().Deployments(newDeployment.Namespace).UpdateStatus(ctx, newDeployment, metav1.UpdateOptions{})
117 return err
118 }
119
120
121
122 func (dc *DeploymentController) getReplicaFailures(allRSs []*apps.ReplicaSet, newRS *apps.ReplicaSet) []apps.DeploymentCondition {
123 var conditions []apps.DeploymentCondition
124 if newRS != nil {
125 for _, c := range newRS.Status.Conditions {
126 if c.Type != apps.ReplicaSetReplicaFailure {
127 continue
128 }
129 conditions = append(conditions, util.ReplicaSetToDeploymentCondition(c))
130 }
131 }
132
133
134 if len(conditions) > 0 {
135 return conditions
136 }
137
138 for i := range allRSs {
139 rs := allRSs[i]
140 if rs == nil {
141 continue
142 }
143
144 for _, c := range rs.Status.Conditions {
145 if c.Type != apps.ReplicaSetReplicaFailure {
146 continue
147 }
148 conditions = append(conditions, util.ReplicaSetToDeploymentCondition(c))
149 }
150 }
151 return conditions
152 }
153
154
155 var nowFn = func() time.Time { return time.Now() }
156
157
158
159
160 func (dc *DeploymentController) requeueStuckDeployment(ctx context.Context, d *apps.Deployment, newStatus apps.DeploymentStatus) time.Duration {
161 logger := klog.FromContext(ctx)
162 currentCond := util.GetDeploymentCondition(d.Status, apps.DeploymentProgressing)
163
164 if !util.HasProgressDeadline(d) || currentCond == nil {
165 return time.Duration(-1)
166 }
167
168 if util.DeploymentComplete(d, &newStatus) || currentCond.Reason == util.TimedOutReason {
169 return time.Duration(-1)
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186 after := currentCond.LastUpdateTime.Time.Add(time.Duration(*d.Spec.ProgressDeadlineSeconds) * time.Second).Sub(nowFn())
187
188
189
190 if after < time.Second {
191 logger.V(4).Info("Queueing up deployment for a progress check now", "deployment", klog.KObj(d))
192 dc.enqueueRateLimited(d)
193 return time.Duration(0)
194 }
195 logger.V(4).Info("Queueing up deployment for a progress check", "deployment", klog.KObj(d), "queueAfter", int(after.Seconds()))
196
197
198 dc.enqueueAfter(d, after+time.Second)
199 return after
200 }
201
View as plain text