handler

package
v0.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2024 License: Apache-2.0 Imports: 14 Imported by: 24

Documentation

Index

Examples

Constants

View Source
const (
	// NamespacedNameAnnotation is an annotation whose value encodes the name and namespace of a resource to
	// reconcile when a resource containing this annotation changes. Valid values are of the form
	// `<namespace>/<name>` for namespace-scoped owners and `<name>` for cluster-scoped owners.
	NamespacedNameAnnotation = "operator-sdk/primary-resource"
	// TypeAnnotation is an annotation whose value encodes the group and kind of a resource to reconcil when a
	// resource containing this annotation changes. Valid values are of the form `<Kind>` for resource in the
	// core group, and `<Kind>.<group>` for all other resources.
	TypeAnnotation = "operator-sdk/primary-resource-type"
)

Variables

This section is empty.

Functions

func NewPause added in v0.6.0

NewPause returns an event handler that filters out objects with a truthy "paused" annotation. When an annotation with key string key is present on an object and has a truthy value, ex. "true", the watch constructed with this event handler will not add events for that object to the queue. Key string key must be a valid annotation key.

A note on security: since users that can CRUD a particular API can apply or remove annotations with default cluster admission controllers, this same set of users can therefore start or stop reconciliation of objects via this pause mechanism. If this is a concern, configure an admission webhook to enforce a stricter annotation modification policy. See AdmissionReview configuration for user info available to a webhook: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#request

Example

This example applies the Pause handler to all incoming Pod events on a Pod controller.

package main

import (
	"context"
	"os"

	corev1 "k8s.io/api/core/v1"
	"sigs.k8s.io/controller-runtime/pkg/client/config"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/manager/signals"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"sigs.k8s.io/controller-runtime/pkg/source"

	"github.com/operator-framework/operator-lib/handler"
)

func main() {
	cfg, err := config.GetConfig()
	if err != nil {
		os.Exit(1)
	}

	mgr, err := manager.New(cfg, manager.Options{})
	if err != nil {
		os.Exit(1)
	}

	c, err := controller.NewUnmanaged("pod", mgr, controller.Options{
		Reconciler: reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
			return reconcile.Result{}, nil
		}),
	})
	if err != nil {
		os.Exit(1)
	}

	// Filter out Pods with the "my.app/paused: true" annotation.
	pause, err := handler.NewPause[*corev1.Pod]("my.app/paused")
	if err != nil {
		os.Exit(1)
	}
	if err := c.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}, pause)); err != nil {
		os.Exit(1)
	}

	<-mgr.Elected()

	if err := c.Start(signals.SetupSignalHandler()); err != nil {
		os.Exit(1)
	}
}
Output:

func SetOwnerAnnotations

func SetOwnerAnnotations(owner, object client.Object) error

SetOwnerAnnotations helps in adding 'NamespacedNameAnnotation' and 'TypeAnnotation' to object based on the values obtained from owner. The object gets the annotations from owner's namespace, name, group and kind. In other terms, object can be said to be the dependent having annotations from the owner. When a watch is set on the object, the annotations help to identify the owner and trigger reconciliation. Annotations are ALWAYS overwritten.

Types

type EnqueueRequestForAnnotation

type EnqueueRequestForAnnotation[T client.Object] struct {
	Type schema.GroupKind
}

EnqueueRequestForAnnotation enqueues Request containing the Name and Namespace specified in the annotations of the object that is the source of the Event. The source of the event triggers reconciliation of the parent resource which is identified by annotations. `NamespacedNameAnnotation` and `TypeAnnotation` together uniquely identify an owner resource to reconcile.

handler.EnqueueRequestForAnnotation can be used to trigger reconciliation of resources which are cross-referenced. This allows a namespace-scoped dependent to trigger reconciliation of an owner which is in a different namespace, and a cluster-scoped dependent can trigger the reconciliation of a namespace(scoped)-owner.

As an example, consider the case where we would like to watch clusterroles based on which we reconcile namespace-scoped replicasets. With native owner references, this would not be possible since the cluster-scoped dependent (clusterroles) is trying to specify a namespace-scoped owner (replicasets). Whereas in case of annotations-based handlers, we could implement the following:

if err := c.Watch(&source.Kind{
	// Watch clusterroles
	Type: &rbacv1.ClusterRole{}},

	// Enqueue ReplicaSet reconcile requests using the namespacedName annotation value in the request.
	&handler.EnqueueRequestForAnnotation{schema.GroupKind{Group:"apps", Kind:"ReplicaSet"}}); err != nil {
		entryLog.Error(err, "unable to watch ClusterRole")
		os.Exit(1)
	}
}

With this watch, the ReplicaSet reconciler would receive a request to reconcile "my-namespace/my-replicaset" based on a change to a ClusterRole that has the following annotations:

annotations:
	operator-sdk/primary-resource:"my-namespace/my-replicaset"
	operator-sdk/primary-resource-type:"ReplicaSet.apps"

Though an annotation-based watch handler removes the boundaries set by native owner reference implementation, the garbage collector still respects the scope restrictions. For example, if a parent creates a child resource across scopes not supported by owner references, it becomes the responsibility of the reconciler to clean up the child resource. Hence, the resource utilizing this handler SHOULD ALWAYS BE IMPLEMENTED WITH A FINALIZER.

func (*EnqueueRequestForAnnotation[T]) Create

Create implements EventHandler

func (*EnqueueRequestForAnnotation[T]) Delete

Delete implements EventHandler

func (*EnqueueRequestForAnnotation[T]) Generic

Generic implements EventHandler

func (*EnqueueRequestForAnnotation[T]) Update

Update implements EventHandler

type InstrumentedEnqueueRequestForObject

type InstrumentedEnqueueRequestForObject[T client.Object] struct {
	handler.TypedEnqueueRequestForObject[T]
}

InstrumentedEnqueueRequestForObject wraps controller-runtime handler for "EnqueueRequestForObject", and sets up primary resource metrics on event handlers. The main objective of this handler is to set prometheus metrics when create/update/delete events occur. These metrics contain the following information on resource.

resource_created_at_seconds{"name", "namespace", "group", "version", "kind"}

To call the handler use:

&handler.InstrumentedEnqueueRequestForObject{}

func (InstrumentedEnqueueRequestForObject[T]) Create

Create implements EventHandler, and creates the metrics.

func (InstrumentedEnqueueRequestForObject[T]) Delete

Delete implements EventHandler, and deletes metrics.

func (InstrumentedEnqueueRequestForObject[T]) Update

Update implements EventHandler, and updates the metrics.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL