controller

package
v0.19.2 Latest Latest
Warning

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

Go to latest
Published: Nov 21, 2024 License: Apache-2.0 Imports: 12 Imported by: 5,406

Documentation

Overview

Package controller provides types and functions for building Controllers. Controllers implement Kubernetes APIs.

Creation

To create a new Controller, first create a manager.Manager and pass it to the controller.New function. The Controller MUST be started by calling Manager.Start.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ReconcileIDFromContext = controller.ReconcileIDFromContext

ReconcileIDFromContext gets the reconcileID from the current context.

Functions

This section is empty.

Types

type Controller

type Controller = TypedController[reconcile.Request]

Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests from source.Sources. Work is performed through the reconcile.Reconciler for each enqueued item. Work typically is reads and writes Kubernetes objects to make the system state match the state specified in the object Spec.

Example

This example starts a new Controller named "pod-controller" to Watch Pods and call a no-op Reconciler.

package main

import (
	"context"
	"os"

	corev1 "k8s.io/api/core/v1"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"

	logf "sigs.k8s.io/controller-runtime/pkg/log"
	"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"
)

var (
	mgr manager.Manager

	log = logf.Log.WithName("controller-examples")
)

func main() {
	// mgr is a manager.Manager

	// Create a new Controller that will call the provided Reconciler function in response
	// to events.
	c, err := controller.New("pod-controller", mgr, controller.Options{
		Reconciler: reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
			// Your business logic to implement the API by creating, updating, deleting objects goes here.
			return reconcile.Result{}, nil
		}),
	})
	if err != nil {
		log.Error(err, "unable to create pod-controller")
		os.Exit(1)
	}

	// Watch for Pod create / update / delete events and call Reconcile
	err = c.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}, &handler.TypedEnqueueRequestForObject[*corev1.Pod]{}))
	if err != nil {
		log.Error(err, "unable to watch pods")
		os.Exit(1)
	}

	// Start the Controller through the manager.
	if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
		log.Error(err, "unable to continue running manager")
		os.Exit(1)
	}
}
Output:

Example (Unstructured)

This example starts a new Controller named "pod-controller" to Watch Pods with the unstructured object and call a no-op Reconciler.

package main

import (
	"context"
	"os"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"

	logf "sigs.k8s.io/controller-runtime/pkg/log"
	"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"
)

var (
	mgr manager.Manager

	log = logf.Log.WithName("controller-examples")
)

func main() {
	// mgr is a manager.Manager

	// Create a new Controller that will call the provided Reconciler function in response
	// to events.
	c, err := controller.New("pod-controller", mgr, controller.Options{
		Reconciler: reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
			// Your business logic to implement the API by creating, updating, deleting objects goes here.
			return reconcile.Result{}, nil
		}),
	})
	if err != nil {
		log.Error(err, "unable to create pod-controller")
		os.Exit(1)
	}

	u := &unstructured.Unstructured{}
	u.SetGroupVersionKind(schema.GroupVersionKind{
		Kind:    "Pod",
		Group:   "",
		Version: "v1",
	})
	// Watch for Pod create / update / delete events and call Reconcile
	err = c.Watch(source.Kind(mgr.GetCache(), u, &handler.TypedEnqueueRequestForObject[*unstructured.Unstructured]{}))
	if err != nil {
		log.Error(err, "unable to watch pods")
		os.Exit(1)
	}

	// Start the Controller through the manager.
	if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
		log.Error(err, "unable to continue running manager")
		os.Exit(1)
	}
}
Output:

func New

func New(name string, mgr manager.Manager, options Options) (Controller, error)

New returns a new Controller registered with the Manager. The Manager will ensure that shared Caches have been synced before the Controller is Started.

The name must be unique as it is used to identify the controller in metrics and logs.

Example

This example creates a new Controller named "pod-controller" with a no-op reconcile function. The manager.Manager will be used to Start the Controller, and will provide it a shared Cache and Client.

package main

import (
	"context"
	"os"

	"sigs.k8s.io/controller-runtime/pkg/controller"

	logf "sigs.k8s.io/controller-runtime/pkg/log"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

var (
	mgr manager.Manager

	log = logf.Log.WithName("controller-examples")
)

func main() {
	_, err := controller.New("pod-controller", mgr, controller.Options{
		Reconciler: reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
			// Your business logic to implement the API by creating, updating, deleting objects goes here.
			return reconcile.Result{}, nil
		}),
	})
	if err != nil {
		log.Error(err, "unable to create pod-controller")
		os.Exit(1)
	}
}
Output:

func NewUnmanaged added in v0.6.0

func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller, error)

NewUnmanaged returns a new controller without adding it to the manager. The caller is responsible for starting the returned controller.

The name must be unique as it is used to identify the controller in metrics and logs.

Example

This example creates a new controller named "pod-controller" to watch Pods and call a no-op reconciler. The controller is not added to the provided manager, and must thus be started and stopped by the caller.

package main

import (
	"context"
	"os"

	corev1 "k8s.io/api/core/v1"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"

	logf "sigs.k8s.io/controller-runtime/pkg/log"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"sigs.k8s.io/controller-runtime/pkg/source"
)

var (
	mgr manager.Manager

	log = logf.Log.WithName("controller-examples")
)

