@@ -32,18 +32,17 @@ import (
32
32
"github.com/operator-framework/operator-sdk/pkg/ansible/proxy/controllermap"
33
33
"github.com/operator-framework/operator-sdk/pkg/ansible/proxy/kubeconfig"
34
34
k8sRequest "github.com/operator-framework/operator-sdk/pkg/ansible/proxy/requestfactory"
35
+ osdkHandler "github.com/operator-framework/operator-sdk/pkg/handler"
35
36
"k8s.io/apimachinery/pkg/api/meta"
36
37
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
37
38
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38
39
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
39
40
"k8s.io/apimachinery/pkg/runtime/schema"
40
- "k8s.io/apimachinery/pkg/types"
41
41
"k8s.io/apimachinery/pkg/util/sets"
42
42
"k8s.io/client-go/rest"
43
43
"sigs.k8s.io/controller-runtime/pkg/cache"
44
44
"sigs.k8s.io/controller-runtime/pkg/client"
45
45
"sigs.k8s.io/controller-runtime/pkg/handler"
46
- "sigs.k8s.io/controller-runtime/pkg/reconcile"
47
46
"sigs.k8s.io/controller-runtime/pkg/source"
48
47
)
49
48
@@ -152,25 +151,8 @@ func CacheResponseHandler(h http.Handler, informerCache cache.Cache, restMapper
152
151
// Once we get the resource, we are going to attempt to recover the dependent watches here,
153
152
// This will happen in the background, and log errors.
154
153
if injectOwnerRef {
155
- go func () {
156
- ownerRef , err := getRequestOwnerRef (req )
157
- if err != nil {
158
- log .Error (err , "Could not get ownerRef from proxy" )
159
- return
160
- }
161
-
162
- for _ , oRef := range un .GetOwnerReferences () {
163
- if oRef .APIVersion == ownerRef .APIVersion && oRef .Kind == ownerRef .Kind {
164
- err := addWatchToController (ownerRef , cMap , un , restMapper )
165
- if err != nil {
166
- log .Error (err , "Could not recover dependent resource watch" , "owner" , ownerRef )
167
- return
168
- }
169
- }
170
- }
171
- }()
154
+ go recoverDependentWatches (req , un , cMap , restMapper )
172
155
}
173
-
174
156
}
175
157
176
158
i := bytes.Buffer {}
@@ -203,6 +185,38 @@ func CacheResponseHandler(h http.Handler, informerCache cache.Cache, restMapper
203
185
})
204
186
}
205
187
188
+ func recoverDependentWatches (req * http.Request , un * unstructured.Unstructured , cMap * controllermap.ControllerMap , restMapper meta.RESTMapper ) {
189
+ ownerRef , err := getRequestOwnerRef (req )
190
+ if err != nil {
191
+ log .Error (err , "Could not get ownerRef from proxy" )
192
+ return
193
+ }
194
+
195
+ for _ , oRef := range un .GetOwnerReferences () {
196
+ if oRef .APIVersion == ownerRef .APIVersion && oRef .Kind == ownerRef .Kind {
197
+ err := addWatchToController (ownerRef , cMap , un , restMapper , true )
198
+ if err != nil {
199
+ log .Error (err , "Could not recover dependent resource watch" , "owner" , ownerRef )
200
+ return
201
+ }
202
+ }
203
+ }
204
+ if typeString , ok := un .GetAnnotations ()[osdkHandler .TypeAnnotation ]; ok {
205
+ ownerGV , err := schema .ParseGroupVersion (ownerRef .APIVersion )
206
+ if err != nil {
207
+ log .Error (err , "Could not get ownerRef from proxy" )
208
+ return
209
+ }
210
+ if typeString == fmt .Sprintf ("%v.%v" , ownerRef .Kind , ownerGV .Group ) {
211
+ err := addWatchToController (ownerRef , cMap , un , restMapper , false )
212
+ if err != nil {
213
+ log .Error (err , "Could not recover dependent resource watch" , "owner" , ownerRef )
214
+ return
215
+ }
216
+ }
217
+ }
218
+ }
219
+
206
220
// InjectOwnerReferenceHandler will handle proxied requests and inject the
207
221
// owner reference found in the authorization header. The Authorization is
208
222
// then deleted so that the proxy can re-set with the correct authorization.
@@ -248,7 +262,33 @@ func InjectOwnerReferenceHandler(h http.Handler, cMap *controllermap.ControllerM
248
262
http .Error (w , m , http .StatusBadRequest )
249
263
return
250
264
}
251
- data .SetOwnerReferences (append (data .GetOwnerReferences (), owner .OwnerReference ))
265
+
266
+ addOwnerRef , err := shouldAddOwnerRef (data , owner , restMapper )
267
+ if err != nil {
268
+ m := "Could not determine if we should add owner ref"
269
+ log .Error (err , m )
270
+ http .Error (w , m , http .StatusBadRequest )
271
+ return
272
+ }
273
+ if addOwnerRef {
274
+ data .SetOwnerReferences (append (data .GetOwnerReferences (), owner .OwnerReference ))
275
+ } else {
276
+ ownerGV , err := schema .ParseGroupVersion (owner .APIVersion )
277
+ if err != nil {
278
+ m := fmt .Sprintf ("could not get broup version for: %v" , owner )
279
+ log .Error (err , m )
280
+ http .Error (w , m , http .StatusBadRequest )
281
+ return
282
+ }
283
+ a := data .GetAnnotations ()
284
+ if a == nil {
285
+ a = map [string ]string {}
286
+ }
287
+ a [osdkHandler .NamespacedNameAnnotation ] = strings .Join ([]string {owner .Namespace , owner .Name }, "/" )
288
+ a [osdkHandler .TypeAnnotation ] = fmt .Sprintf ("%v.%v" , owner .Kind , ownerGV .Group )
289
+
290
+ data .SetAnnotations (a )
291
+ }
252
292
newBody , err := json .Marshal (data .Object )
253
293
if err != nil {
254
294
m := "Could not serialize body"
@@ -269,7 +309,7 @@ func InjectOwnerReferenceHandler(h http.Handler, cMap *controllermap.ControllerM
269
309
_ , allNsPresent := watchedNamespaces [metav1 .NamespaceAll ]
270
310
_ , reqNsPresent := watchedNamespaces [r .Namespace ]
271
311
if allNsPresent || reqNsPresent {
272
- err = addWatchToController (owner , cMap , data , restMapper )
312
+ err = addWatchToController (owner , cMap , data , restMapper , addOwnerRef )
273
313
if err != nil {
274
314
m := "could not add watch to controller"
275
315
log .Error (err , m )
@@ -289,6 +329,39 @@ func removeAuthorizationHeader(h http.Handler) http.Handler {
289
329
})
290
330
}
291
331
332
+ func shouldAddOwnerRef (data * unstructured.Unstructured , owner kubeconfig.NamespacedOwnerReference , restMapper meta.RESTMapper ) (bool , error ) {
333
+ dataMapping , err := restMapper .RESTMapping (data .GroupVersionKind ().GroupKind (), data .GroupVersionKind ().Version )
334
+ if err != nil {
335
+ m := fmt .Sprintf ("Could not get rest mapping for: %v" , data .GroupVersionKind ())
336
+ log .Error (err , m )
337
+ return false , err
338
+
339
+ }
340
+ // We need to determine whether or not the owner is a cluster-scoped
341
+ // resource because enqueue based on an owner reference does not work if
342
+ // a namespaced resource owns a cluster-scoped resource
343
+ ownerGV , err := schema .ParseGroupVersion (owner .APIVersion )
344
+ if err != nil {
345
+ m := fmt .Sprintf ("could not get group version for: %v" , owner )
346
+ log .Error (err , m )
347
+ return false , err
348
+ }
349
+ ownerMapping , err := restMapper .RESTMapping (schema.GroupKind {Kind : owner .Kind , Group : ownerGV .Group }, ownerGV .Version )
350
+ if err != nil {
351
+ m := fmt .Sprintf ("could not get rest mapping for: %v" , owner )
352
+ log .Error (err , m )
353
+ return false , err
354
+ }
355
+
356
+ dataNamespaceScoped := dataMapping .Scope .Name () != meta .RESTScopeNameRoot
357
+ ownerNamespaceScoped := ownerMapping .Scope .Name () != meta .RESTScopeNameRoot
358
+
359
+ if dataNamespaceScoped && ownerNamespaceScoped && data .GetNamespace () == owner .Namespace {
360
+ return true , nil
361
+ }
362
+ return false , nil
363
+ }
364
+
292
365
// RequestLogHandler - log the requests that come through the proxy.
293
366
func RequestLogHandler (h http.Handler ) http.Handler {
294
367
return http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
@@ -399,17 +472,14 @@ func Run(done chan error, o Options) error {
399
472
return nil
400
473
}
401
474
402
- func addWatchToController (owner kubeconfig.NamespacedOwnerReference , cMap * controllermap.ControllerMap , resource * unstructured.Unstructured , restMapper meta.RESTMapper ) error {
475
+ func addWatchToController (owner kubeconfig.NamespacedOwnerReference , cMap * controllermap.ControllerMap , resource * unstructured.Unstructured , restMapper meta.RESTMapper , useOwnerRef bool ) error {
403
476
dataMapping , err := restMapper .RESTMapping (resource .GroupVersionKind ().GroupKind (), resource .GroupVersionKind ().Version )
404
477
if err != nil {
405
478
m := fmt .Sprintf ("Could not get rest mapping for: %v" , resource .GroupVersionKind ())
406
479
log .Error (err , m )
407
480
return err
408
481
409
482
}
410
- // We need to determine whether or not the owner is a cluster-scoped
411
- // resource because enqueue based on an owner reference does not work if
412
- // a namespaced resource owns a cluster-scoped resource
413
483
ownerGV , err := schema .ParseGroupVersion (owner .APIVersion )
414
484
if err != nil {
415
485
m := fmt .Sprintf ("could not get broup version for: %v" , owner )
@@ -424,59 +494,43 @@ func addWatchToController(owner kubeconfig.NamespacedOwnerReference, cMap *contr
424
494
}
425
495
426
496
dataNamespaceScoped := dataMapping .Scope .Name () != meta .RESTScopeNameRoot
427
- ownerNamespaceScoped := ownerMapping .Scope .Name () != meta .RESTScopeNameRoot
428
- useOwnerReference := ! ownerNamespaceScoped || dataNamespaceScoped
429
497
contents , ok := cMap .Get (ownerMapping .GroupVersionKind )
430
498
if ! ok {
431
499
return errors .New ("failed to find controller in map" )
432
500
}
433
- wMap := contents .WatchMap
434
- uMap := contents .UIDMap
501
+ owMap := contents .OwnerWatchMap
502
+ awMap := contents .AnnotationWatchMap
435
503
u := & unstructured.Unstructured {}
436
504
u .SetGroupVersionKind (ownerMapping .GroupVersionKind )
437
505
// Add a watch to controller
438
506
if contents .WatchDependentResources {
439
- // Store UID
440
- uMap .Store (owner .UID , types.NamespacedName {
441
- Name : owner .Name ,
442
- Namespace : owner .Namespace ,
443
- })
444
- _ , exists := wMap .Get (resource .GroupVersionKind ())
445
- // If already watching resource no need to add a new watch
446
- if exists {
447
- return nil
448
- }
449
507
// Store watch in map
450
- wMap .Store (resource .GroupVersionKind ())
451
508
// Use EnqueueRequestForOwner unless user has configured watching cluster scoped resources and we have to
452
- if useOwnerReference {
509
+ switch {
510
+ case useOwnerRef :
511
+ _ , exists := owMap .Get (resource .GroupVersionKind ())
512
+ // If already watching resource no need to add a new watch
513
+ if exists {
514
+ return nil
515
+ }
516
+
517
+ owMap .Store (resource .GroupVersionKind ())
453
518
log .Info ("Watching child resource" , "kind" , resource .GroupVersionKind (), "enqueue_kind" , u .GroupVersionKind ())
454
519
// Store watch in map
455
- err = contents .Controller .Watch (& source.Kind {Type : resource }, & handler.EnqueueRequestForOwner {OwnerType : u })
520
+ err : = contents .Controller .Watch (& source.Kind {Type : resource }, & handler.EnqueueRequestForOwner {OwnerType : u })
456
521
if err != nil {
457
522
return err
458
523
}
459
- } else if contents .WatchClusterScopedResources {
460
- log .Info ("Watching child resource which can be cluster-scoped" , "kind" , resource .GroupVersionKind (), "enqueue_kind" , u .GroupVersionKind ())
461
- // Add watch
462
- err = contents .Controller .Watch (
463
- & source.Kind {Type : resource },
464
- // Use Map func since EnqueuRequestForOwner won't work
465
- & handler.EnqueueRequestsFromMapFunc {ToRequests : handler .ToRequestsFunc (func (a handler.MapObject ) []reconcile.Request {
466
- log .V (2 ).Info ("Creating reconcile request from object" , "gvk" , ownerMapping .GroupVersionKind , "name" , a .Meta .GetName ())
467
- ownRefs := a .Meta .GetOwnerReferences ()
468
- for _ , ref := range ownRefs {
469
- nn , exists := uMap .Get (ref .UID )
470
- if ! exists {
471
- continue
472
- }
473
- return []reconcile.Request {
474
- {NamespacedName : nn },
475
- }
476
- }
477
- return nil
478
- })},
479
- )
524
+ case (! useOwnerRef && dataNamespaceScoped ) || contents .WatchClusterScopedResources :
525
+ _ , exists := awMap .Get (resource .GroupVersionKind ())
526
+ // If already watching resource no need to add a new watch
527
+ if exists {
528
+ return nil
529
+ }
530
+ awMap .Store (resource .GroupVersionKind ())
531
+ typeString := fmt .Sprintf ("%v.%v" , owner .Kind , ownerGV .Group )
532
+ log .Info ("Watching child resource" , "kind" , resource .GroupVersionKind (), "enqueue_annotation_type" , typeString )
533
+ err = contents .Controller .Watch (& source.Kind {Type : resource }, & osdkHandler.EnqueueRequestForAnnotation {Type : typeString })
480
534
if err != nil {
481
535
return err
482
536
}
0 commit comments