1
16
17
18
19 package replicaset
20
21 import (
22 "context"
23 "fmt"
24 "reflect"
25
26 "k8s.io/klog/v2"
27
28 apps "k8s.io/api/apps/v1"
29 v1 "k8s.io/api/core/v1"
30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 "k8s.io/apimachinery/pkg/labels"
32 appsclient "k8s.io/client-go/kubernetes/typed/apps/v1"
33 podutil "k8s.io/kubernetes/pkg/api/v1/pod"
34 )
35
36
37 func updateReplicaSetStatus(logger klog.Logger, c appsclient.ReplicaSetInterface, rs *apps.ReplicaSet, newStatus apps.ReplicaSetStatus) (*apps.ReplicaSet, error) {
38
39
40
41 if rs.Status.Replicas == newStatus.Replicas &&
42 rs.Status.FullyLabeledReplicas == newStatus.FullyLabeledReplicas &&
43 rs.Status.ReadyReplicas == newStatus.ReadyReplicas &&
44 rs.Status.AvailableReplicas == newStatus.AvailableReplicas &&
45 rs.Generation == rs.Status.ObservedGeneration &&
46 reflect.DeepEqual(rs.Status.Conditions, newStatus.Conditions) {
47 return rs, nil
48 }
49
50
51
52
53
54 newStatus.ObservedGeneration = rs.Generation
55
56 var getErr, updateErr error
57 var updatedRS *apps.ReplicaSet
58 for i, rs := 0, rs; ; i++ {
59 logger.V(4).Info(fmt.Sprintf("Updating status for %v: %s/%s, ", rs.Kind, rs.Namespace, rs.Name) +
60 fmt.Sprintf("replicas %d->%d (need %d), ", rs.Status.Replicas, newStatus.Replicas, *(rs.Spec.Replicas)) +
61 fmt.Sprintf("fullyLabeledReplicas %d->%d, ", rs.Status.FullyLabeledReplicas, newStatus.FullyLabeledReplicas) +
62 fmt.Sprintf("readyReplicas %d->%d, ", rs.Status.ReadyReplicas, newStatus.ReadyReplicas) +
63 fmt.Sprintf("availableReplicas %d->%d, ", rs.Status.AvailableReplicas, newStatus.AvailableReplicas) +
64 fmt.Sprintf("sequence No: %v->%v", rs.Status.ObservedGeneration, newStatus.ObservedGeneration))
65
66 rs.Status = newStatus
67 updatedRS, updateErr = c.UpdateStatus(context.TODO(), rs, metav1.UpdateOptions{})
68 if updateErr == nil {
69 return updatedRS, nil
70 }
71
72 if i >= statusUpdateRetries {
73 break
74 }
75
76 if rs, getErr = c.Get(context.TODO(), rs.Name, metav1.GetOptions{}); getErr != nil {
77
78
79 return nil, getErr
80 }
81 }
82
83 return nil, updateErr
84 }
85
86 func calculateStatus(rs *apps.ReplicaSet, filteredPods []*v1.Pod, manageReplicasErr error) apps.ReplicaSetStatus {
87 newStatus := rs.Status
88
89
90
91
92
93 fullyLabeledReplicasCount := 0
94 readyReplicasCount := 0
95 availableReplicasCount := 0
96 templateLabel := labels.Set(rs.Spec.Template.Labels).AsSelectorPreValidated()
97 for _, pod := range filteredPods {
98 if templateLabel.Matches(labels.Set(pod.Labels)) {
99 fullyLabeledReplicasCount++
100 }
101 if podutil.IsPodReady(pod) {
102 readyReplicasCount++
103 if podutil.IsPodAvailable(pod, rs.Spec.MinReadySeconds, metav1.Now()) {
104 availableReplicasCount++
105 }
106 }
107 }
108
109 failureCond := GetCondition(rs.Status, apps.ReplicaSetReplicaFailure)
110 if manageReplicasErr != nil && failureCond == nil {
111 var reason string
112 if diff := len(filteredPods) - int(*(rs.Spec.Replicas)); diff < 0 {
113 reason = "FailedCreate"
114 } else if diff > 0 {
115 reason = "FailedDelete"
116 }
117 cond := NewReplicaSetCondition(apps.ReplicaSetReplicaFailure, v1.ConditionTrue, reason, manageReplicasErr.Error())
118 SetCondition(&newStatus, cond)
119 } else if manageReplicasErr == nil && failureCond != nil {
120 RemoveCondition(&newStatus, apps.ReplicaSetReplicaFailure)
121 }
122
123 newStatus.Replicas = int32(len(filteredPods))
124 newStatus.FullyLabeledReplicas = int32(fullyLabeledReplicasCount)
125 newStatus.ReadyReplicas = int32(readyReplicasCount)
126 newStatus.AvailableReplicas = int32(availableReplicasCount)
127 return newStatus
128 }
129
130
131 func NewReplicaSetCondition(condType apps.ReplicaSetConditionType, status v1.ConditionStatus, reason, msg string) apps.ReplicaSetCondition {
132 return apps.ReplicaSetCondition{
133 Type: condType,
134 Status: status,
135 LastTransitionTime: metav1.Now(),
136 Reason: reason,
137 Message: msg,
138 }
139 }
140
141
142 func GetCondition(status apps.ReplicaSetStatus, condType apps.ReplicaSetConditionType) *apps.ReplicaSetCondition {
143 for _, c := range status.Conditions {
144 if c.Type == condType {
145 return &c
146 }
147 }
148 return nil
149 }
150
151
152
153 func SetCondition(status *apps.ReplicaSetStatus, condition apps.ReplicaSetCondition) {
154 currentCond := GetCondition(*status, condition.Type)
155 if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason {
156 return
157 }
158 newConditions := filterOutCondition(status.Conditions, condition.Type)
159 status.Conditions = append(newConditions, condition)
160 }
161
162
163 func RemoveCondition(status *apps.ReplicaSetStatus, condType apps.ReplicaSetConditionType) {
164 status.Conditions = filterOutCondition(status.Conditions, condType)
165 }
166
167
168 func filterOutCondition(conditions []apps.ReplicaSetCondition, condType apps.ReplicaSetConditionType) []apps.ReplicaSetCondition {
169 var newConditions []apps.ReplicaSetCondition
170 for _, c := range conditions {
171 if c.Type == condType {
172 continue
173 }
174 newConditions = append(newConditions, c)
175 }
176 return newConditions
177 }
178
View as plain text