knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/webhook/resourcesemantics/defaulting/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 defaulting
    18  
    19  import (
    20  	"context"
    21  
    22  	// Injection stuff
    23  	kubeclient "knative.dev/pkg/client/injection/kube/client"
    24  	mwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration"
    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  
    33  	"knative.dev/pkg/controller"
    34  	"knative.dev/pkg/system"
    35  	"knative.dev/pkg/webhook"
    36  	"knative.dev/pkg/webhook/resourcesemantics"
    37  )
    38  
    39  // NewAdmissionController constructs a reconciler
    40  func NewAdmissionController(
    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  	// This not ideal, we are using a variadic argument to effectively make callbacks optional
    49  	// This allows this addition to be non-breaking to consumers of /pkg
    50  	// TODO: once all sub-repos have adopted this, we might move this back to a traditional param.
    51  	var unwrappedCallbacks map[schema.GroupVersionKind]Callback
    52  	switch len(callbacks) {
    53  	case 0:
    54  		unwrappedCallbacks = map[schema.GroupVersionKind]Callback{}
    55  	case 1:
    56  		unwrappedCallbacks = callbacks[0]
    57  	default:
    58  		panic("NewAdmissionController may not be called with multiple callback maps")
    59  	}
    60  
    61  	opts := []OptionFunc{
    62  		WithPath(path),
    63  		WithTypes(handlers),
    64  		WithWrapContext(wc),
    65  		WithCallbacks(unwrappedCallbacks),
    66  	}
    67  
    68  	if disallowUnknownFields {
    69  		opts = append(opts, WithDisallowUnknownFields())
    70  	}
    71  
    72  	return newController(ctx, name, opts...)
    73  }
    74  
    75  func newController(ctx context.Context, name string, optsFunc ...OptionFunc) *controller.Impl {
    76  	client := kubeclient.Get(ctx)
    77  	mwhInformer := mwhinformer.Get(ctx)
    78  	secretInformer := secretinformer.Get(ctx)
    79  
    80  	opts := &options{}
    81  	wopts := webhook.GetOptions(ctx)
    82  
    83  	for _, f := range optsFunc {
    84  		f(opts)
    85  	}
    86  
    87  	// if this environment variable is set, it overrides the value in the Options
    88  	disableNamespaceOwnership := webhook.DisableNamespaceOwnershipFromEnv()
    89  	if disableNamespaceOwnership != nil {
    90  		wopts.DisableNamespaceOwnership = *disableNamespaceOwnership
    91  	}
    92  
    93  	key := types.NamespacedName{Name: name}
    94  
    95  	wh := &reconciler{
    96  		LeaderAwareFuncs: pkgreconciler.LeaderAwareFuncs{
    97  			// Have this reconciler enqueue our singleton whenever it becomes leader.
    98  			PromoteFunc: func(bkt pkgreconciler.Bucket, enq func(pkgreconciler.Bucket, types.NamespacedName)) error {
    99  				enq(bkt, key)
   100  				return nil
   101  			},
   102  		},
   103  
   104  		key:       key,
   105  		path:      opts.path,
   106  		handlers:  opts.types,
   107  		callbacks: opts.callbacks,
   108  
   109  		withContext:               opts.wc,
   110  		disallowUnknownFields:     opts.disallowUnknownFields,
   111  		secretName:                wopts.SecretName,
   112  		disableNamespaceOwnership: wopts.DisableNamespaceOwnership,
   113  
   114  		client:       client,
   115  		mwhlister:    mwhInformer.Lister(),
   116  		secretlister: secretInformer.Lister(),
   117  	}
   118  
   119  	logger := logging.FromContext(ctx)
   120  	controllerOptions := wopts.ControllerOptions
   121  	if controllerOptions == nil {
   122  		const queueName = "DefaultingWebhook"
   123  		controllerOptions = &controller.ControllerOptions{WorkQueueName: queueName, Logger: logger.Named(queueName)}
   124  	}
   125  	c := controller.NewContext(ctx, wh, *controllerOptions)
   126  
   127  	// Reconcile when the named MutatingWebhookConfiguration changes.
   128  	mwhInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
   129  		FilterFunc: controller.FilterWithName(name),
   130  		// It doesn't matter what we enqueue because we will always Reconcile
   131  		// the named MWH resource.
   132  		Handler: controller.HandleAll(c.Enqueue),
   133  	})
   134  
   135  	// Reconcile when the cert bundle changes.
   136  	secretInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
   137  		FilterFunc: controller.FilterWithNameAndNamespace(system.Namespace(), wh.secretName),
   138  		// It doesn't matter what we enqueue because we will always Reconcile
   139  		// the named MWH resource.
   140  		Handler: controller.HandleAll(c.Enqueue),
   141  	})
   142  
   143  	return c
   144  }