Skip to content

Commit 2336462

Browse files
committed
book: added section for using finalizers
1 parent 1623901 commit 2336462

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

docs/book/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
* [Controllers For Core Resources](beyond_basics/controllers_for_core_resources.md)
3636
* [Controller Watch Functions](beyond_basics/controller_watches.md)
3737
* [Creating Events](beyond_basics/creating_events.md)
38+
* [Using Finalizers](beyond_basics/using_finalizers.md)
3839
* Webhooks
3940
* [What is a Webhook](beyond_basics/what_is_a_webhook.md)
4041
* [Webhook Example](beyond_basics/sample_webhook.md)
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Using Finalizers
2+
3+
`Finalizers` allow controllers to implement asynchronous pre-delete hooks. Let
4+
say you create an external resource such as a storage bucket for each object of
5+
the API type you are implementing and you would like to clean up the external resource
6+
when the corresponding object is deleted from Kubernetes, you can use a
7+
finalizer to delete the external resource.
8+
9+
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). Section below
10+
demonstrates how to register and trigger pre-delete hooks in the `Reconcile`
11+
method of a controller.
12+
13+
{% method %}
14+
15+
Highlights:
16+
- If object is not being deleted and does not have the finalizer registered,
17+
then add the finalizer and update the object in kubernetes.
18+
- If object is being deleted and the finalizer is still present in finalizers list,
19+
then execute the pre-delete logic and remove the finalizer and update the
20+
object.
21+
- You should implement the pre-delete logic in such a way that it is safe to
22+
invoke it multiple times for the same object.
23+
24+
25+
```go
26+
27+
func (r *Reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) {
28+
err := r.Get(context.TODO(), request.NamespacedName, instance)
29+
if err != nil {
30+
// handle error
31+
}
32+
33+
// name of your custom finalizer
34+
myFinalizerName := "storage.finalizers.example.com"
35+
36+
if instance.ObjectMeta.DeletionTimestamp.IsZero() {
37+
// The object is not being deleted, so if it does not have our finalizer,
38+
// then lets add the finalizer and update the object.
39+
if !containsString(instance.ObjectMeta.Finalizers, myFinalizerName) {
40+
instance.ObjectMeta.Finalizers = append(instance.ObjectMeta.Finalizers, myFinalizerName)
41+
if err := r.Update(context.Background(), instance); err != nil {
42+
return reconcile.Result{Requeue: true}, nil
43+
}
44+
}
45+
} else {
46+
// The object is being deleted
47+
if containsString(instance.ObjectMeta.Finalizers, myFinalizerName) {
48+
// our finalizer is present, so lets handle our external dependency
49+
err := r.deleteExternalDependency(instance)
50+
if err != nil {
51+
// if fail to delete the external dependency here, return with error
52+
// so that it can be retried
53+
return reconcile.Result{}, err
54+
}
55+
56+
// remove our finalizer from the list and update it.
57+
instance.ObjectMeta.Finalizers = removeString(instance.ObjectMeta.Finalizers, myFinalizerName)
58+
if err := r.Update(context.Background(), instance); err != nil {
59+
return reconcile.Result{Requeue: true}, nil
60+
}
61+
}
62+
}
63+
....
64+
....
65+
}
66+
67+
func (r *Reconciler) deleteExternalDependency(instance *MyType) error {
68+
log.Printf("deleting the external dependencies")
69+
//
70+
// delete the external dependency here
71+
//
72+
// Ensure that delete implementation is idempotent and safe to invoke
73+
// multiple types for same object.
74+
}
75+
76+
//
77+
// Helper functions to check and remove string from a slice of strings.
78+
//
79+
func containsString(slice []string, s string) bool {
80+
for _, item := range slice {
81+
if item == s {
82+
return true
83+
}
84+
}
85+
return false
86+
}
87+
88+
func removeString(slice []string, s string) (result []string) {
89+
for _, item := range slice {
90+
if item == s {
91+
continue
92+
}
93+
result = append(result, item)
94+
}
95+
return
96+
}
97+
98+
```
99+
{% endmethod %}

0 commit comments

Comments
 (0)