New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature Request] Finalizer helper library #1453
Comments
/assign |
Pinging @joelanford as he suggested this approach. |
https://github.com/coderanger/controller-utils/blob/main/core/reconciler.go#L277-L290 is my implementation of the general helper pattern for this. It checks on initialization (up above) for if the component implements the finalizer interface and if so, it will call Finalizer() on that component when needed. |
My high level thought was to have something like this: package finalizer
type Registerer interface {
Register(key string, f Finalizer) error
}
type Finalizer interface {
Finalize(context.Context, client.Object) (needsUpdate bool, err error)
}
type Finalizers interface {
// implements Registerer and Finalizer to finalize
// all registered finalizers if the provided object
// has a deletion timestamp or set all registered
// finalizers if it doesn't
Registerer
Finalizer
}
func NewFinalizers() Finalizers {
return finalizers(map[string]Finalizer{})
}
type finalizers map[string]Finalizer
func (f finalizers) Register(key string, finalizer Finalizer) error {
if _, ok := f[key]; ok {
return fmt.Errorf("finalizer for key %q already registered")
}
f[key] = finalizer
return nil
}
func (f finalizers) Finalize(ctx context.Context, obj client.Object) (bool, error) {
needsUpdate := false
for key, finalizer := range f {
if obj.GetDeletionTimestamp() == nil && !controllerutil.ContainsFinalizer(obj, key) {
controllerutil.AddFinalizer(obj, key)
needsUpdate = true
} else if obj.GetDeletionTimestamp() != nil && controllerutil.ContainsFinalizer(obj, key) {
_, err := finalizer.Finalize(ctx, obj)
if err != nil {
return true, fmt.Errorf("finalize failed for key %q: %v", key, err)
}
controllerutil.RemoveFinalizer(obj, key)
needsUpdate = true
}
}
return needsUpdate, nil
} With something like this users could:
It looks like @coderanger has an actual working implementation of what the |
Issues go stale after 90d of inactivity. If this issue is safe to close now please do so with Send feedback to sig-contributor-experience at kubernetes/community. |
Implemented and merged the finalizer helper library in #1481. |
Are there any examples that use this? I'm giving it a try but don't understand where the business logic of the finalizer should live. It feels like the And then, does it make sense to requeue if either the obj or its status was updated? requeue, err := r.Finalizers.Finalize(ctx, &job)
if requeue.Updated || requeue.StatusUpdated || err != nil {
if requeue.Updated {
r.Client.Update(ctx, &job)
}
if requeue.StatusUpdated {
r.Client.Status().Update(ctx, &job)
}
return ctrl.Result{Requeue: requeue.Updated || requeue.StatusUpdated}, err
} Update: created a new issue instead of continuing to clutter this one |
In Kubernetes garbage collection model, OwnerReferences are allowed within a namespace wherein the "dependent" object has anOwnerReference field referencing the "parent" object. If the parent object is being deleted, Kubernetes garbage collector will delete all of its dependent objects. As cross-namespace owner references are not allowed by design; a Finalizer should be used to perform cleanup.
Finalizers are more powerful and broadly applicable than owner references because they permit customizable deletion steps for a controller to define how an object is cleaned up, ex. updating a CR's status during deletion with a particular message. This gives Operator authors control over CR deletion proceeds.
Operator projects would benefit from a finalizer helper library in controller-runtime which will make it easy for users to define their own finalizer struct implementations and use the abstractions we include to register the Finalizers and hand the Finalizers to their Reconciler and call Finalize function.
Please see @joelanford's high level thought on the implementation details: kubernetes-sigs/kubebuilder#2010 (comment).
/kind feature
The text was updated successfully, but these errors were encountered: