knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/webhook/resourcesemantics/validation/controller.go (about) 1 /* 2 Copyright 2019 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package validation 18 19 import ( 20 "context" 21 22 // Injection stuff 23 kubeclient "knative.dev/pkg/client/injection/kube/client" 24 vwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/validatingwebhookconfiguration" 25 secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret" 26 "knative.dev/pkg/logging" 27 pkgreconciler "knative.dev/pkg/reconciler" 28 29 "k8s.io/apimachinery/pkg/runtime/schema" 30 "k8s.io/apimachinery/pkg/types" 31 "k8s.io/client-go/tools/cache" 32 "knative.dev/pkg/controller" 33 "knative.dev/pkg/system" 34 "knative.dev/pkg/webhook" 35 "knative.dev/pkg/webhook/resourcesemantics" 36 ) 37 38 // NewAdmissionControllerWithConfig constructs a reconciler and registers the 39 // provided handlers with specified verbs and SubResources 40 func NewAdmissionControllerWithConfig( 41 ctx context.Context, 42 name, path string, 43 handlers map[schema.GroupVersionKind]resourcesemantics.GenericCRD, 44 wc func(context.Context) context.Context, 45 disallowUnknownFields bool, 46 callbacks map[schema.GroupVersionKind]Callback, 47 ) *controller.Impl { 48 opts := []OptionFunc{ 49 WithPath(path), 50 WithTypes(handlers), 51 WithWrapContext(wc), 52 WithCallbacks(callbacks), 53 } 54 55 if disallowUnknownFields { 56 opts = append(opts, WithDisallowUnknownFields()) 57 } 58 return newController(ctx, name, opts...) 59 } 60 61 func newController(ctx context.Context, name string, optsFunc ...OptionFunc) *controller.Impl { 62 client := kubeclient.Get(ctx) 63 vwhInformer := vwhinformer.Get(ctx) 64 secretInformer := secretinformer.Get(ctx) 65 woptions := webhook.GetOptions(ctx) 66 67 opts := &options{} 68 69 for _, f := range optsFunc { 70 f(opts) 71 } 72 73 // if this environment variable is set, it overrides the value in the Options 74 disableNamespaceOwnership := webhook.DisableNamespaceOwnershipFromEnv() 75 if disableNamespaceOwnership != nil { 76 woptions.DisableNamespaceOwnership = *disableNamespaceOwnership 77 } 78 79 wh := &reconciler{ 80 LeaderAwareFuncs: pkgreconciler.LeaderAwareFuncs{ 81 // Have this reconciler enqueue our singleton whenever it becomes leader. 82 PromoteFunc: func(bkt pkgreconciler.Bucket, enq func(pkgreconciler.Bucket, types.NamespacedName)) error { 83 enq(bkt, types.NamespacedName{Name: name}) 84 return nil 85 }, 86 }, 87 88 key: types.NamespacedName{ 89 Name: name, 90 }, 91 path: opts.path, 92 handlers: opts.types, 93 callbacks: opts.callbacks, 94 95 withContext: opts.wc, 96 disallowUnknownFields: opts.DisallowUnknownFields(), 97 secretName: woptions.SecretName, 98 disableNamespaceOwnership: woptions.DisableNamespaceOwnership, 99 100 client: client, 101 vwhlister: vwhInformer.Lister(), 102 secretlister: secretInformer.Lister(), 103 } 104 105 logger := logging.FromContext(ctx) 106 107 controllerOptions := woptions.ControllerOptions 108 if woptions.ControllerOptions == nil { 109 const queueName = "ValidationWebhook" 110 controllerOptions = &controller.ControllerOptions{WorkQueueName: queueName, Logger: logger.Named(queueName)} 111 } 112 c := controller.NewContext(ctx, wh, *controllerOptions) 113 114 // Reconcile when the named ValidatingWebhookConfiguration changes. 115 vwhInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ 116 FilterFunc: controller.FilterWithName(name), 117 // It doesn't matter what we enqueue because we will always Reconcile 118 // the named VWH resource. 119 Handler: controller.HandleAll(c.Enqueue), 120 }) 121 122 // Reconcile when the cert bundle changes. 123 secretInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ 124 FilterFunc: controller.FilterWithNameAndNamespace(system.Namespace(), wh.secretName), 125 // It doesn't matter what we enqueue because we will always Reconcile 126 // the named VWH resource. 127 Handler: controller.HandleAll(c.Enqueue), 128 }) 129 130 return c 131 } 132 133 // NewAdmissionController constructs a reconciler 134 func NewAdmissionController( 135 ctx context.Context, 136 name, path string, 137 handlers map[schema.GroupVersionKind]resourcesemantics.GenericCRD, 138 wc func(context.Context) context.Context, 139 disallowUnknownFields bool, 140 callbacks ...map[schema.GroupVersionKind]Callback, 141 ) *controller.Impl { 142 // This not ideal, we are using a variadic argument to effectively make callbacks optional 143 // This allows this addition to be non-breaking to consumers of /pkg 144 // TODO: once all sub-repos have adopted this, we might move this back to a traditional param. 145 var unwrappedCallbacks map[schema.GroupVersionKind]Callback 146 switch len(callbacks) { 147 case 0: 148 unwrappedCallbacks = map[schema.GroupVersionKind]Callback{} 149 case 1: 150 unwrappedCallbacks = callbacks[0] 151 default: 152 panic("NewAdmissionController may not be called with multiple callback maps") 153 } 154 return NewAdmissionControllerWithConfig(ctx, name, path, handlers, wc, disallowUnknownFields, unwrappedCallbacks) 155 }