update dependencies (#6267)

Signed-off-by: hongming <coder.scala@gmail.com>
This commit is contained in:
hongming
2024-11-06 10:27:06 +08:00
committed by GitHub
parent faf255a084
commit cfebd96a1f
4263 changed files with 341374 additions and 132036 deletions

View File

@@ -19,6 +19,7 @@ package builder
import (
"errors"
"fmt"
"reflect"
"strings"
"github.com/go-logr/logr"
@@ -30,17 +31,12 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
internalsource "sigs.k8s.io/controller-runtime/pkg/internal/source"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)
// Supporting mocking out functions for testing.
var newController = controller.New
var getGvk = apiutil.GVKForObject
// project represents other forms that we can use to
// send/receive a given resource (metadata-only, unstructured, etc).
type objectProjection int
@@ -53,20 +49,32 @@ const (
)
// Builder builds a Controller.
type Builder struct {
type Builder = TypedBuilder[reconcile.Request]
// TypedBuilder builds a Controller. The request is the request type
// that is passed to the workqueue and then to the Reconciler.
// The workqueue de-duplicates identical requests.
type TypedBuilder[request comparable] struct {
forInput ForInput
ownsInput []OwnsInput
watchesInput []WatchesInput
rawSources []source.TypedSource[request]
watchesInput []WatchesInput[request]
mgr manager.Manager
globalPredicates []predicate.Predicate
ctrl controller.Controller
ctrlOptions controller.Options
ctrl controller.TypedController[request]
ctrlOptions controller.TypedOptions[request]
name string
newController func(name string, mgr manager.Manager, options controller.TypedOptions[request]) (controller.TypedController[request], error)
}
// ControllerManagedBy returns a new controller builder that will be started by the provided Manager.
func ControllerManagedBy(m manager.Manager) *Builder {
return &Builder{mgr: m}
return TypedControllerManagedBy[reconcile.Request](m)
}
// TypedControllerManagedBy returns a new typed controller builder that will be started by the provided Manager.
func TypedControllerManagedBy[request comparable](m manager.Manager) *TypedBuilder[request] {
return &TypedBuilder[request]{mgr: m}
}
// ForInput represents the information set by the For method.
@@ -79,9 +87,10 @@ type ForInput struct {
// For defines the type of Object being *reconciled*, and configures the ControllerManagedBy to respond to create / delete /
// update events by *reconciling the object*.
//
// This is the equivalent of calling
// Watches(&source.Kind{Type: apiType}, &handler.EnqueueRequestForObject{}).
func (blder *Builder) For(object client.Object, opts ...ForOption) *Builder {
// Watches(source.Kind(cache, &Type{}, &handler.EnqueueRequestForObject{})).
func (blder *TypedBuilder[request]) For(object client.Object, opts ...ForOption) *TypedBuilder[request] {
if blder.forInput.object != nil {
blder.forInput.err = fmt.Errorf("For(...) should only be called once, could not assign multiple objects for reconciliation")
return blder
@@ -110,8 +119,8 @@ type OwnsInput struct {
// Use Owns(object, builder.MatchEveryOwner) to reconcile all owners.
//
// By default, this is the equivalent of calling
// Watches(object, handler.EnqueueRequestForOwner([...], ownerType, OnlyControllerOwner())).
func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder {
// Watches(source.Kind(cache, &Type{}, handler.EnqueueRequestForOwner([...], &OwnerType{}, OnlyControllerOwner()))).
func (blder *TypedBuilder[request]) Owns(object client.Object, opts ...OwnsOption) *TypedBuilder[request] {
input := OwnsInput{object: object}
for _, opt := range opts {
opt.ApplyToOwns(&input)
@@ -121,22 +130,48 @@ func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder {
return blder
}
type untypedWatchesInput interface {
setPredicates([]predicate.Predicate)
setObjectProjection(objectProjection)
}
// WatchesInput represents the information set by Watches method.
type WatchesInput struct {
src source.Source
eventHandler handler.EventHandler
type WatchesInput[request comparable] struct {
obj client.Object
handler handler.TypedEventHandler[client.Object, request]
predicates []predicate.Predicate
objectProjection objectProjection
}
func (w *WatchesInput[request]) setPredicates(predicates []predicate.Predicate) {
w.predicates = predicates
}
func (w *WatchesInput[request]) setObjectProjection(objectProjection objectProjection) {
w.objectProjection = objectProjection
}
// Watches defines the type of Object to watch, and configures the ControllerManagedBy to respond to create / delete /
// update events by *reconciling the object* with the given EventHandler.
//
// This is the equivalent of calling
// WatchesRawSource(source.Kind(cache, object), eventHandler, opts...).
func (blder *Builder) Watches(object client.Object, eventHandler handler.EventHandler, opts ...WatchesOption) *Builder {
src := source.Kind(blder.mgr.GetCache(), object)
return blder.WatchesRawSource(src, eventHandler, opts...)
// WatchesRawSource(source.Kind(cache, object, eventHandler, predicates...)).
func (blder *TypedBuilder[request]) Watches(
object client.Object,
eventHandler handler.TypedEventHandler[client.Object, request],
opts ...WatchesOption,
) *TypedBuilder[request] {
input := WatchesInput[request]{
obj: object,
handler: eventHandler,
}
for _, opt := range opts {
opt.ApplyToWatches(&input)
}
blder.watchesInput = append(blder.watchesInput, input)
return blder
}
// WatchesMetadata is the same as Watches, but forces the internal cache to only watch PartialObjectMetadata.
@@ -166,43 +201,45 @@ func (blder *Builder) Watches(object client.Object, eventHandler handler.EventHa
// In the first case, controller-runtime will create another cache for the
// concrete type on top of the metadata cache; this increases memory
// consumption and leads to race conditions as caches are not in sync.
func (blder *Builder) WatchesMetadata(object client.Object, eventHandler handler.EventHandler, opts ...WatchesOption) *Builder {
func (blder *TypedBuilder[request]) WatchesMetadata(
object client.Object,
eventHandler handler.TypedEventHandler[client.Object, request],
opts ...WatchesOption,
) *TypedBuilder[request] {
opts = append(opts, OnlyMetadata)
return blder.Watches(object, eventHandler, opts...)
}
// WatchesRawSource exposes the lower-level ControllerManagedBy Watches functions through the builder.
// Specified predicates are registered only for given source.
//
// STOP! Consider using For(...), Owns(...), Watches(...), WatchesMetadata(...) instead.
// This method is only exposed for more advanced use cases, most users should use one of the higher level functions.
func (blder *Builder) WatchesRawSource(src source.Source, eventHandler handler.EventHandler, opts ...WatchesOption) *Builder {
input := WatchesInput{src: src, eventHandler: eventHandler}
for _, opt := range opts {
opt.ApplyToWatches(&input)
}
// WatchesRawSource does not respect predicates configured through WithEventFilter.
//
// WatchesRawSource makes it possible to use typed handlers and predicates with `source.Kind` as well as custom source implementations.
func (blder *TypedBuilder[request]) WatchesRawSource(src source.TypedSource[request]) *TypedBuilder[request] {
blder.rawSources = append(blder.rawSources, src)
blder.watchesInput = append(blder.watchesInput, input)
return blder
}
// WithEventFilter sets the event filters, to filter which create/update/delete/generic events eventually
// trigger reconciliations. For example, filtering on whether the resource version has changed.
// Given predicate is added for all watched objects.
// Given predicate is added for all watched objects and thus must be able to deal with the type
// of all watched objects.
//
// Defaults to the empty list.
func (blder *Builder) WithEventFilter(p predicate.Predicate) *Builder {
func (blder *TypedBuilder[request]) WithEventFilter(p predicate.Predicate) *TypedBuilder[request] {
blder.globalPredicates = append(blder.globalPredicates, p)
return blder
}
// WithOptions overrides the controller options used in doController. Defaults to empty.
func (blder *Builder) WithOptions(options controller.Options) *Builder {
func (blder *TypedBuilder[request]) WithOptions(options controller.TypedOptions[request]) *TypedBuilder[request] {
blder.ctrlOptions = options
return blder
}
// WithLogConstructor overrides the controller options's LogConstructor.
func (blder *Builder) WithLogConstructor(logConstructor func(*reconcile.Request) logr.Logger) *Builder {
func (blder *TypedBuilder[request]) WithLogConstructor(logConstructor func(*request) logr.Logger) *TypedBuilder[request] {
blder.ctrlOptions.LogConstructor = logConstructor
return blder
}
@@ -212,19 +249,21 @@ func (blder *Builder) WithLogConstructor(logConstructor func(*reconcile.Request)
// (underscores and alphanumeric characters only).
//
// By default, controllers are named using the lowercase version of their kind.
func (blder *Builder) Named(name string) *Builder {
//
// The name must be unique as it is used to identify the controller in metrics and logs.
func (blder *TypedBuilder[request]) Named(name string) *TypedBuilder[request] {
blder.name = name
return blder
}
// Complete builds the Application Controller.
func (blder *Builder) Complete(r reconcile.Reconciler) error {
func (blder *TypedBuilder[request]) Complete(r reconcile.TypedReconciler[request]) error {
_, err := blder.Build(r)
return err
}
// Build builds the Application Controller and returns the Controller it created.
func (blder *Builder) Build(r reconcile.Reconciler) (controller.Controller, error) {
func (blder *TypedBuilder[request]) Build(r reconcile.TypedReconciler[request]) (controller.TypedController[request], error) {
if r == nil {
return nil, fmt.Errorf("must provide a non-nil Reconciler")
}
@@ -248,13 +287,13 @@ func (blder *Builder) Build(r reconcile.Reconciler) (controller.Controller, erro
return blder.ctrl, nil
}
func (blder *Builder) project(obj client.Object, proj objectProjection) (client.Object, error) {
func (blder *TypedBuilder[request]) project(obj client.Object, proj objectProjection) (client.Object, error) {
switch proj {
case projectAsNormal:
return obj, nil
case projectAsMetadata:
metaObj := &metav1.PartialObjectMetadata{}
gvk, err := getGvk(obj, blder.mgr.GetScheme())
gvk, err := apiutil.GVKForObject(obj, blder.mgr.GetScheme())
if err != nil {
return nil, fmt.Errorf("unable to determine GVK of %T for a metadata-only watch: %w", obj, err)
}
@@ -265,18 +304,24 @@ func (blder *Builder) project(obj client.Object, proj objectProjection) (client.
}
}
func (blder *Builder) doWatch() error {
func (blder *TypedBuilder[request]) doWatch() error {
// Reconcile type
if blder.forInput.object != nil {
obj, err := blder.project(blder.forInput.object, blder.forInput.objectProjection)
if err != nil {
return err
}
src := source.Kind(blder.mgr.GetCache(), obj)
hdler := &handler.EnqueueRequestForObject{}
if reflect.TypeFor[request]() != reflect.TypeOf(reconcile.Request{}) {
return fmt.Errorf("For() can only be used with reconcile.Request, got %T", *new(request))
}
var hdler handler.TypedEventHandler[client.Object, request]
reflect.ValueOf(&hdler).Elem().Set(reflect.ValueOf(&handler.EnqueueRequestForObject{}))
allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
allPredicates = append(allPredicates, blder.forInput.predicates...)
if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
src := source.TypedKind(blder.mgr.GetCache(), obj, hdler, allPredicates...)
if err := blder.ctrl.Watch(src); err != nil {
return err
}
}
@@ -290,46 +335,49 @@ func (blder *Builder) doWatch() error {
if err != nil {
return err
}
src := source.Kind(blder.mgr.GetCache(), obj)
opts := []handler.OwnerOption{}
if !own.matchEveryOwner {
opts = append(opts, handler.OnlyControllerOwner())
}
hdler := handler.EnqueueRequestForOwner(
var hdler handler.TypedEventHandler[client.Object, request]
reflect.ValueOf(&hdler).Elem().Set(reflect.ValueOf(handler.EnqueueRequestForOwner(
blder.mgr.GetScheme(), blder.mgr.GetRESTMapper(),
blder.forInput.object,
opts...,
)
)))
allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
allPredicates = append(allPredicates, own.predicates...)
if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
src := source.TypedKind(blder.mgr.GetCache(), obj, hdler, allPredicates...)
if err := blder.ctrl.Watch(src); err != nil {
return err
}
}
// Do the watch requests
if len(blder.watchesInput) == 0 && blder.forInput.object == nil {
return errors.New("there are no watches configured, controller will never get triggered. Use For(), Owns() or Watches() to set them up")
if len(blder.watchesInput) == 0 && blder.forInput.object == nil && len(blder.rawSources) == 0 {
return errors.New("there are no watches configured, controller will never get triggered. Use For(), Owns(), Watches() or WatchesRawSource() to set them up")
}
for _, w := range blder.watchesInput {
// If the source of this watch is of type Kind, project it.
if srcKind, ok := w.src.(*internalsource.Kind); ok {
typeForSrc, err := blder.project(srcKind.Type, w.objectProjection)
if err != nil {
return err
}
srcKind.Type = typeForSrc
projected, err := blder.project(w.obj, w.objectProjection)
if err != nil {
return fmt.Errorf("failed to project for %T: %w", w.obj, err)
}
allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
allPredicates = append(allPredicates, w.predicates...)
if err := blder.ctrl.Watch(w.src, w.eventHandler, allPredicates...); err != nil {
if err := blder.ctrl.Watch(source.TypedKind(blder.mgr.GetCache(), projected, w.handler, allPredicates...)); err != nil {
return err
}
}
for _, src := range blder.rawSources {
if err := blder.ctrl.Watch(src); err != nil {
return err
}
}
return nil
}
func (blder *Builder) getControllerName(gvk schema.GroupVersionKind, hasGVK bool) (string, error) {
func (blder *TypedBuilder[request]) getControllerName(gvk schema.GroupVersionKind, hasGVK bool) (string, error) {
if blder.name != "" {
return blder.name, nil
}
@@ -339,7 +387,7 @@ func (blder *Builder) getControllerName(gvk schema.GroupVersionKind, hasGVK bool
return strings.ToLower(gvk.Kind), nil
}
func (blder *Builder) doController(r reconcile.Reconciler) error {
func (blder *TypedBuilder[request]) doController(r reconcile.TypedReconciler[request]) error {
globalOpts := blder.mgr.GetControllerOptions()
ctrlOptions := blder.ctrlOptions
@@ -356,7 +404,7 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
hasGVK := blder.forInput.object != nil
if hasGVK {
var err error
gvk, err = getGvk(blder.forInput.object, blder.mgr.GetScheme())
gvk, err = apiutil.GVKForObject(blder.forInput.object, blder.mgr.GetScheme())
if err != nil {
return err
}
@@ -393,9 +441,10 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
)
}
ctrlOptions.LogConstructor = func(req *reconcile.Request) logr.Logger {
ctrlOptions.LogConstructor = func(in *request) logr.Logger {
log := log
if req != nil {
if req, ok := any(in).(*reconcile.Request); ok && req != nil {
if hasGVK {
log = log.WithValues(gvk.Kind, klog.KRef(req.Namespace, req.Name))
}
@@ -407,7 +456,11 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
}
}
if blder.newController == nil {
blder.newController = controller.NewTyped[request]
}
// Build the controller and return.
blder.ctrl, err = newController(controllerName, blder.mgr, ctrlOptions)
blder.ctrl, err = blder.newController(controllerName, blder.mgr, ctrlOptions)
return err
}

View File

@@ -37,7 +37,7 @@ type OwnsOption interface {
// WatchesOption is some configuration that modifies options for a watches request.
type WatchesOption interface {
// ApplyToWatches applies this configuration to the given watches options.
ApplyToWatches(*WatchesInput)
ApplyToWatches(untypedWatchesInput)
}
// }}}
@@ -67,8 +67,8 @@ func (w Predicates) ApplyToOwns(opts *OwnsInput) {
}
// ApplyToWatches applies this configuration to the given WatchesInput options.
func (w Predicates) ApplyToWatches(opts *WatchesInput) {
opts.predicates = w.predicates
func (w Predicates) ApplyToWatches(opts untypedWatchesInput) {
opts.setPredicates(w.predicates)
}
var _ ForOption = &Predicates{}
@@ -95,8 +95,8 @@ func (p projectAs) ApplyToOwns(opts *OwnsInput) {
}
// ApplyToWatches applies this configuration to the given WatchesInput options.
func (p projectAs) ApplyToWatches(opts *WatchesInput) {
opts.objectProjection = objectProjection(p)
func (p projectAs) ApplyToWatches(opts untypedWatchesInput) {
opts.setObjectProjection(objectProjection(p))
}
var (

View File

@@ -42,8 +42,9 @@ type WebhookBuilder struct {
gvk schema.GroupVersionKind
mgr manager.Manager
config *rest.Config
recoverPanic bool
recoverPanic *bool
logConstructor func(base logr.Logger, req *admission.Request) logr.Logger
err error
}
// WebhookManagedBy returns a new webhook builder.
@@ -57,6 +58,9 @@ func WebhookManagedBy(m manager.Manager) *WebhookBuilder {
// If the given object implements the admission.Defaulter interface, a MutatingWebhook will be wired for this type.
// If the given object implements the admission.Validator interface, a ValidatingWebhook will be wired for this type.
func (blder *WebhookBuilder) For(apiType runtime.Object) *WebhookBuilder {
if blder.apiType != nil {
blder.err = errors.New("For(...) should only be called once, could not assign multiple objects for webhook registration")
}
blder.apiType = apiType
return blder
}
@@ -80,8 +84,9 @@ func (blder *WebhookBuilder) WithLogConstructor(logConstructor func(base logr.Lo
}
// RecoverPanic indicates whether panics caused by the webhook should be recovered.
func (blder *WebhookBuilder) RecoverPanic() *WebhookBuilder {
blder.recoverPanic = true
// Defaults to true.
func (blder *WebhookBuilder) RecoverPanic(recoverPanic bool) *WebhookBuilder {
blder.recoverPanic = &recoverPanic
return blder
}
@@ -142,7 +147,7 @@ func (blder *WebhookBuilder) registerWebhooks() error {
if err != nil {
return err
}
return nil
return blder.err
}
// registerDefaultingWebhook registers a defaulting webhook if necessary.
@@ -165,10 +170,18 @@ func (blder *WebhookBuilder) registerDefaultingWebhook() {
func (blder *WebhookBuilder) getDefaultingWebhook() *admission.Webhook {
if defaulter := blder.customDefaulter; defaulter != nil {
return admission.WithCustomDefaulter(blder.mgr.GetScheme(), blder.apiType, defaulter).WithRecoverPanic(blder.recoverPanic)
w := admission.WithCustomDefaulter(blder.mgr.GetScheme(), blder.apiType, defaulter)
if blder.recoverPanic != nil {
w = w.WithRecoverPanic(*blder.recoverPanic)
}
return w
}
if defaulter, ok := blder.apiType.(admission.Defaulter); ok {
return admission.DefaultingWebhookFor(blder.mgr.GetScheme(), defaulter).WithRecoverPanic(blder.recoverPanic)
w := admission.DefaultingWebhookFor(blder.mgr.GetScheme(), defaulter)
if blder.recoverPanic != nil {
w = w.WithRecoverPanic(*blder.recoverPanic)
}
return w
}
log.Info(
"skip registering a mutating webhook, object does not implement admission.Defaulter or WithDefaulter wasn't called",
@@ -196,10 +209,18 @@ func (blder *WebhookBuilder) registerValidatingWebhook() {
func (blder *WebhookBuilder) getValidatingWebhook() *admission.Webhook {
if validator := blder.customValidator; validator != nil {
return admission.WithCustomValidator(blder.mgr.GetScheme(), blder.apiType, validator).WithRecoverPanic(blder.recoverPanic)
w := admission.WithCustomValidator(blder.mgr.GetScheme(), blder.apiType, validator)
if blder.recoverPanic != nil {
w = w.WithRecoverPanic(*blder.recoverPanic)
}
return w
}
if validator, ok := blder.apiType.(admission.Validator); ok {
return admission.ValidatingWebhookFor(blder.mgr.GetScheme(), validator).WithRecoverPanic(blder.recoverPanic)
w := admission.ValidatingWebhookFor(blder.mgr.GetScheme(), validator)
if blder.recoverPanic != nil {
w = w.WithRecoverPanic(*blder.recoverPanic)
}
return w
}
log.Info(
"skip registering a validating webhook, object does not implement admission.Validator or WithValidator wasn't called",