github.imxd.top/operator-framework/operator-sdk@v0.8.2/pkg/handler/enqueue_annotation.go (about) 1 // Copyright 2019 The Operator-SDK Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package handler 16 17 import ( 18 "strings" 19 20 "k8s.io/apimachinery/pkg/api/meta" 21 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 "k8s.io/apimachinery/pkg/types" 23 "k8s.io/client-go/util/workqueue" 24 "sigs.k8s.io/controller-runtime/pkg/event" 25 crtHandler "sigs.k8s.io/controller-runtime/pkg/handler" 26 "sigs.k8s.io/controller-runtime/pkg/reconcile" 27 logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" 28 ) 29 30 var log = logf.Log.WithName("event_handler") 31 32 const ( 33 // NamespacedNameAnnotation - annotation that will be used to get the primary resource namespaced name. 34 NamespacedNameAnnotation = "operator-sdk/primary-resource" 35 // TypeAnnotation - annotation that will be used to verify that the primary resource is the primary resource to use. 36 TypeAnnotation = "operator-sdk/primary-resource-type" 37 ) 38 39 // EnqueueRequestForAnnotation enqueues Requests based on the presence of an annotation that contains the 40 // namespaced name of the primary resource. 41 // 42 // The primary usecase for this, is to have a controller enqueue requests for the following scenarios 43 // 1. namespaced primary object and dependent cluster scoped resource 44 // 2. cluster scoped primary object. 45 // 3. namespaced primary object and dependent namespaced scoped but in a different namespace object. 46 type EnqueueRequestForAnnotation struct { 47 Type string 48 49 mapper meta.RESTMapper 50 } 51 52 var _ crtHandler.EventHandler = &EnqueueRequestForAnnotation{} 53 54 // Create implements EventHandler 55 func (e *EnqueueRequestForAnnotation) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) { 56 if ok, req := e.getAnnotationRequests(evt.Meta); ok { 57 q.Add(req) 58 } 59 } 60 61 // Update implements EventHandler 62 func (e *EnqueueRequestForAnnotation) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) { 63 if ok, req := e.getAnnotationRequests(evt.MetaOld); ok { 64 q.Add(req) 65 } 66 if ok, req := e.getAnnotationRequests(evt.MetaNew); ok { 67 q.Add(req) 68 } 69 } 70 71 // Delete implements EventHandler 72 func (e *EnqueueRequestForAnnotation) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) { 73 if ok, req := e.getAnnotationRequests(evt.Meta); ok { 74 q.Add(req) 75 } 76 } 77 78 // Generic implements EventHandler 79 func (e *EnqueueRequestForAnnotation) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) { 80 if ok, req := e.getAnnotationRequests(evt.Meta); ok { 81 q.Add(req) 82 } 83 } 84 85 func (e *EnqueueRequestForAnnotation) getAnnotationRequests(object metav1.Object) (bool, reconcile.Request) { 86 if typeString, ok := object.GetAnnotations()[TypeAnnotation]; ok && typeString == e.Type { 87 namespacedNameString, ok := object.GetAnnotations()[NamespacedNameAnnotation] 88 if !ok { 89 log.Info("Unable to find namespaced name annotation for resource", "resource", object) 90 } 91 if namespacedNameString == "" { 92 return false, reconcile.Request{} 93 } 94 nsn := parseNamespacedName(namespacedNameString) 95 return true, reconcile.Request{NamespacedName: nsn} 96 } 97 return false, reconcile.Request{} 98 } 99 100 func parseNamespacedName(namespacedNameString string) types.NamespacedName { 101 values := strings.Split(namespacedNameString, "/") 102 if len(values) == 1 { 103 return types.NamespacedName{ 104 Name: values[0], 105 Namespace: "", 106 } 107 } 108 if len(values) >= 2 { 109 return types.NamespacedName{ 110 Name: values[1], 111 Namespace: values[0], 112 } 113 } 114 return types.NamespacedName{} 115 }