patch

package
v0.49.1 Latest Latest
Warning

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

Go to latest
Published: Sep 13, 2024 License: Apache-2.0 Imports: 14 Imported by: 29

Documentation

Overview

Package patch implements patch utilities to help with proper patching of objects while reducing the number of potential conflicts.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ToUnstructured added in v0.13.1

func ToUnstructured(obj runtime.Object) (*unstructured.Unstructured, error)

ToUnstructured converts a runtime.Object into an Unstructured object.

Types

type Helper

type Helper struct {
	// contains filtered or unexported fields
}

Helper is a utility for ensuring the proper patching of objects.

The Helper MUST be initialised before a set of modifications within the scope of an envisioned patch are made to an object, so that the difference in state can be utilised to calculate a patch that can be used on a new revision of the resource in case of conflicts.

A common pattern for reconcilers is to initialise a NewHelper at the beginning of their Reconcile method, after having fetched the latest revision for the resource from the API server, and then defer the call of Helper.Patch. This ensures any modifications made to the spec and the status (conditions) object of the resource are always persisted at the end of a reconcile run.

The example below assumes that you will use the Reconciling condition to signal that progress can be made; if it is not present, and the Ready condition is not true, the resource will be marked as stalled.

func (r *FooReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
	// Retrieve the object from the API server
	obj := &v1.Foo{}
	if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
		return ctrl.Result{}, client.IgnoreNotFound(err)
	}

	// Initialise the patch helper
	patchHelper, err := patch.NewHelper(obj, r.Client)
	if err != nil {
		return ctrl.Result{}, err
	}

	// Always attempt to patch the object and status after each reconciliation
	defer func() {
		// Patch the object, ignoring conflicts on the conditions owned by this controller
		patchOpts := []patch.Option{
			patch.WithOwnedConditions{
				Conditions: []string{
					meta.ReadyCondition,
					meta.ReconcilingCondition,
					meta.StalledCondition,
					// any other "owned conditions"
				},
			},
		}

		// On a clean exit, determine if the resource is still being reconciled, or if it has stalled, and record this observation
		if retErr == nil && (result.IsZero() || !result.Requeue) {
			// We have now observed this generation
			patchOpts = append(patchOpts, patch.WithStatusObservedGeneration{})

			readyCondition := conditions.Get(obj, meta.ReadyCondition)
			switch {
			case readyCondition.Status == metav1.ConditionTrue:
				// As we are no longer reconciling and the end-state is ready, the reconciliation is no longer stalled or progressing, so clear these
				conditions.Delete(obj, meta.StalledCondition)
				conditions.Delete(obj, meta.ReconcilingCondition)
			case conditions.IsReconciling(obj):
				// This implies stalling is not set; nothing to do
				break
			case readyCondition.Status == metav1.ConditionFalse:
				// As we are no longer reconciling and the end-state is not ready, the reconciliation has stalled
				conditions.MarkTrue(obj, meta.StalledCondition, readyCondition.Reason, readyCondition.Message)
			}
		}

		// Finally, patch the resource
		if err := patchHelper.Patch(ctx, obj, patchOpts...); err != nil {
			retErr = kerrors.NewAggregate([]error{retErr, err})
		}
	}()

	// ...start with actual reconciliation logic
}

Using this pattern, one-off or scoped patches for a subset of a reconcile operation can be made by initialising a new Helper using NewHelper with the current state of the resource, making the modifications, and then directly applying the patch using Helper.Patch, for example:

func (r *FooReconciler) subsetReconcile(ctx context.Context, obj *v1.Foo) (ctrl.Result, error) {
	patchHelper, err := patch.NewHelper(obj, r.Client)
	if err != nil {
		return ctrl.Result{}, err
	}

	// Set CustomField in status object of resource
	obj.Status.CustomField = "value"

	// Patch now only attempts to persist CustomField
	patchHelper.Patch(ctx, obj, nil)
}

func NewHelper

func NewHelper(obj client.Object, crClient client.Client) (*Helper, error)

NewHelper returns an initialised Helper.

func (*Helper) Patch

func (h *Helper) Patch(ctx context.Context, obj client.Object, opts ...Option) error

Patch will attempt to patch the given object, including its status.

type HelperOptions

type HelperOptions struct {
	// IncludeStatusObservedGeneration sets the status.observedGeneration field on the incoming object to match
	// metadata.generation, only if there is a change.
	IncludeStatusObservedGeneration bool

	// ForceOverwriteConditions allows the patch helper to overwrite conditions in case of conflicts.
	// This option should only ever be set in controller managing the object being patched.
	ForceOverwriteConditions bool

	// OwnedConditions defines condition types owned by the controller.
	// In case of conflicts for the owned conditions, the patch helper will always use the value provided by the
	// controller.
	OwnedConditions []string

	// FieldOwner defines the field owner configuration for Kubernetes patch operations.
	FieldOwner string
}

HelperOptions contains options for patch options.

type Option

type Option interface {
	// ApplyToHelper applies this configuration to the given Helper options.
	ApplyToHelper(*HelperOptions)
}

Option is some configuration that modifies options for a patch request.

type SerialPatcher added in v0.22.0

type SerialPatcher struct {
	// contains filtered or unexported fields
}

SerialPatcher provides serial patching of object using the patch helper. It remembers the state of the last patched object and uses that to calculate the patch aginst a new object.

func NewSerialPatcher added in v0.22.0

func NewSerialPatcher(obj client.Object, c client.Client) *SerialPatcher

NewSerialPatcher returns a SerialPatcher with the given object as the initial base object for the patching operations.

func (*SerialPatcher) Patch added in v0.22.0

func (sp *SerialPatcher) Patch(ctx context.Context, obj client.Object, options ...Option) error

Patch performs patching operation of the SerialPatcher and updates the beforeObject after a successful patch for subsequent patching.

type WithFieldOwner

type WithFieldOwner string

WithFieldOwner set the field manager name for the patch operations.

func (WithFieldOwner) ApplyToHelper

func (w WithFieldOwner) ApplyToHelper(in *HelperOptions)

ApplyToHelper applies this configuration to the given HelperOptions.

type WithForceOverwriteConditions

type WithForceOverwriteConditions struct{}

WithForceOverwriteConditions allows the patch helper to overwrite conditions in case of conflicts. This option should only ever be set in controller managing the object being patched.

func (WithForceOverwriteConditions) ApplyToHelper

func (w WithForceOverwriteConditions) ApplyToHelper(in *HelperOptions)

ApplyToHelper applies this configuration to the given HelperOptions.

type WithOwnedConditions

type WithOwnedConditions struct {
	Conditions []string
}

WithOwnedConditions allows to define condition types owned by the controller. In case of conflicts for the owned conditions, the patch helper will always use the value provided by the controller.

func (WithOwnedConditions) ApplyToHelper

func (w WithOwnedConditions) ApplyToHelper(in *HelperOptions)

ApplyToHelper applies this configuration to the given HelperOptions.

type WithStatusObservedGeneration

type WithStatusObservedGeneration struct{}

WithStatusObservedGeneration sets the status.observedGeneration field on the incoming object to match metadata.generation, only if there is a change.

func (WithStatusObservedGeneration) ApplyToHelper

func (w WithStatusObservedGeneration) ApplyToHelper(in *HelperOptions)

ApplyToHelper applies this configuration to the given HelperOptions.

Jump to

Keyboard shortcuts

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