...
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 ReconcilerMeta 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 type InitReconciler struct {
56 ReconcilerMeta
57 }
58
59
60 func (r *InitReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
61 obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject)
62
63 if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
64 if apierrors.IsNotFound(err) {
65 r.Log.Info("chaos not found")
66 } else {
67
68 r.Log.Error(err, "unable to get chaos")
69 }
70 return ctrl.Result{}, nil
71 }
72
73 if !obj.IsDeleted() {
74 if !ContainsFinalizer(obj.(metav1.Object), RecordFinalizer) {
75 r.Recorder.Event(obj, recorder.FinalizerInited{})
76 finalizers := append(obj.GetFinalizers(), RecordFinalizer)
77 return updateFinalizer(r.ReconcilerMeta, obj, req, finalizers)
78 }
79 }
80
81 return ctrl.Result{}, nil
82 }
83
84
85 type CleanReconciler struct {
86 ReconcilerMeta
87 }
88
89
90 func (r *CleanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
91 obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject)
92
93 if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
94 if apierrors.IsNotFound(err) {
95 r.Log.Info("chaos not found")
96 } else {
97
98 r.Log.Error(err, "unable to get chaos")
99 }
100 return ctrl.Result{}, nil
101 }
102
103 finalizers := obj.GetFinalizers()
104 records := obj.GetStatus().Experiment.Records
105 if obj.IsDeleted() {
106 resumed := true
107 for _, record := range records {
108 if record.Phase != v1alpha1.NotInjected {
109 resumed = false
110 }
111 }
112
113 if obj.GetAnnotations()[AnnotationCleanFinalizer] == AnnotationCleanFinalizerForced || (resumed && len(finalizers) != 0) {
114 r.Recorder.Event(obj, recorder.FinalizerRemoved{})
115 finalizers = []string{}
116 return updateFinalizer(r.ReconcilerMeta, obj, req, finalizers)
117 }
118 }
119
120 return ctrl.Result{}, nil
121 }
122
123 func updateFinalizer(r ReconcilerMeta, obj v1alpha1.InnerObject, req ctrl.Request, finalizers []string) (ctrl.Result, error) {
124 updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
125 obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject)
126
127 if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
128 r.Log.Error(err, "unable to get chaos")
129 return err
130 }
131
132 obj.SetFinalizers(finalizers)
133 return r.Client.Update(context.TODO(), obj)
134 })
135 if updateError != nil {
136
137 r.Log.Error(updateError, "fail to update")
138 r.Recorder.Event(obj, recorder.Failed{
139 Activity: "update finalizer",
140 Err: "updateError.Error()",
141 })
142 return ctrl.Result{}, nil
143 }
144
145 r.Recorder.Event(obj, recorder.Updated{
146 Field: "finalizer",
147 })
148 return ctrl.Result{}, nil
149 }
150
151
152 func ContainsFinalizer(o metav1.Object, finalizer string) bool {
153 f := o.GetFinalizers()
154 for _, e := range f {
155 if e == finalizer {
156 return true
157 }
158 }
159 return false
160 }
161