Skip to content

Commit dad8159

Browse files
committed
introduce LabelChangedPredicate to trigger event on label change
Signed-off-by: Bruce Ma <[email protected]>
1 parent 5564be7 commit dad8159

File tree

2 files changed

+226
-0
lines changed

2 files changed

+226
-0
lines changed

pkg/predicate/predicate.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,36 @@ func (AnnotationChangedPredicate) Update(e event.UpdateEvent) bool {
200200
return !reflect.DeepEqual(e.ObjectNew.GetAnnotations(), e.ObjectOld.GetAnnotations())
201201
}
202202

203+
// LabelChangedPredicate implements a default update predicate function on label change.
204+
//
205+
// This predicate will skip update events that have no change in the object's label.
206+
// It is intended to be used in conjunction with the GenerationChangedPredicate, as in the following example:
207+
//
208+
// Controller.Watch(
209+
// &source.Kind{Type: v1.MyCustomKind},
210+
// &handler.EnqueueRequestForObject{},
211+
// predicate.Or(predicate.GenerationChangedPredicate{}, predicate.LabelChangedPredicate{}))
212+
//
213+
// This will be helpful when object's labels is carrying some extra specification information beyond object's spec,
214+
// and the controller will be triggered if any valid spec change (not only in spec, but also in labels) happens.
215+
type LabelChangedPredicate struct {
216+
Funcs
217+
}
218+
219+
// Update implements default UpdateEvent filter for checking label change
220+
func (LabelChangedPredicate) Update(e event.UpdateEvent) bool {
221+
if e.ObjectOld == nil {
222+
log.Error(nil, "Update event has no old object to update", "event", e)
223+
return false
224+
}
225+
if e.ObjectNew == nil {
226+
log.Error(nil, "Update event has no new object for update", "event", e)
227+
return false
228+
}
229+
230+
return !reflect.DeepEqual(e.ObjectNew.GetLabels(), e.ObjectOld.GetLabels())
231+
}
232+
203233
// And returns a composite predicate that implements a logical AND of the predicates passed to it.
204234
func And(predicates ...Predicate) Predicate {
205235
return and{predicates}

pkg/predicate/predicate_test.go

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,202 @@ var _ = Describe("Predicate", func() {
610610
})
611611
})
612612