func main() {
	// mgr is a manager.Manager

	// Configure creates a new controller but does not add it to the supplied
	// manager.
	c, err := controller.NewUnmanaged("pod-controller", mgr, controller.Options{
		Reconciler: reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
			return reconcile.Result{}, nil
		}),
	})
	if err != nil {
		log.Error(err, "unable to create pod-controller")
		os.Exit(1)
	}

	if err := c.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}, &handler.TypedEnqueueRequestForObject[*corev1.Pod]{})); err != nil {
		log.Error(err, "unable to watch pods")
		os.Exit(1)
	}

	ctx, cancel := context.WithCancel(context.Background())

	// Start our controller in a goroutine so that we do not block.
	go func() {
		// Block until our controller manager is elected leader. We presume our
		// entire process will terminate if we lose leadership, so we don't need
		// to handle that.
		<-mgr.Elected()

		// Start our controller. This will block until the context is
		// closed, or the controller returns an error.
		if err := c.Start(ctx); err != nil {
			log.Error(err, "cannot run experiment controller")
		}
	}()

	// Stop our controller.
	cancel()
}
Output:

type Options

type Options = TypedOptions[reconcile.Request]

Options are the arguments for creating a new Controller.

type TypedController added in v0.19.0

type TypedController[request comparable] interface {
	// Reconciler is called to reconcile an object by Namespace/Name
	reconcile.TypedReconciler[request]

	// Watch watches the provided Source.
	Watch(src source.TypedSource[request]) error

	// Start starts the controller.  Start blocks until the context is closed or a
	// controller has an error starting.
	Start(ctx context.Context) error

	// GetLogger returns this controller logger prefilled with basic information.
	GetLogger() logr.Logger
}

TypedController implements an API.

func NewTyped added in v0.19.0

func NewTyped[request comparable](name string, mgr manager.Manager, options TypedOptions[request]) (TypedController[request], error)

NewTyped returns a new typed controller registered with the Manager,

The name must be unique as it is used to identify the controller in metrics and logs.

func NewTypedUnmanaged added in v0.19.0

func NewTypedUnmanaged[request comparable](name string, mgr manager.Manager, options TypedOptions[request]) (TypedController[request], error)

NewTypedUnmanaged returns a new typed controller without adding it to the manager.

The name must be unique as it is used to identify the controller in metrics and logs.

type TypedOptions added in v0.19.0

type TypedOptions[request comparable] struct {
	// SkipNameValidation allows skipping the name validation that ensures that every controller name is unique.
	// Unique controller names are important to get unique metrics and logs for a controller.
	// Defaults to the Controller.SkipNameValidation setting from the Manager if unset.
	// Defaults to false if Controller.SkipNameValidation setting from the Manager is also unset.
	SkipNameValidation *bool

	// MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
	MaxConcurrentReconciles int

	// CacheSyncTimeout refers to the time limit set to wait for syncing caches.
	// Defaults to 2 minutes if not set.
	CacheSyncTimeout time.Duration

	// RecoverPanic indicates whether the panic caused by reconcile should be recovered.
	// Defaults to the Controller.RecoverPanic setting from the Manager if unset.
	// Defaults to true if Controller.RecoverPanic setting from the Manager is also unset.
	RecoverPanic *bool

	// NeedLeaderElection indicates whether the controller needs to use leader election.
	// Defaults to true, which means the controller will use leader election.
	NeedLeaderElection *bool

	// Reconciler reconciles an object
	Reconciler reconcile.TypedReconciler[request]

	// RateLimiter is used to limit how frequently requests may be queued.
	// Defaults to MaxOfRateLimiter which has both overall and per-item rate limiting.
	// The overall is a token bucket and the per-item is exponential.
	RateLimiter workqueue.TypedRateLimiter[request]

	// NewQueue constructs the queue for this controller once the controller is ready to start.
	// With NewQueue a custom queue implementation can be used, e.g. a priority queue to prioritize with which
	// priority/order objects are reconciled (e.g. to reconcile objects with changes first).
	// This is a func because the standard Kubernetes work queues start themselves immediately, which
	// leads to goroutine leaks if something calls controller.New repeatedly.
	// The NewQueue func gets the controller name and the RateLimiter option (defaulted if necessary) passed in.
	// NewQueue defaults to NewRateLimitingQueueWithConfig.
	//
	// NOTE: LOW LEVEL PRIMITIVE!
	// Only use a custom NewQueue if you know what you are doing.
	NewQueue func(controllerName string, rateLimiter workqueue.TypedRateLimiter[request]) workqueue.TypedRateLimitingInterface[request]

	// LogConstructor is used to construct a logger used for this controller and passed
	// to each reconciliation via the context field.
	LogConstructor func(request *request) logr.Logger
}

TypedOptions are the arguments for creating a new Controller.

Directories

Path Synopsis
Package controllertest contains fake informers for testing controllers When in doubt, it's almost always better to test against a real API server using envtest.Environment.
Package controllertest contains fake informers for testing controllers When in doubt, it's almost always better to test against a real API server using envtest.Environment.
Package controllerutil contains utility functions for working with and implementing Controllers.
Package controllerutil contains utility functions for working with and implementing Controllers.

Jump to

Keyboard shortcuts

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