1
16
17 package util
18
19 import (
20 "context"
21 "sort"
22
23 apps "k8s.io/api/apps/v1"
24 v1 "k8s.io/api/core/v1"
25 apiequality "k8s.io/apimachinery/pkg/api/equality"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 intstrutil "k8s.io/apimachinery/pkg/util/intstr"
28 appsclient "k8s.io/client-go/kubernetes/typed/apps/v1"
29 )
30
31
32
33
34
35
36 type RsListFunc func(string, metav1.ListOptions) ([]*apps.ReplicaSet, error)
37
38
39
40
41
42 func ListReplicaSets(deployment *apps.Deployment, getRSList RsListFunc) ([]*apps.ReplicaSet, error) {
43
44
45 namespace := deployment.Namespace
46 selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
47 if err != nil {
48 return nil, err
49 }
50 options := metav1.ListOptions{LabelSelector: selector.String()}
51 all, err := getRSList(namespace, options)
52 if err != nil {
53 return nil, err
54 }
55
56 owned := make([]*apps.ReplicaSet, 0, len(all))
57 for _, rs := range all {
58 if metav1.IsControlledBy(rs, deployment) {
59 owned = append(owned, rs)
60 }
61 }
62 return owned, nil
63 }
64
65
66 type ReplicaSetsByCreationTimestamp []*apps.ReplicaSet
67
68 func (o ReplicaSetsByCreationTimestamp) Len() int { return len(o) }
69 func (o ReplicaSetsByCreationTimestamp) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
70 func (o ReplicaSetsByCreationTimestamp) Less(i, j int) bool {
71 if o[i].CreationTimestamp.Equal(&o[j].CreationTimestamp) {
72 return o[i].Name < o[j].Name
73 }
74 return o[i].CreationTimestamp.Before(&o[j].CreationTimestamp)
75 }
76
77
78 func FindNewReplicaSet(deployment *apps.Deployment, rsList []*apps.ReplicaSet) *apps.ReplicaSet {
79 sort.Sort(ReplicaSetsByCreationTimestamp(rsList))
80 for i := range rsList {
81 if EqualIgnoreHash(&rsList[i].Spec.Template, &deployment.Spec.Template) {
82
83
84
85
86 return rsList[i]
87 }
88 }
89
90 return nil
91 }
92
93
94
95
96
97
98 func EqualIgnoreHash(template1, template2 *v1.PodTemplateSpec) bool {
99 t1Copy := template1.DeepCopy()
100 t2Copy := template2.DeepCopy()
101
102 delete(t1Copy.Labels, apps.DefaultDeploymentUniqueLabelKey)
103 delete(t2Copy.Labels, apps.DefaultDeploymentUniqueLabelKey)
104 return apiequality.Semantic.DeepEqual(t1Copy, t2Copy)
105 }
106
107
108
109 func GetNewReplicaSet(deployment *apps.Deployment, c appsclient.AppsV1Interface) (*apps.ReplicaSet, error) {
110 rsList, err := ListReplicaSets(deployment, RsListFromClient(c))
111 if err != nil {
112 return nil, err
113 }
114 return FindNewReplicaSet(deployment, rsList), nil
115 }
116
117
118 func RsListFromClient(c appsclient.AppsV1Interface) RsListFunc {
119 return func(namespace string, options metav1.ListOptions) ([]*apps.ReplicaSet, error) {
120 rsList, err := c.ReplicaSets(namespace).List(context.Background(), options)
121 if err != nil {
122 return nil, err
123 }
124 var ret []*apps.ReplicaSet
125 for i := range rsList.Items {
126 ret = append(ret, &rsList.Items[i])
127 }
128 return ret, err
129 }
130 }
131
132
133 func IsRollingUpdate(deployment *apps.Deployment) bool {
134 return deployment.Spec.Strategy.Type == apps.RollingUpdateDeploymentStrategyType
135 }
136
137
138 func MaxUnavailable(deployment apps.Deployment) int32 {
139 if !IsRollingUpdate(&deployment) || *(deployment.Spec.Replicas) == 0 {
140 return int32(0)
141 }
142
143 _, maxUnavailable, _ := ResolveFenceposts(deployment.Spec.Strategy.RollingUpdate.MaxSurge, deployment.Spec.Strategy.RollingUpdate.MaxUnavailable, *(deployment.Spec.Replicas))
144 if maxUnavailable > *deployment.Spec.Replicas {
145 return *deployment.Spec.Replicas
146 }
147 return maxUnavailable
148 }
149
150
151
152
153
154
155
156
157
158
159 func ResolveFenceposts(maxSurge, maxUnavailable *intstrutil.IntOrString, desired int32) (int32, int32, error) {
160 surge, err := intstrutil.GetValueFromIntOrPercent(intstrutil.ValueOrDefault(maxSurge, intstrutil.FromInt(0)), int(desired), true)
161 if err != nil {
162 return 0, 0, err
163 }
164 unavailable, err := intstrutil.GetValueFromIntOrPercent(intstrutil.ValueOrDefault(maxUnavailable, intstrutil.FromInt(0)), int(desired), false)
165 if err != nil {
166 return 0, 0, err
167 }
168
169 if surge == 0 && unavailable == 0 {
170
171
172
173
174 unavailable = 1
175 }
176
177 return int32(surge), int32(unavailable), nil
178 }
179
View as plain text