@@ -23,6 +23,8 @@ import (
23
23
24
24
. "github.com/onsi/ginkgo"
25
25
. "github.com/onsi/gomega"
26
+ "k8s.io/client-go/rest"
27
+ "sigs.k8s.io/controller-runtime/pkg/cache"
26
28
27
29
appsv1 "k8s.io/api/apps/v1"
28
30
corev1 "k8s.io/api/core/v1"
@@ -203,8 +205,107 @@ var _ = Describe("application", func() {
203
205
close (done )
204
206
}, 10 )
205
207
})
208
+
209
+ Describe ("watching with projections" , func () {
210
+ var mgr manager.Manager
211
+ BeforeEach (func () {
212
+ // use a cache that intercepts requests for fully typed objects to
213
+ // ensure we use the projected versions
214
+ var err error
215
+ mgr , err = manager .New (cfg , manager.Options {NewCache : newNonTypedOnlyCache })
216
+ Expect (err ).NotTo (HaveOccurred ())
217
+ })
218
+
219
+ It ("should support watching For, Owns, and Watch as metadata" , func () {
220
+ statefulSetMaps := make (chan * metav1.PartialObjectMetadata )
221
+
222
+ bldr := ControllerManagedBy (mgr ).
223
+ For (OnlyMetadata (& appsv1.Deployment {})).
224
+ Owns (OnlyMetadata (& appsv1.ReplicaSet {})).
225
+ Watches (& source.Kind {Type : OnlyMetadata (& appsv1.StatefulSet {})},
226
+ & handler.EnqueueRequestsFromMapFunc {
227
+ ToRequests : handler .ToRequestsFunc (func (o handler.MapObject ) []reconcile.Request {
228
+ ometa := o .Object .(* metav1.PartialObjectMetadata )
229
+ statefulSetMaps <- ometa
230
+ return nil
231
+ }),
232
+ })
233
+
234
+ doReconcileTest ("8" , stop , bldr , mgr , true )
235
+
236
+ By ("Creating a new stateful set" )
237
+ set := & appsv1.StatefulSet {
238
+ ObjectMeta : metav1.ObjectMeta {
239
+ Namespace : "default" ,
240
+ Name : "test1" ,
241
+ Labels : map [string ]string {
242
+ "foo" : "bar" ,
243
+ },
244
+ },
245
+ Spec : appsv1.StatefulSetSpec {
246
+ Selector : & metav1.LabelSelector {
247
+ MatchLabels : map [string ]string {"foo" : "bar" },
248
+ },
249
+ Template : corev1.PodTemplateSpec {
250
+ ObjectMeta : metav1.ObjectMeta {Labels : map [string ]string {"foo" : "bar" }},
251
+ Spec : corev1.PodSpec {
252
+ Containers : []corev1.Container {
253
+ {
254
+ Name : "nginx" ,
255
+ Image : "nginx" ,
256
+ },
257
+ },
258
+ },
259
+ },
260
+ },
261
+ }
262
+ err := mgr .GetClient ().Create (context .TODO (), set )
263
+ Expect (err ).NotTo (HaveOccurred ())
264
+
265
+ By ("Checking that the mapping function has been called" )
266
+ Eventually (func () bool {
267
+ metaSet := <- statefulSetMaps
268
+ Expect (metaSet .Name ).To (Equal (set .Name ))
269
+ Expect (metaSet .Namespace ).To (Equal (set .Namespace ))
270
+ Expect (metaSet .Labels ).To (Equal (set .Labels ))
271
+ return true
272
+ }).Should (BeTrue ())
273
+ })
274
+ })
206
275
})
207
276
277
+ // newNonTypedOnlyCache returns a new cache that wraps the normal cache,
278
+ // returning an error if normal, typed objects have informers requested.
279
+ func newNonTypedOnlyCache (config * rest.Config , opts cache.Options ) (cache.Cache , error ) {
280
+ normalCache , err := cache .New (config , opts )
281
+ if err != nil {
282
+ return nil , err
283
+ }
284
+ return & nonTypedOnlyCache {
285
+ Cache : normalCache ,
286
+ }, nil
287
+ }
288
+
289
+ // nonTypedOnlyCache is a cache.Cache that only provides metadata &
290
+ // unstructured informers.
291
+ type nonTypedOnlyCache struct {
292
+ cache.Cache
293
+ }
294
+
295
+ func (c * nonTypedOnlyCache ) GetInformer (obj runtime.Object ) (cache.Informer , error ) {
296
+ switch obj .(type ) {
297
+ case (* metav1.PartialObjectMetadata ):
298
+ return c .Cache .GetInformer (obj )
299
+ default :
300
+ return nil , fmt .Errorf ("did not want to provide an informer for normal type %T" , obj )
301
+ }
302
+ }
303
+ func (c * nonTypedOnlyCache ) GetInformerForKind (gvk schema.GroupVersionKind ) (cache.Informer , error ) {
304
+ return nil , fmt .Errorf ("don't try to sidestep the restriction on informer types by calling GetInformerForKind" )
305
+ }
306
+
307
+ // TODO(directxman12): this function has too many arguments, and the whole
308
+ // "nameSuffix" think is a bit of a hack It should be cleaned up significantly by someone with a bit of time
208
309
func doReconcileTest (nameSuffix string , stop chan struct {}, blder * Builder , mgr manager.Manager , complete bool ) {
209
310
deployName := "deploy-name-" + nameSuffix
210
311
rsName := "rs-name-" + nameSuffix
@@ -267,8 +368,8 @@ func doReconcileTest(nameSuffix string, stop chan struct{}, blder *Builder, mgr
267
368
Expect (err ).NotTo (HaveOccurred ())
268
369
269
370
By ("Waiting for the Deployment Reconcile" )
270
- Expect ( <- ch ).To (Equal (reconcile.Request {
271
- NamespacedName : types.NamespacedName {Namespace : "default" , Name : deployName }}))
371
+ Eventually ( ch ).Should ( Receive (Equal (reconcile.Request {
372
+ NamespacedName : types.NamespacedName {Namespace : "default" , Name : deployName }})))
272
373
273
374
By ("Creating a ReplicaSet" )
274
375
// Expect a Reconcile when an Owned object is managedObjects.
@@ -297,8 +398,8 @@ func doReconcileTest(nameSuffix string, stop chan struct{}, blder *Builder, mgr
297
398
Expect (err ).NotTo (HaveOccurred ())
298
399
299
400
By ("Waiting for the ReplicaSet Reconcile" )
300
- Expect ( <- ch ).To (Equal (reconcile.Request {
301
- NamespacedName : types.NamespacedName {Namespace : "default" , Name : deployName }}))
401
+ Eventually ( ch ).Should ( Receive (Equal (reconcile.Request {
402
+ NamespacedName : types.NamespacedName {Namespace : "default" , Name : deployName }})))
302
403
303
404
}
304
405
0 commit comments