Skip to content

Commit 8941d18

Browse files
authored
Merge pull request #567 from kubernetes-sigs/master
🏃 preparing 0.2.0-rc.0 release
2 parents eb94491 + d7467fc commit 8941d18

File tree

3 files changed

+176
-1
lines changed

3 files changed

+176
-1
lines changed

pkg/predicate/predicate.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type Predicate interface {
4040

4141
var _ Predicate = Funcs{}
4242
var _ Predicate = ResourceVersionChangedPredicate{}
43+
var _ Predicate = GenerationChangedPredicate{}
4344

4445
// Funcs is a function that implements Predicate.
4546
type Funcs struct {
@@ -116,3 +117,47 @@ func (ResourceVersionChangedPredicate) Update(e event.UpdateEvent) bool {
116117
}
117118
return true
118119
}
120+
121+
// GenerationChangedPredicate implements a default update predicate function on Generation change.
122+
//
123+
// This predicate will skip update events that have no change in the object's metadata.generation field.
124+
// The metadata.generation field of an object is incremented by the API server when writes are made to the spec field of an object.
125+
// This allows a controller to ignore update events where the spec is unchanged, and only the metadata and/or status fields are changed.
126+
//
127+
// For CustomResource objects the Generation is only incremented when the status subresource is enabled.
128+
//
129+
// Caveats:
130+
//
131+
// * The assumption that the Generation is incremented only on writing to the spec does not hold for all APIs.
132+
// E.g For Deployment objects the Generation is also incremented on writes to the metadata.annotations field.
133+
// For object types other than CustomResources be sure to verify which fields will trigger a Generation increment when they are written to.
134+
//
135+
// * With this predicate, any update events with writes only to the status field will not be reconciled.
136+
// So in the event that the status block is overwritten or wiped by someone else the controller will not self-correct to restore the correct status.
137+
type GenerationChangedPredicate struct {
138+
Funcs
139+
}
140+
141+
// Update implements default UpdateEvent filter for validating generation change
142+
func (GenerationChangedPredicate) Update(e event.UpdateEvent) bool {
143+
if e.MetaOld == nil {
144+
log.Error(nil, "Update event has no old metadata", "event", e)
145+
return false
146+
}
147+
if e.ObjectOld == nil {
148+
log.Error(nil, "Update event has no old runtime object to update", "event", e)
149+
return false
150+
}
151+
if e.ObjectNew == nil {
152+
log.Error(nil, "Update event has no new runtime object for update", "event", e)
153+
return false
154+
}
155+
if e.MetaNew == nil {
156+
log.Error(nil, "Update event has no new metadata", "event", e)
157+
return false
158+
}
159+
if e.MetaNew.GetGeneration() == e.MetaOld.GetGeneration() {
160+
return false
161+
}
162+
return true
163+
}

pkg/predicate/predicate_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,4 +308,134 @@ var _ = Describe("Predicate", func() {
308308
})
309309

310310
})
311+
312+
Describe("When checking a GenerationChangedPredicate", func() {
313+
instance := predicate.GenerationChangedPredicate{}
314+
Context("Where the old object doesn't have a Generation or metadata", func() {
315+
It("should return false", func() {
316+
new := &corev1.Pod{
317+
ObjectMeta: metav1.ObjectMeta{
318+
Name: "baz",
319+
Namespace: "biz",
320+
Generation: 1,
321+
}}
322+
323+
failEvnt := event.UpdateEvent{
324+
MetaNew: new.GetObjectMeta(),
325+
ObjectNew: new,
326+
}
327+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
328+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
329+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
330+
Expect(instance.Update(failEvnt)).To(BeFalse())
331+
})
332+
})
333+
334+
Context("Where the new object doesn't have a Generation or metadata", func() {
335+
It("should return false", func() {
336+
old := &corev1.Pod{
337+
ObjectMeta: metav1.ObjectMeta{
338+
Name: "baz",
339+
Namespace: "biz",
340+
Generation: 1,
341+
}}
342+
343+
failEvnt := event.UpdateEvent{
344+
MetaOld: old.GetObjectMeta(),
345+
ObjectOld: old,
346+
}
347+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
348+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
349+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
350+
Expect(instance.Update(failEvnt)).To(BeFalse())
351+
})
352+
})
353+
354+
Context("Where the Generation hasn't changed", func() {
355+
It("should return false", func() {
356+
new := &corev1.Pod{
357+
ObjectMeta: metav1.ObjectMeta{
358+
Name: "baz",
359+
Namespace: "biz",
360+
Generation: 1,
361+
}}
362+
363+
old := &corev1.Pod{
364+
ObjectMeta: metav1.ObjectMeta{
365+
Name: "baz",
366+
Namespace: "biz",
367+
Generation: 1,
368+
}}
369+
370+
failEvnt := event.UpdateEvent{
371+
MetaOld: old.GetObjectMeta(),
372+
ObjectOld: old,
373+
MetaNew: new.GetObjectMeta(),
374+
ObjectNew: new,
375+
}
376+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
377+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
378+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
379+
Expect(instance.Update(failEvnt)).To(BeFalse())
380+
})
381+
})
382+
383+
Context("Where the Generation has changed", func() {
384+
It("should return true", func() {
385+
new := &corev1.Pod{
386+
ObjectMeta: metav1.ObjectMeta{
387+
Name: "baz",
388+
Namespace: "biz",
389+
Generation: 1,
390+
}}
391+
392+
old := &corev1.Pod{
393+
ObjectMeta: metav1.ObjectMeta{
394+
Name: "baz",
395+
Namespace: "biz",
396+
Generation: 2,
397+
}}
398+
passEvt := event.UpdateEvent{
399+
MetaOld: old.GetObjectMeta(),
400+
ObjectOld: old,
401+
MetaNew: new.GetObjectMeta(),
402+
ObjectNew: new,
403+
}
404+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
405+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
406+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
407+
Expect(instance.Update(passEvt)).To(BeTrue())
408+
})
409+
})
410+
411+
Context("Where the objects or metadata are missing", func() {
412+
413+
It("should return false", func() {
414+
new := &corev1.Pod{
415+
ObjectMeta: metav1.ObjectMeta{
416+
Name: "baz",
417+
Namespace: "biz",
418+
Generation: 1,
419+
}}
420+
421+
old := &corev1.Pod{
422+
ObjectMeta: metav1.ObjectMeta{
423+
Name: "baz",
424+
Namespace: "biz",
425+
Generation: 1,
426+
}}
427+
428+
failEvt1 := event.UpdateEvent{MetaOld: old.GetObjectMeta(), ObjectOld: old, MetaNew: new.GetObjectMeta()}
429+
failEvt2 := event.UpdateEvent{MetaOld: old.GetObjectMeta(), MetaNew: new.GetObjectMeta(), ObjectNew: new}
430+
failEvt3 := event.UpdateEvent{MetaOld: old.GetObjectMeta(), ObjectOld: old, ObjectNew: new}
431+
Expect(instance.Create(event.CreateEvent{})).To(BeTrue())
432+
Expect(instance.Delete(event.DeleteEvent{})).To(BeTrue())
433+
Expect(instance.Generic(event.GenericEvent{})).To(BeTrue())
434+
Expect(instance.Update(failEvt1)).To(BeFalse())
435+
Expect(instance.Update(failEvt2)).To(BeFalse())
436+
Expect(instance.Update(failEvt3)).To(BeFalse())
437+
})
438+
})
439+
440+
})
311441
})

pkg/runtime/log/log.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ var (
3737
// ZapLoggerTo returns a new Logger implementation using Zap which logs
3838
// to the given destination, instead of stderr. It otherwise behaves like
3939
// ZapLogger.
40-
ZapLoggerTo = zap.Logger
40+
ZapLoggerTo = zap.LoggerTo
4141

4242
// SetLogger sets a concrete logging implementation for all deferred Loggers.
4343
SetLogger = log.SetLogger

0 commit comments

Comments
 (0)