1
16
17 package util
18
19 import (
20 "context"
21 "fmt"
22 "math"
23 "sort"
24 "strconv"
25 "strings"
26 "time"
27
28 apps "k8s.io/api/apps/v1"
29 v1 "k8s.io/api/core/v1"
30 apiequality "k8s.io/apimachinery/pkg/api/equality"
31 "k8s.io/apimachinery/pkg/api/meta"
32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33 "k8s.io/apimachinery/pkg/labels"
34 "k8s.io/apimachinery/pkg/runtime"
35 "k8s.io/apimachinery/pkg/types"
36 intstrutil "k8s.io/apimachinery/pkg/util/intstr"
37 "k8s.io/apimachinery/pkg/util/wait"
38 appsclient "k8s.io/client-go/kubernetes/typed/apps/v1"
39 appslisters "k8s.io/client-go/listers/apps/v1"
40 "k8s.io/klog/v2"
41 "k8s.io/kubernetes/pkg/controller"
42 labelsutil "k8s.io/kubernetes/pkg/util/labels"
43 "k8s.io/utils/integer"
44 )
45
46 const (
47
48 RevisionAnnotation = "deployment.kubernetes.io/revision"
49
50 RevisionHistoryAnnotation = "deployment.kubernetes.io/revision-history"
51
52
53
54 DesiredReplicasAnnotation = "deployment.kubernetes.io/desired-replicas"
55
56
57
58 MaxReplicasAnnotation = "deployment.kubernetes.io/max-replicas"
59
60
61 RollbackRevisionNotFound = "DeploymentRollbackRevisionNotFound"
62
63 RollbackTemplateUnchanged = "DeploymentRollbackTemplateUnchanged"
64
65 RollbackDone = "DeploymentRollback"
66
67
68
69
70
71
72
73 ReplicaSetUpdatedReason = "ReplicaSetUpdated"
74
75 FailedRSCreateReason = "ReplicaSetCreateError"
76
77 NewReplicaSetReason = "NewReplicaSetCreated"
78
79 FoundNewRSReason = "FoundNewReplicaSet"
80
81
82
83 NewRSAvailableReason = "NewReplicaSetAvailable"
84
85
86 TimedOutReason = "ProgressDeadlineExceeded"
87
88
89 PausedDeployReason = "DeploymentPaused"
90
91
92 ResumedDeployReason = "DeploymentResumed"
93
94
95
96
97 MinimumReplicasAvailable = "MinimumReplicasAvailable"
98
99
100 MinimumReplicasUnavailable = "MinimumReplicasUnavailable"
101 )
102
103
104 func NewDeploymentCondition(condType apps.DeploymentConditionType, status v1.ConditionStatus, reason, message string) *apps.DeploymentCondition {
105 return &apps.DeploymentCondition{
106 Type: condType,
107 Status: status,
108 LastUpdateTime: metav1.Now(),
109 LastTransitionTime: metav1.Now(),
110 Reason: reason,
111 Message: message,
112 }
113 }
114
115
116 func GetDeploymentCondition(status apps.DeploymentStatus, condType apps.DeploymentConditionType) *apps.DeploymentCondition {
117 for i := range status.Conditions {
118 c := status.Conditions[i]
119 if c.Type == condType {
120 return &c
121 }
122 }
123 return nil
124 }
125
126
127
128 func SetDeploymentCondition(status *apps.DeploymentStatus, condition apps.DeploymentCondition) {
129 currentCond := GetDeploymentCondition(*status, condition.Type)
130 if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason {
131 return
132 }
133
134 if currentCond != nil && currentCond.Status == condition.Status {
135 condition.LastTransitionTime = currentCond.LastTransitionTime
136 }
137 newConditions := filterOutCondition(status.Conditions, condition.Type)
138 status.Conditions = append(newConditions, condition)
139 }
140
141
142 func RemoveDeploymentCondition(status *apps.DeploymentStatus, condType apps.DeploymentConditionType) {
143 status.Conditions = filterOutCondition(status.Conditions, condType)
144 }
145
146
147 func filterOutCondition(conditions []apps.DeploymentCondition, condType apps.DeploymentConditionType) []apps.DeploymentCondition {
148 var newConditions []apps.DeploymentCondition
149 for _, c := range conditions {
150 if c.Type == condType {
151 continue
152 }
153 newConditions = append(newConditions, c)
154 }
155 return newConditions
156 }
157
158
159
160 func ReplicaSetToDeploymentCondition(cond apps.ReplicaSetCondition) apps.DeploymentCondition {
161 return apps.DeploymentCondition{
162 Type: apps.DeploymentConditionType(cond.Type),
163 Status: cond.Status,
164 LastTransitionTime: cond.LastTransitionTime,
165 LastUpdateTime: cond.LastTransitionTime,
166 Reason: cond.Reason,
167 Message: cond.Message,
168 }
169 }
170
171
172 func SetDeploymentRevision(deployment *apps.Deployment, revision string) bool {
173 updated := false
174
175 if deployment.Annotations == nil {
176 deployment.Annotations = make(map[string]string)
177 }
178 if deployment.Annotations[RevisionAnnotation] != revision {
179 deployment.Annotations[RevisionAnnotation] = revision
180 updated = true
181 }
182
183 return updated
184 }
185
186
187 func MaxRevision(logger klog.Logger, allRSs []*apps.ReplicaSet) int64 {
188 max := int64(0)
189 for _, rs := range allRSs {
190 if v, err := Revision(rs); err != nil {
191
192 logger.V(4).Info("Couldn't parse revision for replica set, deployment controller will skip it when reconciling revisions", "replicaSet", klog.KObj(rs), "err", err)
193 } else if v > max {
194 max = v
195 }
196 }
197 return max
198 }
199
200
201 func LastRevision(logger klog.Logger, allRSs []*apps.ReplicaSet) int64 {
202 max, secMax := int64(0), int64(0)
203 for _, rs := range allRSs {
204 if v, err := Revision(rs); err != nil {
205
206 logger.V(4).Info("Couldn't parse revision for replica set, deployment controller will skip it when reconciling revisions", "replicaSet", klog.KObj(rs), "err", err)
207 } else if v >= max {
208 secMax = max
209 max = v
210 } else if v > secMax {
211 secMax = v
212 }
213 }
214 return secMax
215 }
216
217
218 func Revision(obj runtime.Object) (int64, error) {
219 acc, err := meta.Accessor(obj)
220 if err != nil {
221 return 0, err
222 }
223 v, ok := acc.GetAnnotations()[RevisionAnnotation]
224 if !ok {
225 return 0, nil
226 }
227 return strconv.ParseInt(v, 10, 64)
228 }
229
230
231
232 func SetNewReplicaSetAnnotations(ctx context.Context, deployment *apps.Deployment, newRS *apps.ReplicaSet, newRevision string, exists bool, revHistoryLimitInChars int) bool {
233 logger := klog.FromContext(ctx)
234
235 annotationChanged := copyDeploymentAnnotationsToReplicaSet(deployment, newRS)
236
237 if newRS.Annotations == nil {
238 newRS.Annotations = make(map[string]string)
239 }
240 oldRevision, ok := newRS.Annotations[RevisionAnnotation]
241
242
243
244
245 oldRevisionInt, err := strconv.ParseInt(oldRevision, 10, 64)
246 if err != nil {
247 if oldRevision != "" {
248 logger.Info("Updating replica set revision OldRevision not int", "err", err)
249 return false
250 }
251
252 oldRevisionInt = 0
253 }
254 newRevisionInt, err := strconv.ParseInt(newRevision, 10, 64)
255 if err != nil {
256 logger.Info("Updating replica set revision NewRevision not int", "err", err)
257 return false
258 }
259 if oldRevisionInt < newRevisionInt {
260 newRS.Annotations[RevisionAnnotation] = newRevision
261 annotationChanged = true
262 logger.V(4).Info("Updating replica set revision", "replicaSet", klog.KObj(newRS), "newRevision", newRevision)
263 }
264
265
266
267 if ok && oldRevisionInt < newRevisionInt {
268 revisionHistoryAnnotation := newRS.Annotations[RevisionHistoryAnnotation]
269 oldRevisions := strings.Split(revisionHistoryAnnotation, ",")
270 if len(oldRevisions[0]) == 0 {
271 newRS.Annotations[RevisionHistoryAnnotation] = oldRevision
272 } else {
273 totalLen := len(revisionHistoryAnnotation) + len(oldRevision) + 1
274
275 start := 0
276 for totalLen > revHistoryLimitInChars && start < len(oldRevisions) {
277 totalLen = totalLen - len(oldRevisions[start]) - 1
278 start++
279 }
280 if totalLen <= revHistoryLimitInChars {
281 oldRevisions = append(oldRevisions[start:], oldRevision)
282 newRS.Annotations[RevisionHistoryAnnotation] = strings.Join(oldRevisions, ",")
283 } else {
284 logger.Info("Not appending revision due to revision history length limit reached", "revisionHistoryLimit", revHistoryLimitInChars)
285 }
286 }
287 }
288
289 if !exists && SetReplicasAnnotations(newRS, *(deployment.Spec.Replicas), *(deployment.Spec.Replicas)+MaxSurge(*deployment)) {
290 annotationChanged = true
291 }
292 return annotationChanged
293 }
294
295 var annotationsToSkip = map[string]bool{
296 v1.LastAppliedConfigAnnotation: true,
297 RevisionAnnotation: true,
298 RevisionHistoryAnnotation: true,
299 DesiredReplicasAnnotation: true,
300 MaxReplicasAnnotation: true,
301 apps.DeprecatedRollbackTo: true,
302 }
303
304
305
306
307
308 func skipCopyAnnotation(key string) bool {
309 return annotationsToSkip[key]
310 }
311
312
313
314
315 func copyDeploymentAnnotationsToReplicaSet(deployment *apps.Deployment, rs *apps.ReplicaSet) bool {
316 rsAnnotationsChanged := false
317 if rs.Annotations == nil {
318 rs.Annotations = make(map[string]string)
319 }
320 for k, v := range deployment.Annotations {
321
322
323
324 if _, exist := rs.Annotations[k]; skipCopyAnnotation(k) || (exist && rs.Annotations[k] == v) {
325 continue
326 }
327 rs.Annotations[k] = v
328 rsAnnotationsChanged = true
329 }
330 return rsAnnotationsChanged
331 }
332
333
334
335
336 func SetDeploymentAnnotationsTo(deployment *apps.Deployment, rollbackToRS *apps.ReplicaSet) {
337 deployment.Annotations = getSkippedAnnotations(deployment.Annotations)
338 for k, v := range rollbackToRS.Annotations {
339 if !skipCopyAnnotation(k) {
340 deployment.Annotations[k] = v
341 }
342 }
343 }
344
345 func getSkippedAnnotations(annotations map[string]string) map[string]string {
346 skippedAnnotations := make(map[string]string)
347 for k, v := range annotations {
348 if skipCopyAnnotation(k) {
349 skippedAnnotations[k] = v
350 }
351 }
352 return skippedAnnotations
353 }
354
355
356
357 func FindActiveOrLatest(newRS *apps.ReplicaSet, oldRSs []*apps.ReplicaSet) *apps.ReplicaSet {
358 if newRS == nil && len(oldRSs) == 0 {
359 return nil
360 }
361
362 sort.Sort(sort.Reverse(controller.ReplicaSetsByCreationTimestamp(oldRSs)))
363 allRSs := controller.FilterActiveReplicaSets(append(oldRSs, newRS))
364
365 switch len(allRSs) {
366 case 0:
367
368 if newRS != nil {
369 return newRS
370 }
371 return oldRSs[0]
372 case 1:
373 return allRSs[0]
374 default:
375 return nil
376 }
377 }
378
379
380 func GetDesiredReplicasAnnotation(logger klog.Logger, rs *apps.ReplicaSet) (int32, bool) {
381 return getIntFromAnnotation(logger, rs, DesiredReplicasAnnotation)
382 }
383
384 func getMaxReplicasAnnotation(logger klog.Logger, rs *apps.ReplicaSet) (int32, bool) {
385 return getIntFromAnnotation(logger, rs, MaxReplicasAnnotation)
386 }
387
388 func getIntFromAnnotation(logger klog.Logger, rs *apps.ReplicaSet, annotationKey string) (int32, bool) {
389 annotationValue, ok := rs.Annotations[annotationKey]
390 if !ok {
391 return int32(0), false
392 }
393 intValue, err := strconv.Atoi(annotationValue)
394 if err != nil {
395 logger.V(2).Info("Could not convert the value with annotation key for the replica set", "annotationValue", annotationValue, "annotationKey", annotationKey, "replicaSet", klog.KObj(rs))
396 return int32(0), false
397 }
398 return int32(intValue), true
399 }
400
401
402 func SetReplicasAnnotations(rs *apps.ReplicaSet, desiredReplicas, maxReplicas int32) bool {
403 updated := false
404 if rs.Annotations == nil {
405 rs.Annotations = make(map[string]string)
406 }
407 desiredString := fmt.Sprintf("%d", desiredReplicas)
408 if hasString := rs.Annotations[DesiredReplicasAnnotation]; hasString != desiredString {
409 rs.Annotations[DesiredReplicasAnnotation] = desiredString
410 updated = true
411 }
412 maxString := fmt.Sprintf("%d", maxReplicas)
413 if hasString := rs.Annotations[MaxReplicasAnnotation]; hasString != maxString {
414 rs.Annotations[MaxReplicasAnnotation] = maxString
415 updated = true
416 }
417 return updated
418 }
419
420
421 func ReplicasAnnotationsNeedUpdate(rs *apps.ReplicaSet, desiredReplicas, maxReplicas int32) bool {
422 if rs.Annotations == nil {
423 return true
424 }
425 desiredString := fmt.Sprintf("%d", desiredReplicas)
426 if hasString := rs.Annotations[DesiredReplicasAnnotation]; hasString != desiredString {
427 return true
428 }
429 maxString := fmt.Sprintf("%d", maxReplicas)
430 if hasString := rs.Annotations[MaxReplicasAnnotation]; hasString != maxString {
431 return true
432 }
433 return false
434 }
435
436
437 func MaxUnavailable(deployment apps.Deployment) int32 {
438 if !IsRollingUpdate(&deployment) || *(deployment.Spec.Replicas) == 0 {
439 return int32(0)
440 }
441
442 _, maxUnavailable, _ := ResolveFenceposts(deployment.Spec.Strategy.RollingUpdate.MaxSurge, deployment.Spec.Strategy.RollingUpdate.MaxUnavailable, *(deployment.Spec.Replicas))
443 if maxUnavailable > *deployment.Spec.Replicas {
444 return *deployment.Spec.Replicas
445 }
446 return maxUnavailable
447 }
448
449
450 func MinAvailable(deployment *apps.Deployment) int32 {
451 if !IsRollingUpdate(deployment) {
452 return int32(0)
453 }
454 return *(deployment.Spec.Replicas) - MaxUnavailable(*deployment)
455 }
456
457
458 func MaxSurge(deployment apps.Deployment) int32 {
459 if !IsRollingUpdate(&deployment) {
460 return int32(0)
461 }
462
463 maxSurge, _, _ := ResolveFenceposts(deployment.Spec.Strategy.RollingUpdate.MaxSurge, deployment.Spec.Strategy.RollingUpdate.MaxUnavailable, *(deployment.Spec.Replicas))
464 return maxSurge
465 }
466
467
468
469
470 func GetProportion(logger klog.Logger, rs *apps.ReplicaSet, d apps.Deployment, deploymentReplicasToAdd, deploymentReplicasAdded int32) int32 {
471 if rs == nil || *(rs.Spec.Replicas) == 0 || deploymentReplicasToAdd == 0 || deploymentReplicasToAdd == deploymentReplicasAdded {
472 return int32(0)
473 }
474
475 rsFraction := getReplicaSetFraction(logger, *rs, d)
476 allowed := deploymentReplicasToAdd - deploymentReplicasAdded
477
478 if deploymentReplicasToAdd > 0 {
479
480
481
482 return min(rsFraction, allowed)
483 }
484
485
486
487 return max(rsFraction, allowed)
488 }
489
490
491
492 func getReplicaSetFraction(logger klog.Logger, rs apps.ReplicaSet, d apps.Deployment) int32 {
493
494 if *(d.Spec.Replicas) == int32(0) {
495 return -*(rs.Spec.Replicas)
496 }
497
498 deploymentReplicas := *(d.Spec.Replicas) + MaxSurge(d)
499 annotatedReplicas, ok := getMaxReplicasAnnotation(logger, &rs)
500 if !ok {
501
502
503
504
505 annotatedReplicas = d.Status.Replicas
506 }
507
508
509
510 newRSsize := (float64(*(rs.Spec.Replicas) * deploymentReplicas)) / float64(annotatedReplicas)
511 return integer.RoundToInt32(newRSsize) - *(rs.Spec.Replicas)
512 }
513
514
515 func RsListFromClient(c appsclient.AppsV1Interface) RsListFunc {
516 return func(namespace string, options metav1.ListOptions) ([]*apps.ReplicaSet, error) {
517 rsList, err := c.ReplicaSets(namespace).List(context.TODO(), options)
518 if err != nil {
519 return nil, err
520 }
521 var ret []*apps.ReplicaSet
522 for i := range rsList.Items {
523 ret = append(ret, &rsList.Items[i])
524 }
525 return ret, err
526 }
527 }
528
529
530
531
532 type RsListFunc func(string, metav1.ListOptions) ([]*apps.ReplicaSet, error)
533
534
535 type podListFunc func(string, metav1.ListOptions) (*v1.PodList, error)
536
537
538
539
540
541 func ListReplicaSets(deployment *apps.Deployment, getRSList RsListFunc) ([]*apps.ReplicaSet, error) {
542
543
544 namespace := deployment.Namespace
545 selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
546 if err != nil {
547 return nil, err
548 }
549 options := metav1.ListOptions{LabelSelector: selector.String()}
550 all, err := getRSList(namespace, options)
551 if err != nil {
552 return nil, err
553 }
554
555 owned := make([]*apps.ReplicaSet, 0, len(all))
556 for _, rs := range all {
557 if metav1.IsControlledBy(rs, deployment) {
558 owned = append(owned, rs)
559 }
560 }
561 return owned, nil
562 }
563
564
565
566
567
568
569
570 func ListPods(deployment *apps.Deployment, rsList []*apps.ReplicaSet, getPodList podListFunc) (*v1.PodList, error) {
571 namespace := deployment.Namespace
572 selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
573 if err != nil {
574 return nil, err
575 }
576 options := metav1.ListOptions{LabelSelector: selector.String()}
577 all, err := getPodList(namespace, options)
578 if err != nil {
579 return all, err
580 }
581
582
583 rsMap := make(map[types.UID]bool, len(rsList))
584 for _, rs := range rsList {
585 rsMap[rs.UID] = true
586 }
587 owned := &v1.PodList{Items: make([]v1.Pod, 0, len(all.Items))}
588 for i := range all.Items {
589 pod := &all.Items[i]
590 controllerRef := metav1.GetControllerOf(pod)
591 if controllerRef != nil && rsMap[controllerRef.UID] {
592 owned.Items = append(owned.Items, *pod)
593 }
594 }
595 return owned, nil
596 }
597
598
599
600
601
602
603 func EqualIgnoreHash(template1, template2 *v1.PodTemplateSpec) bool {
604 t1Copy := template1.DeepCopy()
605 t2Copy := template2.DeepCopy()
606
607 delete(t1Copy.Labels, apps.DefaultDeploymentUniqueLabelKey)
608 delete(t2Copy.Labels, apps.DefaultDeploymentUniqueLabelKey)
609 return apiequality.Semantic.DeepEqual(t1Copy, t2Copy)
610 }
611
612
613 func FindNewReplicaSet(deployment *apps.Deployment, rsList []*apps.ReplicaSet) *apps.ReplicaSet {
614 sort.Sort(controller.ReplicaSetsByCreationTimestamp(rsList))
615 for i := range rsList {
616 if EqualIgnoreHash(&rsList[i].Spec.Template, &deployment.Spec.Template) {
617
618
619
620
621 return rsList[i]
622 }
623 }
624
625 return nil
626 }
627
628
629
630 func FindOldReplicaSets(deployment *apps.Deployment, rsList []*apps.ReplicaSet) ([]*apps.ReplicaSet, []*apps.ReplicaSet) {
631 var requiredRSs []*apps.ReplicaSet
632 var allRSs []*apps.ReplicaSet
633 newRS := FindNewReplicaSet(deployment, rsList)
634 for _, rs := range rsList {
635
636 if newRS != nil && rs.UID == newRS.UID {
637 continue
638 }
639 allRSs = append(allRSs, rs)
640 if *(rs.Spec.Replicas) != 0 {
641 requiredRSs = append(requiredRSs, rs)
642 }
643 }
644 return requiredRSs, allRSs
645 }
646
647
648 func SetFromReplicaSetTemplate(deployment *apps.Deployment, template v1.PodTemplateSpec) *apps.Deployment {
649 deployment.Spec.Template.ObjectMeta = template.ObjectMeta
650 deployment.Spec.Template.Spec = template.Spec
651 deployment.Spec.Template.ObjectMeta.Labels = labelsutil.CloneAndRemoveLabel(
652 deployment.Spec.Template.ObjectMeta.Labels,
653 apps.DefaultDeploymentUniqueLabelKey)
654 return deployment
655 }
656
657
658 func GetReplicaCountForReplicaSets(replicaSets []*apps.ReplicaSet) int32 {
659 totalReplicas := int32(0)
660 for _, rs := range replicaSets {
661 if rs != nil {
662 totalReplicas += *(rs.Spec.Replicas)
663 }
664 }
665 return totalReplicas
666 }
667
668
669 func GetActualReplicaCountForReplicaSets(replicaSets []*apps.ReplicaSet) int32 {
670 totalActualReplicas := int32(0)
671 for _, rs := range replicaSets {
672 if rs != nil {
673 totalActualReplicas += rs.Status.Replicas
674 }
675 }
676 return totalActualReplicas
677 }
678
679
680 func GetReadyReplicaCountForReplicaSets(replicaSets []*apps.ReplicaSet) int32 {
681 totalReadyReplicas := int32(0)
682 for _, rs := range replicaSets {
683 if rs != nil {
684 totalReadyReplicas += rs.Status.ReadyReplicas
685 }
686 }
687 return totalReadyReplicas
688 }
689
690
691 func GetAvailableReplicaCountForReplicaSets(replicaSets []*apps.ReplicaSet) int32 {
692 totalAvailableReplicas := int32(0)
693 for _, rs := range replicaSets {
694 if rs != nil {
695 totalAvailableReplicas += rs.Status.AvailableReplicas
696 }
697 }
698 return totalAvailableReplicas
699 }
700
701
702 func IsRollingUpdate(deployment *apps.Deployment) bool {
703 return deployment.Spec.Strategy.Type == apps.RollingUpdateDeploymentStrategyType
704 }
705
706
707
708 func DeploymentComplete(deployment *apps.Deployment, newStatus *apps.DeploymentStatus) bool {
709 return newStatus.UpdatedReplicas == *(deployment.Spec.Replicas) &&
710 newStatus.Replicas == *(deployment.Spec.Replicas) &&
711 newStatus.AvailableReplicas == *(deployment.Spec.Replicas) &&
712 newStatus.ObservedGeneration >= deployment.Generation
713 }
714
715
716
717
718
719 func DeploymentProgressing(deployment *apps.Deployment, newStatus *apps.DeploymentStatus) bool {
720 oldStatus := deployment.Status
721
722
723 oldStatusOldReplicas := oldStatus.Replicas - oldStatus.UpdatedReplicas
724 newStatusOldReplicas := newStatus.Replicas - newStatus.UpdatedReplicas
725
726 return (newStatus.UpdatedReplicas > oldStatus.UpdatedReplicas) ||
727 (newStatusOldReplicas < oldStatusOldReplicas) ||
728 newStatus.ReadyReplicas > deployment.Status.ReadyReplicas ||
729 newStatus.AvailableReplicas > deployment.Status.AvailableReplicas
730 }
731
732
733 var nowFn = func() time.Time { return time.Now() }
734
735
736
737
738 func DeploymentTimedOut(ctx context.Context, deployment *apps.Deployment, newStatus *apps.DeploymentStatus) bool {
739 if !HasProgressDeadline(deployment) {
740 return false
741 }
742
743
744
745
746 condition := GetDeploymentCondition(*newStatus, apps.DeploymentProgressing)
747 if condition == nil {
748 return false
749 }
750
751
752
753
754
755
756
757
758
759
760
761 if condition.Reason == NewRSAvailableReason {
762 return false
763 }
764 if condition.Reason == TimedOutReason {
765 return true
766 }
767 logger := klog.FromContext(ctx)
768
769
770
771 from := condition.LastUpdateTime
772 now := nowFn()
773 delta := time.Duration(*deployment.Spec.ProgressDeadlineSeconds) * time.Second
774 timedOut := from.Add(delta).Before(now)
775
776 logger.V(4).Info("Deployment timed out from last progress check", "deployment", klog.KObj(deployment), "timeout", timedOut, "from", from, "now", now)
777 return timedOut
778 }
779
780
781
782
783
784 func NewRSNewReplicas(deployment *apps.Deployment, allRSs []*apps.ReplicaSet, newRS *apps.ReplicaSet) (int32, error) {
785 switch deployment.Spec.Strategy.Type {
786 case apps.RollingUpdateDeploymentStrategyType:
787
788 maxSurge, err := intstrutil.GetScaledValueFromIntOrPercent(deployment.Spec.Strategy.RollingUpdate.MaxSurge, int(*(deployment.Spec.Replicas)), true)
789 if err != nil {
790 return 0, err
791 }
792
793 currentPodCount := GetReplicaCountForReplicaSets(allRSs)
794 maxTotalPods := *(deployment.Spec.Replicas) + int32(maxSurge)
795 if currentPodCount >= maxTotalPods {
796
797 return *(newRS.Spec.Replicas), nil
798 }
799
800 scaleUpCount := maxTotalPods - currentPodCount
801
802 scaleUpCount = min(scaleUpCount, *(deployment.Spec.Replicas)-*(newRS.Spec.Replicas))
803 return *(newRS.Spec.Replicas) + scaleUpCount, nil
804 case apps.RecreateDeploymentStrategyType:
805 return *(deployment.Spec.Replicas), nil
806 default:
807 return 0, fmt.Errorf("deployment type %v isn't supported", deployment.Spec.Strategy.Type)
808 }
809 }
810
811
812
813
814
815 func IsSaturated(deployment *apps.Deployment, rs *apps.ReplicaSet) bool {
816 if rs == nil {
817 return false
818 }
819 desiredString := rs.Annotations[DesiredReplicasAnnotation]
820 desired, err := strconv.Atoi(desiredString)
821 if err != nil {
822 return false
823 }
824 return *(rs.Spec.Replicas) == *(deployment.Spec.Replicas) &&
825 int32(desired) == *(deployment.Spec.Replicas) &&
826 rs.Status.AvailableReplicas == *(deployment.Spec.Replicas)
827 }
828
829
830
831 func WaitForObservedDeployment(getDeploymentFunc func() (*apps.Deployment, error), desiredGeneration int64, interval, timeout time.Duration) error {
832
833 return wait.PollImmediate(interval, timeout, func() (bool, error) {
834 deployment, err := getDeploymentFunc()
835 if err != nil {
836 return false, err
837 }
838 return deployment.Status.ObservedGeneration >= desiredGeneration, nil
839 })
840 }
841
842
843
844
845
846
847
848
849
850
851 func ResolveFenceposts(maxSurge, maxUnavailable *intstrutil.IntOrString, desired int32) (int32, int32, error) {
852 surge, err := intstrutil.GetScaledValueFromIntOrPercent(intstrutil.ValueOrDefault(maxSurge, intstrutil.FromInt32(0)), int(desired), true)
853 if err != nil {
854 return 0, 0, err
855 }
856 unavailable, err := intstrutil.GetScaledValueFromIntOrPercent(intstrutil.ValueOrDefault(maxUnavailable, intstrutil.FromInt32(0)), int(desired), false)
857 if err != nil {
858 return 0, 0, err
859 }
860
861 if surge == 0 && unavailable == 0 {
862
863
864
865
866 unavailable = 1
867 }
868
869 return int32(surge), int32(unavailable), nil
870 }
871
872
873
874 func HasProgressDeadline(d *apps.Deployment) bool {
875 return d.Spec.ProgressDeadlineSeconds != nil && *d.Spec.ProgressDeadlineSeconds != math.MaxInt32
876 }
877
878
879
880
881
882 func HasRevisionHistoryLimit(d *apps.Deployment) bool {
883 return d.Spec.RevisionHistoryLimit != nil && *d.Spec.RevisionHistoryLimit != math.MaxInt32
884 }
885
886
887
888
889
890 func GetDeploymentsForReplicaSet(deploymentLister appslisters.DeploymentLister, rs *apps.ReplicaSet) ([]*apps.Deployment, error) {
891 if len(rs.Labels) == 0 {
892 return nil, fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name)
893 }
894
895
896 dList, err := deploymentLister.Deployments(rs.Namespace).List(labels.Everything())
897 if err != nil {
898 return nil, err
899 }
900
901 var deployments []*apps.Deployment
902 for _, d := range dList {
903 selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector)
904 if err != nil {
905
906 continue
907 }
908
909 if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) {
910 continue
911 }
912 deployments = append(deployments, d)
913 }
914
915 if len(deployments) == 0 {
916 return nil, fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels)
917 }
918
919 return deployments, nil
920 }
921
922
923
924 type ReplicaSetsByRevision []*apps.ReplicaSet
925
926 func (o ReplicaSetsByRevision) Len() int { return len(o) }
927 func (o ReplicaSetsByRevision) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
928 func (o ReplicaSetsByRevision) Less(i, j int) bool {
929 revision1, err1 := Revision(o[i])
930 revision2, err2 := Revision(o[j])
931 if err1 != nil || err2 != nil || revision1 == revision2 {
932 return controller.ReplicaSetsByCreationTimestamp(o).Less(i, j)
933 }
934 return revision1 < revision2
935 }
936
View as plain text