613+
Describe("When checking a LabelChangedPredicate", func() {
614+
instance := predicate.LabelChangedPredicate{}
615+
Context("Where the old object is missing", func() {
616+
It("should return false", func() {
617+
new := &corev1.Pod{
618+
ObjectMeta: metav1.ObjectMeta{
619+
Name: "baz",
620+
Namespace: "biz",
621+
Labels: map[string]string{
622+
"foo": "bar",
623+
},
624+
}}
625+
626+
evt := event.UpdateEvent{
627+
ObjectNew: new,
628+
}
629+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
630+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
631+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
632+
Expect(instance.Update(evt)).To(BeFalse())
633+
})
634+
})
635+
636+
Context("Where the new object is missing", func() {
637+
It("should return false", func() {
638+
old := &corev1.Pod{
639+
ObjectMeta: metav1.ObjectMeta{
640+
Name: "baz",
641+
Namespace: "biz",
642+
Labels: map[string]string{
643+
"foo": "bar",
644+
},
645+
}}
646+
647+
evt := event.UpdateEvent{
648+
ObjectOld: old,
649+
}
650+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
651+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
652+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
653+
Expect(instance.Update(evt)).To(BeFalse())
654+
})
655+
})
656+
657+
Context("Where the labels are empty", func() {
658+
It("should return false", func() {
659+
new := &corev1.Pod{
660+
ObjectMeta: metav1.ObjectMeta{
661+
Name: "baz",
662+
Namespace: "biz",
663+
}}
664+
665+
old := &corev1.Pod{
666+
ObjectMeta: metav1.ObjectMeta{
667+
Name: "baz",
668+
Namespace: "biz",
669+
}}
670+
671+
evt := event.UpdateEvent{
672+
ObjectOld: old,
673+
ObjectNew: new,
674+
}
675+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
676+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
677+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
678+
Expect(instance.Update(evt)).To(BeFalse())
679+
})
680+
})
681+
682+
Context("Where the labels haven't changed", func() {
683+
It("should return false", func() {
684+
new := &corev1.Pod{
685+
ObjectMeta: metav1.ObjectMeta{
686+
Name: "baz",
687+
Namespace: "biz",
688+
Labels: map[string]string{
689+
"foo": "bar",
690+
},
691+
}}
692+
693+
old := &corev1.Pod{
694+
ObjectMeta: metav1.ObjectMeta{
695+
Name: "baz",
696+
Namespace: "biz",
697+
Labels: map[string]string{
698+
"foo": "bar",
699+
},
700+
}}
701+
702+
evt := event.UpdateEvent{
703+
ObjectOld: old,
704+
ObjectNew: new,
705+
}
706+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
707+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
708+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
709+
Expect(instance.Update(evt)).To(BeFalse())
710+
})
711+
})
712+
713+
Context("Where a label value has changed", func() {
714+
It("should return true", func() {
715+
new := &corev1.Pod{
716+
ObjectMeta: metav1.ObjectMeta{
717+
Name: "baz",
718+
Namespace: "biz",
719+
Labels: map[string]string{
720+
"foo": "bar",
721+
},
722+
}}
723+
724+
old := &corev1.Pod{
725+
ObjectMeta: metav1.ObjectMeta{
726+
Name: "baz",
727+
Namespace: "biz",
728+
Labels: map[string]string{
729+
"foo": "bee",
730+
},
731+
}}
732+
733+
evt := event.UpdateEvent{
734+
ObjectOld: old,
735+
ObjectNew: new,
736+
}
737+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
738+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
739+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
740+
Expect(instance.Update(evt)).To(BeTrue())
741+
})
742+
})
743+
744+
Context("Where a label has been added", func() {
745+
It("should return true", func() {
746+
new := &corev1.Pod{
747+
ObjectMeta: metav1.ObjectMeta{
748+
Name: "baz",
749+
Namespace: "biz",
750+
Labels: map[string]string{
751+
"foo": "bar",
752+
},
753+
}}
754+
755+
old := &corev1.Pod{
756+
ObjectMeta: metav1.ObjectMeta{
757+
Name: "baz",
758+
Namespace: "biz",
759+
Labels: map[string]string{
760+
"foo": "bar",
761+
"faa": "bor",
762+
},
763+
}}
764+
765+
evt := event.UpdateEvent{
766+
ObjectOld: old,
767+
ObjectNew: new,
768+
}
769+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
770+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
771+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
772+
Expect(instance.Update(evt)).To(BeTrue())
773+
})
774+
})
775+
776+
Context("Where a label has been removed", func() {
777+
It("should return true", func() {
778+
new := &corev1.Pod{
779+
ObjectMeta: metav1.ObjectMeta{
780+
Name: "baz",
781+
Namespace: "biz",
782+
Labels: map[string]string{
783+
"foo": "bar",
784+
"faa": "bor",
785+
},
786+
}}
787+
788+
old := &corev1.Pod{
789+
ObjectMeta: metav1.ObjectMeta{
790+
Name: "baz",
791+
Namespace: "biz",
792+
Labels: map[string]string{
793+
"foo": "bar",
794+
},
795+
}}
796+
797+
evt := event.UpdateEvent{
798+
ObjectOld: old,
799+
ObjectNew: new,
800+
}
801+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
802+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
803+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
804+
Expect(instance.Update(evt)).To(BeTrue())
805+
})
806+
})
807+
})
808+
613809
Context("With a boolean predicate", func() {
614810
funcs := func(pass bool) predicate.Funcs {
615811
return predicate.Funcs{

0 commit comments

Comments
 (0)