@@ -17,6 +17,10 @@ limitations under the License.
17
17
package status
18
18
19
19
import (
20
+ "fmt"
21
+ "sort"
22
+ "strings"
23
+
20
24
apiv1 "k8s.io/api/core/v1"
21
25
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
22
26
@@ -143,3 +147,230 @@ func UpdateScaleUpError(s *ScaleUpStatus, err errors.AutoscalerError) (*ScaleUpS
143
147
s .Result = ScaleUpError
144
148
return s , err
145
149
}
150
+
151
+
152
+ type combinedStatusSet struct {
153
+ Result ScaleUpResult
154
+ ScaleupErrors map [* errors.AutoscalerError ]bool
155
+ ScaleUpInfosSet map [nodegroupset.ScaleUpInfo ]bool
156
+ PodsTriggeredScaleUpSet map [* apiv1.Pod ]bool
157
+ PodsRemainUnschedulableSet map [* NoScaleUpInfo ]bool
158
+ PodsAwaitEvaluationSet map [* apiv1.Pod ]bool
159
+ CreateNodeGroupResultsSet map [* nodegroups.CreateNodeGroupResult ]bool
160
+ ConsideredNodeGroupsSet map [cloudprovider.NodeGroup ]bool
161
+ FailedCreationNodeGroupsSet map [cloudprovider.NodeGroup ]bool
162
+ FailedResizeNodeGroupsSet map [cloudprovider.NodeGroup ]bool
163
+ }
164
+
165
+ func (c * combinedStatusSet ) Add (status * ScaleUpStatus ) {
166
+ resultPriority := map [ScaleUpResult ]int {
167
+ ScaleUpNotTried : 0 ,
168
+ ScaleUpNotNeeded : 1 ,
169
+ ScaleUpNoOptionsAvailable : 2 ,
170
+ ScaleUpError : 3 ,
171
+ ScaleUpSuccessful : 4 ,
172
+ }
173
+
174
+ if resultPriority [c .Result ] < resultPriority [status .Result ] {
175
+ c .Result = status .Result
176
+ }
177
+ if status .ScaleUpError != nil {
178
+ if _ , found := c .ScaleupErrors [status .ScaleUpError ]; ! found {
179
+ c .ScaleupErrors [status .ScaleUpError ] = true
180
+ }
181
+ }
182
+ if status .ScaleUpInfos != nil {
183
+ for _ , scaleUpInfo := range status .ScaleUpInfos {
184
+ if _ , found := c .ScaleUpInfosSet [scaleUpInfo ]; ! found {
185
+ c .ScaleUpInfosSet [scaleUpInfo ] = true
186
+ }
187
+ }
188
+ }
189
+ if status .PodsTriggeredScaleUp != nil {
190
+ for _ , pod := range status .PodsTriggeredScaleUp {
191
+ if _ , found := c .PodsTriggeredScaleUpSet [pod ]; ! found {
192
+ c .PodsTriggeredScaleUpSet [pod ] = true
193
+ }
194
+ }
195
+ }
196
+ if status .PodsRemainUnschedulable != nil {
197
+ for _ , pod := range status .PodsRemainUnschedulable {
198
+ if _ , found := c .PodsRemainUnschedulableSet [& pod ]; ! found {
199
+ c .PodsRemainUnschedulableSet [& pod ] = true
200
+ }
201
+ }
202
+ }
203
+ if status .PodsAwaitEvaluation != nil {
204
+ for _ , pod := range status .PodsAwaitEvaluation {
205
+ if _ , found := c .PodsAwaitEvaluationSet [pod ]; ! found {
206
+ c .PodsAwaitEvaluationSet [pod ] = true
207
+ }
208
+ }
209
+ }
210
+ if status .CreateNodeGroupResults != nil {
211
+ for _ , createNodeGroupResult := range status .CreateNodeGroupResults {
212
+ if _ , found := c .CreateNodeGroupResultsSet [& createNodeGroupResult ]; ! found {
213
+ c .CreateNodeGroupResultsSet [& createNodeGroupResult ] = true
214
+ }
215
+ }
216
+ }
217
+ if status .ConsideredNodeGroups != nil {
218
+ for _ , nodeGroup := range status .ConsideredNodeGroups {
219
+ if _ , found := c .ConsideredNodeGroupsSet [nodeGroup ]; ! found {
220
+ c .ConsideredNodeGroupsSet [nodeGroup ] = true
221
+ }
222
+ }
223
+ }
224
+ if status .FailedCreationNodeGroups != nil {
225
+ for _ , nodeGroup := range status .FailedCreationNodeGroups {
226
+ if _ , found := c .FailedCreationNodeGroupsSet [nodeGroup ]; ! found {
227
+ c .FailedCreationNodeGroupsSet [nodeGroup ] = true
228
+ }
229
+ }
230
+ }
231
+ if status .FailedResizeNodeGroups != nil {
232
+ for _ , nodeGroup := range status .FailedResizeNodeGroups {
233
+ if _ , found := c .FailedResizeNodeGroupsSet [nodeGroup ]; ! found {
234
+ c .FailedResizeNodeGroupsSet [nodeGroup ] = true
235
+ }
236
+ }
237
+ }
238
+ }
239
+
240
+ func (c * combinedStatusSet ) formatMessageFromBatchErrors (errs []errors.AutoscalerError , printErrorTypes bool ) string {
241
+ firstErr := errs [0 ]
242
+ var builder strings.Builder
243
+ builder .WriteString (firstErr .Error ())
244
+ builder .WriteString (" ...and other concurrent errors: [" )
245
+ formattedErrs := map [errors.AutoscalerError ]bool {
246
+ firstErr : true ,
247
+ }
248
+ for _ , err := range errs {
249
+ if _ , has := formattedErrs [err ]; has {
250
+ continue
251
+ }
252
+ formattedErrs [err ] = true
253
+ var message string
254
+ if printErrorTypes {
255
+ message = fmt .Sprintf ("[%s] %s" , err .Type (), err .Error ())
256
+ } else {
257
+ message = err .Error ()
258
+ }
259
+ if len (formattedErrs ) > 2 {
260
+ builder .WriteString (", " )
261
+ }
262
+ builder .WriteString (fmt .Sprintf ("%q" , message ))
263
+ }
264
+ builder .WriteString ("]" )
265
+ return builder .String ()
266
+ }
267
+
268
+ func (c * combinedStatusSet ) combineBatchScaleUpErrors () * errors.AutoscalerError {
269
+ if len (c .ScaleupErrors ) == 0 {
270
+ return nil
271
+ }
272
+ if len (c .ScaleupErrors ) == 1 {
273
+ for err := range c .ScaleupErrors {
274
+ return err
275
+ }
276
+ }
277
+ uniqueMessages := make (map [string ]bool )
278
+ uniqueTypes := make (map [errors.AutoscalerErrorType ]bool )
279
+ for err := range c .ScaleupErrors {
280
+ uniqueTypes [(* err ).Type ()] = true
281
+ uniqueMessages [(* err ).Error ()] = true
282
+ }
283
+ if len (uniqueTypes ) == 1 && len (uniqueMessages ) == 1 {
284
+ for err := range c .ScaleupErrors {
285
+ return err
286
+ }
287
+ }
288
+ // sort to stabilize the results and easier log aggregation
289
+ errs := make ([]errors.AutoscalerError , 0 , len (c .ScaleupErrors ))
290
+ for err := range c .ScaleupErrors {
291
+ errs = append (errs , * err )
292
+ }
293
+ sort .Slice (errs , func (i , j int ) bool {
294
+ errA := errs [i ]
295
+ errB := errs [j ]
296
+ if errA .Type () == errB .Type () {
297
+ return errs [i ].Error () < errs [j ].Error ()
298
+ }
299
+ return errA .Type () < errB .Type ()
300
+ })
301
+ firstErr := errs [0 ]
302
+ printErrorTypes := len (uniqueTypes ) > 1
303
+ message := c .formatMessageFromBatchErrors (errs , printErrorTypes )
304
+ combinedErr := errors .NewAutoscalerError (firstErr .Type (), message )
305
+ return & combinedErr
306
+ }
307
+
308
+ func (c * combinedStatusSet ) Export () (* ScaleUpStatus , errors.AutoscalerError ) {
309
+ result := & ScaleUpStatus {Result : c .Result }
310
+ if len (c .ScaleupErrors ) > 0 {
311
+ result .ScaleUpError = c .combineBatchScaleUpErrors ()
312
+ }
313
+ if len (c .ScaleUpInfosSet ) > 0 {
314
+ for scaleUpInfo := range c .ScaleUpInfosSet {
315
+ result .ScaleUpInfos = append (result .ScaleUpInfos , scaleUpInfo )
316
+ }
317
+ }
318
+ if len (c .PodsTriggeredScaleUpSet ) > 0 {
319
+ for pod := range c .PodsTriggeredScaleUpSet {
320
+ result .PodsTriggeredScaleUp = append (result .PodsTriggeredScaleUp , pod )
321
+ }
322
+ }
323
+ if len (c .PodsRemainUnschedulableSet ) > 0 {
324
+ for pod := range c .PodsRemainUnschedulableSet {
325
+ result .PodsRemainUnschedulable = append (result .PodsRemainUnschedulable , * pod )
326
+ }
327
+ }
328
+ if len (c .PodsAwaitEvaluationSet ) > 0 {
329
+ for pod := range c .PodsAwaitEvaluationSet {
330
+ result .PodsAwaitEvaluation = append (result .PodsAwaitEvaluation , pod )
331
+ }
332
+ }
333
+ if len (c .CreateNodeGroupResultsSet ) > 0 {
334
+ for createNodeGroupResult := range c .CreateNodeGroupResultsSet {
335
+ result .CreateNodeGroupResults = append (result .CreateNodeGroupResults , * createNodeGroupResult )
336
+ }
337
+ }
338
+ if len (c .ConsideredNodeGroupsSet ) > 0 {
339
+ for nodeGroup := range c .ConsideredNodeGroupsSet {
340
+ result .ConsideredNodeGroups = append (result .ConsideredNodeGroups , nodeGroup )
341
+ }
342
+ }
343
+ if len (c .FailedCreationNodeGroupsSet ) > 0 {
344
+ for nodeGroup := range c .FailedCreationNodeGroupsSet {
345
+ result .FailedCreationNodeGroups = append (result .FailedCreationNodeGroups , nodeGroup )
346
+ }
347
+ }
348
+ if len (c .FailedResizeNodeGroupsSet ) > 0 {
349
+ for nodeGroup := range c .FailedResizeNodeGroupsSet {
350
+ result .FailedResizeNodeGroups = append (result .FailedResizeNodeGroups , nodeGroup )
351
+ }
352
+ }
353
+
354
+ var resErr errors.AutoscalerError
355
+
356
+ if result .Result == ScaleUpError {
357
+ resErr = * result .ScaleUpError
358
+ }
359
+
360
+ return result , resErr
361
+ }
362
+
363
+ func NewCombinedStatusSet () combinedStatusSet {
364
+ return combinedStatusSet {
365
+ Result : ScaleUpNotTried ,
366
+ ScaleupErrors : make (map [* errors.AutoscalerError ]bool ),
367
+ ScaleUpInfosSet : make (map [nodegroupset.ScaleUpInfo ]bool ),
368
+ PodsTriggeredScaleUpSet : make (map [* apiv1.Pod ]bool ),
369
+ PodsRemainUnschedulableSet : make (map [* NoScaleUpInfo ]bool ),
370
+ PodsAwaitEvaluationSet : make (map [* apiv1.Pod ]bool ),
371
+ CreateNodeGroupResultsSet : make (map [* nodegroups.CreateNodeGroupResult ]bool ),
372
+ ConsideredNodeGroupsSet : make (map [cloudprovider.NodeGroup ]bool ),
373
+ FailedCreationNodeGroupsSet : make (map [cloudprovider.NodeGroup ]bool ),
374
+ FailedResizeNodeGroupsSet : make (map [cloudprovider.NodeGroup ]bool ),
375
+ }
376
+ }
0 commit comments