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) }
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.
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.