...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package finalizers
17
18 import (
19 "context"
20
21 "github.com/go-logr/logr"
22 apierrors "k8s.io/apimachinery/pkg/api/errors"
23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 "k8s.io/client-go/util/retry"
25 ctrl "sigs.k8s.io/controller-runtime"
26 "sigs.k8s.io/controller-runtime/pkg/client"
27
28 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
29 "github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder"
30 )
31
32 const (
33
34 AnnotationCleanFinalizer = `chaos-mesh.chaos-mesh.org/cleanFinalizer`
35
36 AnnotationCleanFinalizerForced = `forced`
37
38 RecordFinalizer = "chaos-mesh/records"
39 )
40
41
42 type Reconciler struct {
43
44 Object v1alpha1.InnerObject
45
46
47 client.Client
48
49 Recorder recorder.ChaosRecorder
50
51 Log logr.Logger
52 }
53
54
55 func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
56 obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject)
57
58 if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
59 if apierrors.IsNotFound(err) {
60 r.Log.Info("chaos not found")
61 } else {
62
63 r.Log.Error(err, "unable to get chaos")
64 }
65 return ctrl.Result{}, nil
66 }
67
68 finalizers := obj.GetFinalizers()
69 records := obj.GetStatus().Experiment.Records
70 shouldUpdate := false
71 if obj.IsDeleted() {
72 resumed := true
73 for _, record := range records {
74 if record.Phase != v1alpha1.NotInjected {
75 resumed = false
76 }
77 }
78
79 if obj.GetAnnotations()[AnnotationCleanFinalizer] == AnnotationCleanFinalizerForced || (resumed && len(finalizers) != 0) {
80 r.Recorder.Event(obj, recorder.FinalizerRemoved{})
81 finalizers = []string{}
82 shouldUpdate = true
83 }
84 } else {
85 if !ContainsFinalizer(obj.(metav1.Object), RecordFinalizer) {
86 r.Recorder.Event(obj, recorder.FinalizerInited{})
87 shouldUpdate = true
88 finalizers = append(obj.GetFinalizers(), RecordFinalizer)
89 }
90 }
91
92 if shouldUpdate {
93 updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
94 obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject)
95
96 if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
97 r.Log.Error(err, "unable to get chaos")
98 return err
99 }
100
101 obj.SetFinalizers(finalizers)
102 return r.Client.Update(context.TODO(), obj)
103 })
104 if updateError != nil {
105
106 r.Log.Error(updateError, "fail to update")
107 r.Recorder.Event(obj, recorder.Failed{
108 Activity: "update finalizer",
109 Err: "updateError.Error()",
110 })
111 return ctrl.Result{}, nil
112 }
113
114 r.Recorder.Event(obj, recorder.Updated{
115 Field: "finalizer",
116 })
117 }
118 return ctrl.Result{}, nil
119 }
120
121
122 func ContainsFinalizer(o metav1.Object, finalizer string) bool {
123 f := o.GetFinalizers()
124 for _, e := range f {
125 if e == finalizer {
126 return true
127 }
128 }
129 return false
130 }
131