Skip to content

Commit b444828

Browse files
committed
CreateOrUseAndPatch: Make lessFunc configurable
1 parent 79a5fd1 commit b444828

File tree

2 files changed

+59
-15
lines changed

2 files changed

+59
-15
lines changed

clientutils/clientutils.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,13 @@ func setObject(dst, src client.Object) error {
448448
return nil
449449
}
450450

451+
// IsOlderThan returns a function that determines whether an object is older than another.
452+
func IsOlderThan(obj client.Object) func(other client.Object) (bool, error) {
453+
return func(other client.Object) (bool, error) {
454+
return obj.GetCreationTimestamp().Time.After(other.GetCreationTimestamp().Time), nil
455+
}
456+
}
457+
451458
// CreateOrUseAndPatch traverses through a slice of objects and tries to find a matching object using matchFunc.
452459
// If it does, the matching object is set to the object, optionally patched and returned.
453460
// If multiple objects match, the winning object is the oldest.
@@ -459,6 +466,7 @@ func CreateOrUseAndPatch(
459466
objects []client.Object,
460467
obj client.Object,
461468
matchFunc func() (bool, error),
469+
lessFunc func(other client.Object) (bool, error),
462470
mutateFunc func() error,
463471
) (controllerutil.OperationResult, []client.Object, error) {
464472
var (
@@ -477,17 +485,23 @@ func CreateOrUseAndPatch(
477485
return controllerutil.OperationResultNone, nil, err
478486
}
479487

480-
switch {
481-
case match && best == nil:
482-
best = object
483-
// The older object is better.
484-
// Using older objects over newer objects helps avoid creating too many new objects.
485-
case match && best.GetCreationTimestamp().Time.After(object.GetCreationTimestamp().Time):
486-
other = append(other, best)
487-
best = object
488-
default:
489-
other = append(other, object)
488+
if match {
489+
if best == nil {
490+
best = object
491+
continue
492+
}
493+
494+
less, err := lessFunc(best)
495+
if err != nil {
496+
return controllerutil.OperationResultNone, nil, err
497+
}
498+
if !less {
499+
other = append(other, best)
500+
best = object
501+
continue
502+
}
490503
}
504+
other = append(other, object)
491505
}
492506
if best != nil {
493507
if err := setObject(obj, best); err != nil {

clientutils/clientutils_test.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,24 @@ var _ = Describe("Clientutils", func() {
643643
})
644644
})
645645

646+
Describe("IsOlderThan", func() {
647+
It("should return true if an object is older than another", func() {
648+
cm1 := &corev1.ConfigMap{
649+
ObjectMeta: metav1.ObjectMeta{
650+
CreationTimestamp: metav1.Unix(100, 0),
651+
},
652+
}
653+
cm2 := &corev1.ConfigMap{
654+
ObjectMeta: metav1.ObjectMeta{
655+
CreationTimestamp: metav1.Unix(0, 0),
656+
},
657+
}
658+
Expect(IsOlderThan(cm2)(cm1)).To(BeFalse(), "cm1 should not be older than cm1")
659+
Expect(IsOlderThan(cm1)(cm2)).To(BeTrue(), "cm2 should be older than cm1")
660+
Expect(IsOlderThan(cm1)(cm1)).To(BeFalse(), "cm1 should not be older than itself")
661+
})
662+
})
663+
646664
Describe("CreateOrUseAndPatch", func() {
647665
var (
648666
cm1, cm2, cm3 corev1.ConfigMap
@@ -656,8 +674,9 @@ var _ = Describe("Clientutils", func() {
656674
}
657675
cm2 = corev1.ConfigMap{
658676
ObjectMeta: metav1.ObjectMeta{
659-
Namespace: "foo",
660-
Name: "n2",
677+
CreationTimestamp: metav1.Unix(100, 0),
678+
Namespace: "foo",
679+
Name: "n2",
661680
},
662681
}
663682
cm3 = corev1.ConfigMap{
@@ -683,7 +702,7 @@ var _ = Describe("Clientutils", func() {
683702
cm := &corev1.ConfigMap{}
684703
res, other, err := CreateOrUseAndPatch(ctx, c, []client.Object{&cm1, &cm2, &cm3}, cm, func() (bool, error) {
685704
return cm.Name == "n3", nil
686-
}, func() error {
705+
}, IsOlderThan(cm), func() error {
687706
cm.Annotations = annotations
688707
return nil
689708
})
@@ -703,7 +722,18 @@ var _ = Describe("Clientutils", func() {
703722
cm := &corev1.ConfigMap{}
704723
res, other, err := CreateOrUseAndPatch(ctx, c, []client.Object{&cm1, &cm2, &cm3}, cm, func() (bool, error) {
705724
return cm.Name == "n3", nil
706-
}, nil)
725+
}, IsOlderThan(cm), nil)
726+
Expect(err).NotTo(HaveOccurred())
727+
Expect(other).To(Equal([]client.Object{&cm1, &cm2}))
728+
Expect(res).To(Equal(controllerutil.OperationResultNone))
729+
Expect(cm).To(Equal(&cm3))
730+
})
731+
732+
It("should use the older object when multiple objects match", func() {
733+
cm := &corev1.ConfigMap{}
734+
res, other, err := CreateOrUseAndPatch(ctx, c, []client.Object{&cm1, &cm2, &cm3}, cm, func() (bool, error) {
735+
return cm.Name == "n2" || cm.Name == "n3", nil
736+
}, IsOlderThan(cm), nil)
707737
Expect(err).NotTo(HaveOccurred())
708738
Expect(other).To(Equal([]client.Object{&cm1, &cm2}))
709739
Expect(res).To(Equal(controllerutil.OperationResultNone))
@@ -715,7 +745,7 @@ var _ = Describe("Clientutils", func() {
715745
c.EXPECT().Create(ctx, cm)
716746
res, other, err := CreateOrUseAndPatch(ctx, c, []client.Object{&cm1, &cm2, &cm3}, cm, func() (bool, error) {
717747
return false, nil
718-
}, func() error {
748+
}, IsOlderThan(cm), func() error {
719749
cm.Name = "n4"
720750
return nil
721751
})

0 commit comments

Comments
 (0)