README
¶
Subreconciler
Subreconciler is a tiny convenience library for Kubernetes Operator developers, adding utilities that improve Operator code readability.
This library encourages you to break your Operator reconciliation logic into fragments ("subreconciler" functions), which can then be executed (serially, if needed), and return signals as to whether reconciliation should continue or halt.
This project is intended to go hand-in-hand with Operator developers consuming tools like Operator Framework or Kubebuilder, and assumes some degree of familiarity with Operator development using these tools.
Motivation
The Operator reconciliation workflow generally consists of some incoming event that triggers your controllers to evaluate said event, and ensure that the existing state of your resources match the desired state of your specification
In many cases, that workflow involves any number of logical tasks that take place under one controller, potentially in concert with supplementary controllers, to ensure application workloads reach their desired state.
The goal of this project is to make the definition, intent, and outcome of each logical task a bit easier to read, write, parse, and understand.
Quick Start
The key concepts of this library involve:
-
Subreconciler functions
-
Flow control
Subreconciler Functions
The subreconciler.Fn
type definition represents the smaller, logical units of
work that need to be executed by your controller. You should implement this type
definition in your code as your individual tasks associated with reconciliation.
As an example, you may have:
// NOTE: the `ctrl` package here refers to the controller-runtime package:
// https://pkg.go.dev/sigs.k8s.io/controller-runtime
func (t *YourReconciler) ensureServiceAccount(c context.Context) (*ctrl.Result, error){
// omitted for brevity
}
func (t *YourReconciler) ensureRole(c context.Context) (*ctrl.Result, error){
// omitted for brevity
}
func (t *YourReconciler) ensureRoleBinding(c context.Context) (*ctrl.Result, error){
// omitted for brevity
}
// etc.
All of these match the expected signature of a subreconciler.Fn
, with their individual goals clearly
defined. Executing these in a logical order might look like:
func (t *YourReconciler) Reconcile(c context.Context, req ctrl.Request) (ctrl.Result, error){
// additional code as you need
subrecs := []subreconciler.Fn{
t.ensureServiceAccount,
t.ensureRole,
t.ensureRoleBinding
}
for _, subrec := range subrecs {
subres, err := subrec(c)
// More on these the Flow Control section below
if subreconciler.ShouldHaltOrRequeue(subres, err) {
return subreconciler.Evaluate(subres, err)
}
}
// additional code as you need
// When done with all logic, indicate successful reconciliation and do not requeue.
return subreconciler.Evaluate(subreconciler.DoNotRequeue())
}
This structure allows you to build out your order of operations, and add additional subreconcilers to the execution as needed in a way that's easy to follow for your future self.
In cases where you may want to pass along the
Request type from
the top-level reconciler, the subreconciler.FnWithRequest
type definition is
the signature you would want to use instead.
Flow Control
The previous examples included a few references to flow control functions
available in the subreconciler
module. The return value of a subreconciler can
indicate to callers whether reconciliation should continue, halt, throw an
error, requeue, etc.
The subreconciler
module provides helper functions that return the appropriate
return values based on the mentioned case. An example might look like:
func (t *YourReconciler) doSomeSpecificWork(c context.Context) (*ctrl.Result, error) {
// In this example, resources being deleted means we should stop our work
// so we'll return the corresponding subreconciler result.
if resourceIsBeingDeleted() {
return subreconciler.DoNotRequeue()
}
// In this example, this task can tell us to backoff without throwing an error, in
// which case we want to requeue for the work to be done later instead of spamming
// the reconciliation until the work can be completed.
backoff, err := doSomeComplicatedWork(c)
if err != nil {
// Here, we encountered an error, so we bubble up that error.
return subreconciler.RequeueWithError(err)
}
if backoff {
// If we were told to back off, we requeue after 10 seconds.
return subreconciler.RequeueWithDelay(10 * time.Second)
}
// We successfully completed this bit of work, so we'll signal our success by indicating
// that reconciliation can continue.
return subreconciler.ContinueReconciling()
}
It's important that subreconcilers indicate that reconciliation can continue on their completion. This is what allows us to be able to call multiple tasks in succession.
Documentation
¶
Overview ¶
Package subreconciler defines a set of functions that can help partition controller reconciliation into smaller, reliable pieces.
Index ¶
- func ContinueReconciling() (*reconcile.Result, error)
- func DoNotRequeue() (*reconcile.Result, error)
- func Evaluate(r *reconcile.Result, e error) (reconcile.Result, error)
- func Requeue() (*reconcile.Result, error)
- func RequeueWithDelay(dur time.Duration) (*reconcile.Result, error)
- func RequeueWithDelayAndError(dur time.Duration, e error) (*reconcile.Result, error)
- func RequeueWithError(e error) (*reconcile.Result, error)
- func ShouldContinue(r *ctrl.Result, err error) bool
- func ShouldHaltOrRequeue(r *ctrl.Result, err error) bool
- func ShouldRequeue(r *ctrl.Result, err error) bool
- type Fn
- type FnWithRequest
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ContinueReconciling ¶
ContinueReconciling indicates that the reconciliation block should continue by returning a nil result and a nil error
func DoNotRequeue ¶
DoNotRequeue returns a controller result pairing specifying not to requeue.
func Evaluate ¶
Evaluate returns the actual reconcile struct and error. Wrap helpers in this when returning from within the top-level Reconciler.
func Requeue ¶
Requeue returns a controller result pairing specifying to requeue with no error message implied. This returns no error.
func RequeueWithDelay ¶
RequeueWithDelay returns a controller result pairing specifying to requeue after a delay. This returns no error.
func RequeueWithDelayAndError ¶
RequeueWithDelayAndError returns a controller result pairing specifying to requeue after a delay with an error message.
func RequeueWithError ¶
RequeueWithError returns a controller result pairing specifying to requeue with an error message.
func ShouldContinue ¶
ShouldContinue returns the inverse of ShouldHalt.
func ShouldHaltOrRequeue ¶
ShouldHaltOrRequeue returns true if reconciler result is not nil or the err is not nil. In theory, the error evaluation is not needed because ShouldRequeue handles it, but it's included in case ShouldHaltOrRequeue is called directly.