@@ -175,44 +175,93 @@ func CalculateReplicaCountsForCanary(rollout *v1alpha1.Rollout, newRS *appsv1.Re
175
175
}
176
176
177
177
minAvailableReplicaCount := rolloutSpecReplica - MaxUnavailable (rollout )
178
+
178
179
// isIncreasing indicates if we are supposed to be increasing our canary replica count.
179
180
// If so, we can ignore pod availability of the stableRS. Otherwise, if we are reducing our
180
181
// weight (e.g. we are aborting), then we can ignore pod availability of the canaryRS.
181
182
isIncreasing := newRS == nil || desiredNewRSReplicaCount >= * newRS .Spec .Replicas
182
183
replicasToScaleDown := GetReplicasForScaleDown (newRS , ! isIncreasing ) + GetReplicasForScaleDown (stableRS , isIncreasing )
183
-
184
184
if replicasToScaleDown <= minAvailableReplicaCount {
185
185
// Cannot scale down stableRS or newRS without going below min available replica count
186
186
return newRSReplicaCount , stableRSReplicaCount
187
187
}
188
188
189
189
scaleDownCount := replicasToScaleDown - minAvailableReplicaCount
190
190
191
- if newRS != nil && * newRS .Spec .Replicas > desiredNewRSReplicaCount {
192
- // if the controller doesn't have to use every replica to achieve the desired count, it only scales down to the
193
- // desired count.
194
- if * newRS .Spec .Replicas - scaleDownCount < desiredNewRSReplicaCount {
195
- newRSReplicaCount = desiredNewRSReplicaCount
196
- // Calculating how many replicas were used to scale down to the desired count
197
- scaleDownCount = scaleDownCount - (* newRS .Spec .Replicas - desiredNewRSReplicaCount )
198
- } else {
199
- // The controller is using every replica it can to get closer to desired state.
200
- newRSReplicaCount = * newRS .Spec .Replicas - scaleDownCount
201
- scaleDownCount = 0
202
- }
191
+ if ! isIncreasing {
192
+ // Skip scalingDown Stable replicaSet when Canary availability is not taken into calculation for scaleDown
193
+ newRSReplicaCount = calculateScaleDownReplicaCount (newRS , desiredNewRSReplicaCount , scaleDownCount , newRSReplicaCount )
194
+ newRSReplicaCount , stableRSReplicaCount = adjustReplicaWithinLimits (newRS , stableRS , newRSReplicaCount , stableRSReplicaCount , maxReplicaCountAllowed , minAvailableReplicaCount )
195
+ } else {
196
+ // Skip scalingDown canary replicaSet when StableSet availability is not taken into calculation for scaleDown
197
+ stableRSReplicaCount = calculateScaleDownReplicaCount (stableRS , desiredStableRSReplicaCount , scaleDownCount , stableRSReplicaCount )
198
+ stableRSReplicaCount , newRSReplicaCount = adjustReplicaWithinLimits (stableRS , newRS , stableRSReplicaCount , newRSReplicaCount , maxReplicaCountAllowed , minAvailableReplicaCount )
203
199
}
200
+ return newRSReplicaCount , stableRSReplicaCount
201
+ }
204
202
205
- if scaleStableRS && * stableRS . Spec . Replicas > desiredStableRSReplicaCount {
206
- // This follows the same logic as scaling down the newRS except with the stableRS and it does not need to
207
- // set the scaleDownCount again since it's not used again
208
- if * stableRS . Spec . Replicas - scaleDownCount < desiredStableRSReplicaCount {
209
- stableRSReplicaCount = desiredStableRSReplicaCount
210
- } else {
211
- stableRSReplicaCount = * stableRS . Spec . Replicas - scaleDownCount
212
- }
203
+ // calculateScaleDownReplicaCount calculates drainRSReplicaCount
204
+ // drainRSReplicaCount can be either stableRS count or canaryRS count
205
+ // drainRSReplicaCount corresponds to RS whose availability is not considered in calculating replicasToScaleDown
206
+ func calculateScaleDownReplicaCount ( drainRS * appsv1. ReplicaSet , desireRSReplicaCount int32 , scaleDownCount int32 , drainRSReplicaCount int32 ) int32 {
207
+ if drainRS != nil && * drainRS . Spec . Replicas > desireRSReplicaCount {
208
+ // if the controller doesn't have to use every replica to achieve the desired count,
209
+ // it can scales down to the desired count or get closer to desired state.
210
+ drainRSReplicaCount = maxValue ( desireRSReplicaCount , * drainRS . Spec . Replicas - scaleDownCount )
213
211
}
212
+ return drainRSReplicaCount
213
+ }
214
214
215
- return newRSReplicaCount , stableRSReplicaCount
215
+ // adjustReplicaWithinLimits adjusts replicaCounters to be within maxSurge & maxUnavailable limits
216
+ // drainRSReplicaCount corresponds to RS whose availability is not considered in calculating replicasToScaleDown
217
+ // adjustRSReplicaCount corresponds to RS whose availability is to taken account while adjusting maxUnavailable limit
218
+ func adjustReplicaWithinLimits (drainRS * appsv1.ReplicaSet , adjustRS * appsv1.ReplicaSet , drainRSReplicaCount int32 , adjustRSReplicaCount int32 , maxReplicaCountAllowed int32 , minAvailableReplicaCount int32 ) (int32 , int32 ) {
219
+ extraAvailableAdjustRS := int32 (0 )
220
+ totalAvailableReplicas := int32 (0 )
221
+ // calculates current limit over the allowed value
222
+ overTheLimitVal := maxValue (0 , adjustRSReplicaCount + drainRSReplicaCount - maxReplicaCountAllowed )
223
+ if drainRS != nil {
224
+ totalAvailableReplicas = totalAvailableReplicas + minValue (drainRS .Status .AvailableReplicas , drainRSReplicaCount )
225
+ }
226
+ if adjustRS != nil {
227
+ // 1. adjust adjustRSReplicaCount to be within maxSurge
228
+ adjustRSReplicaCount = adjustRSReplicaCount - overTheLimitVal
229
+ // 2. Calculate availability corresponding to adjusted count
230
+ totalAvailableReplicas = totalAvailableReplicas + minValue (adjustRS .Status .AvailableReplicas , adjustRSReplicaCount )
231
+ // 3. Calculate decrease in availability of adjustRS because of (1)
232
+ extraAvailableAdjustRS = maxValue (0 , adjustRS .Status .AvailableReplicas - adjustRSReplicaCount )
233
+
234
+ // 4. Now calculate how far count is from maxUnavailable limit
235
+ moreToNeedAvailableReplicas := maxValue (0 , minAvailableReplicaCount - totalAvailableReplicas )
236
+ // 5. From (3), we got the count for decrease in availability because of (1),
237
+ // take the min of (3) & (4) and add it back to adjustRS
238
+ // remaining of moreToNeedAvailableReplicas can be ignored as it is part of drainRS,
239
+ // there is no case of deviating from maxUnavailable limit from drainRS as in the event of said case,
240
+ // scaleDown calculation wont even occur as we are checking
241
+ // replicasToScaleDown <= minAvailableReplicaCount in caller function
242
+ adjustRSReplicaCount = adjustRSReplicaCount + minValue (extraAvailableAdjustRS , moreToNeedAvailableReplicas )
243
+ // 6. Calculate final overTheLimit because of adjustment
244
+ overTheLimitVal = maxValue (0 , adjustRSReplicaCount + drainRSReplicaCount - maxReplicaCountAllowed )
245
+ // 7. we can safely subtract from drainRS and other cases like deviation from maxUnavailable limit
246
+ // wont occur as said in (5)
247
+ drainRSReplicaCount = drainRSReplicaCount - overTheLimitVal
248
+ }
249
+
250
+ return drainRSReplicaCount , adjustRSReplicaCount
251
+ }
252
+
253
+ func minValue (countA int32 , countB int32 ) int32 {
254
+ if countA > countB {
255
+ return countB
256
+ }
257
+ return countA
258
+ }
259
+
260
+ func maxValue (countA int32 , countB int32 ) int32 {
261
+ if countA < countB {
262
+ return countB
263
+ }
264
+ return countA
216
265
}
217
266
218
267
// BeforeStartingStep checks if canary rollout is at the starting step
0 commit comments