Skip to content

Commit 85d1343

Browse files
committed
📖 docs for using finalizers
1 parent de15359 commit 85d1343

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

docs/book/src/SUMMARY.md

+6
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,10 @@
2626

2727
---
2828

29+
- [Reference](./reference/reference.md)
30+
31+
- [Using Finalizers](./reference/using-finalizers.md)
32+
33+
---
34+
2935
[Appendix: The TODO Landing Page](./TODO.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
// +kubebuilder:docs-gen:collapse=Apache License
16+
17+
/*
18+
First, we start out with some standard imports.
19+
As before, we need the core controller-runtime library, as well as
20+
the client package, and the package for our API types.
21+
*/
22+
package controllers
23+
24+
import (
25+
"context"
26+
27+
"github.com/go-logr/logr"
28+
ctrl "sigs.k8s.io/controller-runtime"
29+
"sigs.k8s.io/controller-runtime/pkg/client"
30+
31+
batchv1 "tutorial.kubebuilder.io/project/api/v1"
32+
)
33+
34+
// +kubebuilder:docs-gen:collapse=Imports
35+
36+
/*
37+
The code snippet below shows skeleton code for implementing a finalizer.
38+
*/
39+
40+
func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
41+
ctx := context.Background()
42+
log := r.Log.WithValues("cronjob", req.NamespacedName)
43+
44+
var cronJob batch.CronJob
45+
if err := r.Get(ctx, req.NamespacedName, &cronJob); err != nil {
46+
log.Error(err, "unable to fetch CronJob")
47+
// we'll ignore not-found errors, since they can't be fixed by an immediate
48+
// requeue (we'll need to wait for a new notification), and we can get them
49+
// on deleted requests.
50+
return ctrl.Result{}, ignoreNotFound(err)
51+
}
52+
53+
// name of our custom finalizer
54+
myFinalizerName := "storage.finalizers.tutorial.kubebuilder.io"
55+
56+
// examine DeletionTimestamp to determine if object is under deletion
57+
if cronJob.ObjectMeta.DeletionTimestamp.IsZero() {
58+
// The object is not being deleted, so if it does not have our finalizer,
59+
// then lets add the finalizer and update the object. This is equivalent
60+
// registering our finalizer.
61+
if !containsString(cronJob.ObjectMeta.Finalizers, myFinalizerName) {
62+
cronJob.ObjectMeta.Finalizers = append(cronJob.ObjectMeta.Finalizers, myFinalizerName)
63+
if err := r.Update(context.Background(), cronJob); err != nil {
64+
return ctrl.Result{}, err
65+
}
66+
}
67+
} else {
68+
// The object is being deleted
69+
if containsString(cronJob.ObjectMeta.Finalizers, myFinalizerName) {
70+
// our finalizer is present, so lets handle any external dependency
71+
if err := r.deleteExternalResources(cronJob); err != nil {
72+
// if fail to delete the external dependency here, return with error
73+
// so that it can be retried
74+
return ctrl.Result{}, err
75+
}
76+
77+
// remove our finalizer from the list and update it.
78+
cronJob.ObjectMeta.Finalizers = removeString(cronJob.ObjectMeta.Finalizers, myFinalizerName)
79+
if err := r.Update(context.Background(), cronJob); err != nil {
80+
return ctrl.Result{}, err
81+
}
82+
}
83+
84+
return ctrl.Result{}, err
85+
}
86+
87+
// rest of the reconciler code
88+
}
89+
90+
func (r *Reconciler) deleteExternalResources(cronJob *batch.CronJob) error {
91+
//
92+
// delete any external resources associated with the cronJob
93+
//
94+
// Ensure that delete implementation is idempotent and safe to invoke
95+
// multiple types for same object.
96+
}
97+
98+
// Helper functions to check and remove string from a slice of strings.
99+
func containsString(slice []string, s string) bool {
100+
for _, item := range slice {
101+
if item == s {
102+
return true
103+
}
104+
}
105+
return false
106+
}
107+
108+
func removeString(slice []string, s string) (result []string) {
109+
for _, item := range slice {
110+
if item == s {
111+
continue
112+
}
113+
result = append(result, item)
114+
}
115+
return
116+
}

docs/book/src/reference/reference.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Reference
2+
3+
- [Using Finalizers](./using-finalizers.md): Finalizers are a mechanism to
4+
execute any custom logic related to a resource before it gets deleted from
5+
Kubernetes cluster.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Using Finalizers
2+
3+
`Finalizers` allow controllers to implement asynchronous pre-delete hooks. Let's
4+
say you create an external resource (such as a storage bucket) for each object of
5+
your API type, and you want to delete the associated external resource
6+
on object's deletion from Kubernetes, you can use a finalizer to do that.
7+
8+
You can read more about the finalizers in the [Kubernetes reference docs](https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#finalizers). The section below demonstrates how to register and trigger pre-delete hooks
9+
in the `Reconcile` method of a controller.
10+
11+
The key point to note is that a finalizer causes "delete" on the object to become
12+
an "update" to set deletion timestamp. Presence of deletion timestamp on the object
13+
indicates that it is being deleted. Otherwise, without finalizers, a delete
14+
shows up as a reconcile where the object is missing from the cache.
15+
16+
Highlights:
17+
- If the object is not being deleted and does not have the finalizer registered,
18+
then add the finalizer and update the object in Kubernetes.
19+
- If object is being deleted and the finalizer is still present in finalizers list,
20+
then execute the pre-delete logic and remove the finalizer and update the
21+
object.
22+
- Ensure that the pre-delete logic is idempotent.
23+
24+
{{#literatego ../cronjob-tutorial/testdata/finalizer_example.go}}
25+

0 commit comments

Comments
 (0)