1
16
17 package history
18
19 import (
20 "bytes"
21 "context"
22 "encoding/json"
23 "fmt"
24 "hash/fnv"
25 "sort"
26 "strconv"
27
28 apps "k8s.io/api/apps/v1"
29 appsinformers "k8s.io/client-go/informers/apps/v1"
30 clientset "k8s.io/client-go/kubernetes"
31 appslisters "k8s.io/client-go/listers/apps/v1"
32 "k8s.io/kubernetes/pkg/controller"
33 hashutil "k8s.io/kubernetes/pkg/util/hash"
34
35 apiequality "k8s.io/apimachinery/pkg/api/equality"
36 "k8s.io/apimachinery/pkg/api/errors"
37 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38 "k8s.io/apimachinery/pkg/labels"
39 "k8s.io/apimachinery/pkg/runtime"
40 "k8s.io/apimachinery/pkg/types"
41
42 "k8s.io/apimachinery/pkg/runtime/schema"
43 "k8s.io/apimachinery/pkg/util/rand"
44 "k8s.io/client-go/tools/cache"
45 "k8s.io/client-go/util/retry"
46 )
47
48
49 const ControllerRevisionHashLabel = "controller.kubernetes.io/hash"
50
51
52
53 func ControllerRevisionName(prefix string, hash string) string {
54 if len(prefix) > 223 {
55 prefix = prefix[:223]
56 }
57
58 return fmt.Sprintf("%s-%s", prefix, hash)
59 }
60
61
62
63
64
65
66 func NewControllerRevision(parent metav1.Object,
67 parentKind schema.GroupVersionKind,
68 templateLabels map[string]string,
69 data runtime.RawExtension,
70 revision int64,
71 collisionCount *int32) (*apps.ControllerRevision, error) {
72 labelMap := make(map[string]string)
73 for k, v := range templateLabels {
74 labelMap[k] = v
75 }
76 cr := &apps.ControllerRevision{
77 ObjectMeta: metav1.ObjectMeta{
78 Labels: labelMap,
79 OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(parent, parentKind)},
80 },
81 Data: data,
82 Revision: revision,
83 }
84 hash := HashControllerRevision(cr, collisionCount)
85 cr.Name = ControllerRevisionName(parent.GetName(), hash)
86 cr.Labels[ControllerRevisionHashLabel] = hash
87 return cr, nil
88 }
89
90
91
92 func HashControllerRevision(revision *apps.ControllerRevision, probe *int32) string {
93 hf := fnv.New32()
94 if len(revision.Data.Raw) > 0 {
95 hf.Write(revision.Data.Raw)
96 }
97 if revision.Data.Object != nil {
98 hashutil.DeepHashObject(hf, revision.Data.Object)
99 }
100 if probe != nil {
101 hf.Write([]byte(strconv.FormatInt(int64(*probe), 10)))
102 }
103 return rand.SafeEncodeString(fmt.Sprint(hf.Sum32()))
104 }
105
106
107 func SortControllerRevisions(revisions []*apps.ControllerRevision) {
108 sort.Stable(byRevision(revisions))
109 }
110
111
112
113 func EqualRevision(lhs *apps.ControllerRevision, rhs *apps.ControllerRevision) bool {
114 var lhsHash, rhsHash *uint32
115 if lhs == nil || rhs == nil {
116 return lhs == rhs
117 }
118 if hs, found := lhs.Labels[ControllerRevisionHashLabel]; found {
119 hash, err := strconv.ParseInt(hs, 10, 32)
120 if err == nil {
121 lhsHash = new(uint32)
122 *lhsHash = uint32(hash)
123 }
124 }
125 if hs, found := rhs.Labels[ControllerRevisionHashLabel]; found {
126 hash, err := strconv.ParseInt(hs, 10, 32)
127 if err == nil {
128 rhsHash = new(uint32)
129 *rhsHash = uint32(hash)
130 }
131 }
132 if lhsHash != nil && rhsHash != nil && *lhsHash != *rhsHash {
133 return false
134 }
135 return bytes.Equal(lhs.Data.Raw, rhs.Data.Raw) && apiequality.Semantic.DeepEqual(lhs.Data.Object, rhs.Data.Object)
136 }
137
138
139
140 func FindEqualRevisions(revisions []*apps.ControllerRevision, needle *apps.ControllerRevision) []*apps.ControllerRevision {
141 var eq []*apps.ControllerRevision
142 for i := range revisions {
143 if EqualRevision(revisions[i], needle) {
144 eq = append(eq, revisions[i])
145 }
146 }
147 return eq
148 }
149
150
151 type byRevision []*apps.ControllerRevision
152
153 func (br byRevision) Len() int {
154 return len(br)
155 }
156
157
158 func (br byRevision) Less(i, j int) bool {
159 if br[i].Revision == br[j].Revision {
160 if br[j].CreationTimestamp.Equal(&br[i].CreationTimestamp) {
161 return br[i].Name < br[j].Name
162 }
163 return br[j].CreationTimestamp.After(br[i].CreationTimestamp.Time)
164 }
165 return br[i].Revision < br[j].Revision
166 }
167
168 func (br byRevision) Swap(i, j int) {
169 br[i], br[j] = br[j], br[i]
170 }
171
172
173
174
175 type Interface interface {
176
177
178
179 ListControllerRevisions(parent metav1.Object, selector labels.Selector) ([]*apps.ControllerRevision, error)
180
181
182
183
184
185
186
187 CreateControllerRevision(parent metav1.Object, revision *apps.ControllerRevision, collisionCount *int32) (*apps.ControllerRevision, error)
188
189 DeleteControllerRevision(revision *apps.ControllerRevision) error
190
191
192
193 UpdateControllerRevision(revision *apps.ControllerRevision, newRevision int64) (*apps.ControllerRevision, error)
194
195
196
197
198 AdoptControllerRevision(parent metav1.Object, parentKind schema.GroupVersionKind, revision *apps.ControllerRevision) (*apps.ControllerRevision, error)
199
200
201
202 ReleaseControllerRevision(parent metav1.Object, revision *apps.ControllerRevision) (*apps.ControllerRevision, error)
203 }
204
205
206
207 func NewHistory(client clientset.Interface, lister appslisters.ControllerRevisionLister) Interface {
208 return &realHistory{client, lister}
209 }
210
211
212
213 func NewFakeHistory(informer appsinformers.ControllerRevisionInformer) Interface {
214 return &fakeHistory{informer.Informer().GetIndexer(), informer.Lister()}
215 }
216
217 type realHistory struct {
218 client clientset.Interface
219 lister appslisters.ControllerRevisionLister
220 }
221
222 func (rh *realHistory) ListControllerRevisions(parent metav1.Object, selector labels.Selector) ([]*apps.ControllerRevision, error) {
223
224 history, err := rh.lister.ControllerRevisions(parent.GetNamespace()).List(selector)
225 if err != nil {
226 return nil, err
227 }
228 var owned []*apps.ControllerRevision
229 for i := range history {
230 ref := metav1.GetControllerOfNoCopy(history[i])
231 if ref == nil || ref.UID == parent.GetUID() {
232 owned = append(owned, history[i])
233 }
234
235 }
236 return owned, err
237 }
238
239 func (rh *realHistory) CreateControllerRevision(parent metav1.Object, revision *apps.ControllerRevision, collisionCount *int32) (*apps.ControllerRevision, error) {
240 if collisionCount == nil {
241 return nil, fmt.Errorf("collisionCount should not be nil")
242 }
243
244
245 clone := revision.DeepCopy()
246
247
248 for {
249 hash := HashControllerRevision(revision, collisionCount)
250
251 clone.Name = ControllerRevisionName(parent.GetName(), hash)
252 ns := parent.GetNamespace()
253 created, err := rh.client.AppsV1().ControllerRevisions(ns).Create(context.TODO(), clone, metav1.CreateOptions{})
254 if errors.IsAlreadyExists(err) {
255 exists, err := rh.client.AppsV1().ControllerRevisions(ns).Get(context.TODO(), clone.Name, metav1.GetOptions{})
256 if err != nil {
257 return nil, err
258 }
259 if bytes.Equal(exists.Data.Raw, clone.Data.Raw) {
260 return exists, nil
261 }
262 *collisionCount++
263 continue
264 }
265 return created, err
266 }
267 }
268
269 func (rh *realHistory) UpdateControllerRevision(revision *apps.ControllerRevision, newRevision int64) (*apps.ControllerRevision, error) {
270 clone := revision.DeepCopy()
271 err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
272 if clone.Revision == newRevision {
273 return nil
274 }
275 clone.Revision = newRevision
276 updated, updateErr := rh.client.AppsV1().ControllerRevisions(clone.Namespace).Update(context.TODO(), clone, metav1.UpdateOptions{})
277 if updateErr == nil {
278 return nil
279 }
280 if updated != nil {
281 clone = updated
282 }
283 if updated, err := rh.lister.ControllerRevisions(clone.Namespace).Get(clone.Name); err == nil {
284
285 clone = updated.DeepCopy()
286 }
287 return updateErr
288 })
289 return clone, err
290 }
291
292 func (rh *realHistory) DeleteControllerRevision(revision *apps.ControllerRevision) error {
293 return rh.client.AppsV1().ControllerRevisions(revision.Namespace).Delete(context.TODO(), revision.Name, metav1.DeleteOptions{})
294 }
295
296 type objectForPatch struct {
297 Metadata objectMetaForPatch `json:"metadata"`
298 }
299
300
301 type objectMetaForPatch struct {
302 OwnerReferences []metav1.OwnerReference `json:"ownerReferences"`
303 UID types.UID `json:"uid"`
304 }
305
306 func (rh *realHistory) AdoptControllerRevision(parent metav1.Object, parentKind schema.GroupVersionKind, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
307 blockOwnerDeletion := true
308 isController := true
309
310 if owner := metav1.GetControllerOfNoCopy(revision); owner != nil {
311 return nil, fmt.Errorf("attempt to adopt revision owned by %v", owner)
312 }
313 addControllerPatch := objectForPatch{
314 Metadata: objectMetaForPatch{
315 UID: revision.UID,
316 OwnerReferences: []metav1.OwnerReference{{
317 APIVersion: parentKind.GroupVersion().String(),
318 Kind: parentKind.Kind,
319 Name: parent.GetName(),
320 UID: parent.GetUID(),
321 Controller: &isController,
322 BlockOwnerDeletion: &blockOwnerDeletion,
323 }},
324 },
325 }
326 patchBytes, err := json.Marshal(&addControllerPatch)
327 if err != nil {
328 return nil, err
329 }
330
331 return rh.client.AppsV1().ControllerRevisions(parent.GetNamespace()).Patch(context.TODO(), revision.GetName(),
332 types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
333 }
334
335 func (rh *realHistory) ReleaseControllerRevision(parent metav1.Object, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
336 dataBytes, err := controller.GenerateDeleteOwnerRefStrategicMergeBytes(revision.UID, []types.UID{parent.GetUID()})
337 if err != nil {
338 return nil, err
339 }
340
341
342 released, err := rh.client.AppsV1().ControllerRevisions(revision.GetNamespace()).Patch(context.TODO(), revision.GetName(),
343 types.StrategicMergePatchType, dataBytes, metav1.PatchOptions{})
344
345 if err != nil {
346 if errors.IsNotFound(err) {
347
348 return nil, nil
349 }
350 if errors.IsInvalid(err) {
351
352
353 return nil, nil
354 }
355 }
356 return released, err
357 }
358
359 type fakeHistory struct {
360 indexer cache.Indexer
361 lister appslisters.ControllerRevisionLister
362 }
363
364 func (fh *fakeHistory) ListControllerRevisions(parent metav1.Object, selector labels.Selector) ([]*apps.ControllerRevision, error) {
365 history, err := fh.lister.ControllerRevisions(parent.GetNamespace()).List(selector)
366 if err != nil {
367 return nil, err
368 }
369
370 var owned []*apps.ControllerRevision
371 for i := range history {
372 ref := metav1.GetControllerOf(history[i])
373 if ref == nil || ref.UID == parent.GetUID() {
374 owned = append(owned, history[i])
375 }
376
377 }
378 return owned, err
379 }
380
381 func (fh *fakeHistory) addRevision(revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
382 key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(revision)
383 if err != nil {
384 return nil, err
385 }
386 obj, found, err := fh.indexer.GetByKey(key)
387 if err != nil {
388 return nil, err
389 }
390 if found {
391 foundRevision := obj.(*apps.ControllerRevision)
392 return foundRevision, errors.NewAlreadyExists(apps.Resource("controllerrevision"), revision.Name)
393 }
394 return revision, fh.indexer.Update(revision)
395 }
396
397 func (fh *fakeHistory) CreateControllerRevision(parent metav1.Object, revision *apps.ControllerRevision, collisionCount *int32) (*apps.ControllerRevision, error) {
398 if collisionCount == nil {
399 return nil, fmt.Errorf("collisionCount should not be nil")
400 }
401
402
403 clone := revision.DeepCopy()
404 clone.Namespace = parent.GetNamespace()
405
406
407 for {
408 hash := HashControllerRevision(revision, collisionCount)
409
410 clone.Name = ControllerRevisionName(parent.GetName(), hash)
411 created, err := fh.addRevision(clone)
412 if errors.IsAlreadyExists(err) {
413 *collisionCount++
414 continue
415 }
416 return created, err
417 }
418 }
419
420 func (fh *fakeHistory) DeleteControllerRevision(revision *apps.ControllerRevision) error {
421 key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(revision)
422 if err != nil {
423 return err
424 }
425 obj, found, err := fh.indexer.GetByKey(key)
426 if err != nil {
427 return err
428 }
429 if !found {
430 return errors.NewNotFound(apps.Resource("controllerrevisions"), revision.Name)
431 }
432 return fh.indexer.Delete(obj)
433 }
434
435 func (fh *fakeHistory) UpdateControllerRevision(revision *apps.ControllerRevision, newRevision int64) (*apps.ControllerRevision, error) {
436 clone := revision.DeepCopy()
437 clone.Revision = newRevision
438 return clone, fh.indexer.Update(clone)
439 }
440
441 func (fh *fakeHistory) AdoptControllerRevision(parent metav1.Object, parentKind schema.GroupVersionKind, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
442 if owner := metav1.GetControllerOf(revision); owner != nil {
443 return nil, fmt.Errorf("attempt to adopt revision owned by %v", owner)
444 }
445 key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(revision)
446 if err != nil {
447 return nil, err
448 }
449 _, found, err := fh.indexer.GetByKey(key)
450 if err != nil {
451 return nil, err
452 }
453 if !found {
454 return nil, errors.NewNotFound(apps.Resource("controllerrevisions"), revision.Name)
455 }
456 clone := revision.DeepCopy()
457 clone.OwnerReferences = append(clone.OwnerReferences, *metav1.NewControllerRef(parent, parentKind))
458 return clone, fh.indexer.Update(clone)
459 }
460
461 func (fh *fakeHistory) ReleaseControllerRevision(parent metav1.Object, revision *apps.ControllerRevision) (*apps.ControllerRevision, error) {
462 key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(revision)
463 if err != nil {
464 return nil, err
465 }
466 _, found, err := fh.indexer.GetByKey(key)
467 if err != nil {
468 return nil, err
469 }
470 if !found {
471 return nil, nil
472 }
473 clone := revision.DeepCopy()
474 refs := clone.OwnerReferences
475 clone.OwnerReferences = nil
476 for i := range refs {
477 if refs[i].UID != parent.GetUID() {
478 clone.OwnerReferences = append(clone.OwnerReferences, refs[i])
479 }
480 }
481 return clone, fh.indexer.Update(clone)
482 }
483
View as plain text