Skip to content

Commit 7dced0a

Browse files
committed
Support for ReconcileKeys in transformations
1 parent 7bbbc9b commit 7dced0a

File tree

4 files changed

+160
-4
lines changed

4 files changed

+160
-4
lines changed

pkg/controller/controller.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,36 @@ func (gc *GenericController) WatchTransformationOf(obj metav1.Object, mapFn even
126126

127127
// WatchTransformationsOf watches objects matching obj's type and enqueues the keys returned by mapFn.
128128
func (gc *GenericController) WatchTransformationsOf(obj metav1.Object, mapFn eventhandlers.ObjToKeys,
129+
p ...predicates.Predicate) error {
130+
gc.once.Do(gc.init)
131+
return gc.queue.addEventHandler(obj,
132+
eventhandlers.MapAndEnqueue{MultiMap: func(i interface{}) []types.ReconcileKey {
133+
result := []types.ReconcileKey{}
134+
for _, k := range mapFn(i) {
135+
if namespace, name, err := cache.SplitMetaNamespaceKey(k); err == nil {
136+
result = append(result, types.ReconcileKey{namespace, name})
137+
}
138+
}
139+
return result
140+
}, Predicates: p})
141+
}
142+
143+
// WatchTransformationKeyOf watches objects matching obj's type and enqueues the key returned by mapFn.
144+
func (gc *GenericController) WatchTransformationKeyOf(obj metav1.Object, mapFn eventhandlers.ObjToReconcileKey,
145+
p ...predicates.Predicate) error {
146+
gc.once.Do(gc.init)
147+
return gc.queue.addEventHandler(obj,
148+
eventhandlers.MapAndEnqueue{MultiMap: func(i interface{}) []types.ReconcileKey {
149+
if k := mapFn(i); len(k.Name) > 0 {
150+
return []types.ReconcileKey{k}
151+
} else {
152+
return []types.ReconcileKey{}
153+
}
154+
}, Predicates: p})
155+
}
156+
157+
// WatchTransformationKeysOf watches objects matching obj's type and enqueues the keys returned by mapFn.
158+
func (gc *GenericController) WatchTransformationKeysOf(obj metav1.Object, mapFn eventhandlers.ObjToReconcileKeys,
129159
p ...predicates.Predicate) error {
130160
gc.once.Do(gc.init)
131161
return gc.queue.addEventHandler(obj,

pkg/controller/controller_test.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ var _ = Describe("GenericController", func() {
219219
Expect(instance.GetMetrics().QueueLength).Should(Equal(0))
220220
})
221221

222-
It("should use the map function to reconcile a different key", func() {
222+
It("should use the transformation function to reconcile a different key", func() {
223223
// Listen for Pod changes
224224
Expect(instance.WatchTransformationOf(&corev1.Pod{}, func(obj interface{}) string {
225225
p := obj.(*corev1.Pod)
@@ -234,7 +234,22 @@ var _ = Describe("GenericController", func() {
234234
Expect(instance.GetMetrics().QueueLength).Should(Equal(0))
235235
})
236236

237-
It("should use the map function to reconcile multiple different keys", func() {
237+
It("should use the transformationkey function to reconcile a different key", func() {
238+
// Listen for Pod changes
239+
Expect(instance.WatchTransformationKeyOf(&corev1.Pod{}, func(obj interface{}) types.ReconcileKey {
240+
p := obj.(*corev1.Pod)
241+
return types.ReconcileKey{p.Namespace + "-namespace", p.Name + "-name"}
242+
})).Should(Succeed())
243+
244+
fakePodInformer.Add(&corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "default"}})
245+
246+
val := ChannelResult{}
247+
Eventually(result).Should(Receive(&val.result))
248+
Expect(val.result).Should(Equal("default-namespace/test-pod-name"))
249+
Expect(instance.GetMetrics().QueueLength).Should(Equal(0))
250+
})
251+
252+
It("should use the transformationsof function to reconcile multiple different keys", func() {
238253
// Listen for Pod changes
239254
Expect(instance.WatchTransformationsOf(&corev1.Pod{}, func(obj interface{}) []string {
240255
p := obj.(*corev1.Pod)
@@ -253,6 +268,26 @@ var _ = Describe("GenericController", func() {
253268
Expect(instance.GetMetrics().QueueLength).Should(Equal(0))
254269
})
255270

271+
It("should use the transformationkeysof function to reconcile multiple different keys", func() {
272+
// Listen for Pod changes
273+
Expect(instance.WatchTransformationKeysOf(&corev1.Pod{}, func(obj interface{}) []types.ReconcileKey {
274+
p := obj.(*corev1.Pod)
275+
return []types.ReconcileKey{
276+
{p.Namespace + "-namespace", p.Name + "-name-1"},
277+
{p.Namespace + "-namespace", p.Name + "-name-2"},
278+
}
279+
})).Should(Succeed())
280+
281+
fakePodInformer.Add(&corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "default"}})
282+
283+
val := ChannelResult{}
284+
Eventually(result).Should(Receive(&val.result))
285+
Expect(val.result).Should(Equal("default-namespace/test-pod-name-1"))
286+
Eventually(result).Should(Receive(&val.result))
287+
Expect(val.result).Should(Equal("default-namespace/test-pod-name-2"))
288+
Expect(instance.GetMetrics().QueueLength).Should(Equal(0))
289+
})
290+
256291
It("should call the event handling add function", func() {
257292
// Listen for Pod changes
258293
Expect(instance.WatchEvents(&corev1.Pod{},

pkg/controller/eventhandlers/eventhandlers.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type MapAndEnqueue struct {
4040
// Map maps an object to a key that can be enqueued
4141
Map func(interface{}) string
4242

43-
MultiMap func(interface{}) []string
43+
MultiMap func(interface{}) []types.ReconcileKey
4444
}
4545

4646
// Get returns ResourceEventHandlerFuncs that Map an object to a Key and enqueue the key if it is non-empty
@@ -83,7 +83,7 @@ func (mp MapAndEnqueue) addRateLimited(r workqueue.RateLimitingInterface, obj in
8383
}
8484
if mp.MultiMap != nil {
8585
for _, k := range mp.MultiMap(obj) {
86-
r.AddRateLimited(k)
86+
r.AddRateLimited(k.Namespace + "/" + k.Name)
8787
}
8888
}
8989
}
@@ -151,6 +151,10 @@ type ObjToKey func(interface{}) string
151151

152152
type ObjToKeys func(interface{}) []string
153153

154+
type ObjToReconcileKey func(interface{}) types.ReconcileKey
155+
156+
type ObjToReconcileKeys func(interface{}) []types.ReconcileKey
157+
154158
// MapToSelf returns the namespace/name key of obj
155159
func MapToSelf(obj interface{}) string {
156160
if key, err := cache.MetaNamespaceKeyFunc(obj); err != nil {

pkg/controller/example_watchandmap_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,90 @@ func ExampleGenericController_WatchTransformationsOf() {
116116
// One time for program
117117
controller.RunInformersAndControllers(run.CreateRunArguments())
118118
}
119+
120+
func ExampleGenericController_WatchTransformationKeyOf() {
121+
// One time setup for program
122+
flag.Parse()
123+
informerFactory := config.GetKubernetesInformersOrDie()
124+
if err := controller.AddInformerProvider(&corev1.Pod{}, informerFactory.Core().V1().Pods()); err != nil {
125+
log.Fatalf("Could not set informer %v", err)
126+
}
127+
if err := controller.AddInformerProvider(&appsv1.ReplicaSet{}, informerFactory.Apps().V1().ReplicaSets()); err != nil {
128+
log.Fatalf("Could not set informer %v", err)
129+
}
130+
131+
// Per-controller setup
132+
c := &controller.GenericController{
133+
Reconcile: func(key types.ReconcileKey) error {
134+
fmt.Printf("Reconciling Pod %s\n", key)
135+
return nil
136+
},
137+
}
138+
err := c.Watch(&appsv1.ReplicaSet{})
139+
if err != nil {
140+
log.Fatalf("%v", err)
141+
}
142+
err = c.WatchTransformationKeyOf(&corev1.Pod{},
143+
func(i interface{}) types.ReconcileKey {
144+
p, ok := i.(*corev1.Pod)
145+
if !ok {
146+
return types.ReconcileKey{}
147+
}
148+
149+
// Find multiple parents based off the name
150+
return types.ReconcileKey{p.Namespace, strings.Split(p.Name, "-")[0]}
151+
},
152+
)
153+
if err != nil {
154+
log.Fatalf("%v", err)
155+
}
156+
controller.AddController(c)
157+
158+
// One time for program
159+
controller.RunInformersAndControllers(run.CreateRunArguments())
160+
}
161+
162+
func ExampleGenericController_WatchTransformationKeysOf() {
163+
// One time setup for program
164+
flag.Parse()
165+
informerFactory := config.GetKubernetesInformersOrDie()
166+
if err := controller.AddInformerProvider(&corev1.Pod{}, informerFactory.Core().V1().Pods()); err != nil {
167+
log.Fatalf("Could not set informer %v", err)
168+
}
169+
if err := controller.AddInformerProvider(&appsv1.ReplicaSet{}, informerFactory.Apps().V1().ReplicaSets()); err != nil {
170+
log.Fatalf("Could not set informer %v", err)
171+
}
172+
173+
// Per-controller setup
174+
c := &controller.GenericController{
175+
Reconcile: func(key types.ReconcileKey) error {
176+
fmt.Printf("Reconciling Pod %s\n", key)
177+
return nil
178+
},
179+
}
180+
err := c.Watch(&appsv1.ReplicaSet{})
181+
if err != nil {
182+
log.Fatalf("%v", err)
183+
}
184+
err = c.WatchTransformationKeysOf(&corev1.Pod{},
185+
func(i interface{}) []types.ReconcileKey {
186+
p, ok := i.(*corev1.Pod)
187+
if !ok {
188+
return []types.ReconcileKey{}
189+
}
190+
191+
// Find multiple parents based off the name
192+
return []types.ReconcileKey{
193+
{p.Namespace, strings.Split(p.Name, "-")[0] + "-parent-1"},
194+
{p.Namespace, strings.Split(p.Name, "-")[0] + "-parent-2"},
195+
}
196+
},
197+
)
198+
if err != nil {
199+
log.Fatalf("%v", err)
200+
}
201+
controller.AddController(c)
202+
203+
// One time for program
204+
controller.RunInformersAndControllers(run.CreateRunArguments())
205+
}

0 commit comments

Comments
 (0)