...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package condition
17
18 import (
19 "context"
20 "reflect"
21
22 "github.com/go-logr/logr"
23 corev1 "k8s.io/api/core/v1"
24 apierrors "k8s.io/apimachinery/pkg/api/errors"
25 "k8s.io/apimachinery/pkg/runtime"
26 "k8s.io/client-go/tools/record"
27 "k8s.io/client-go/util/retry"
28 ctrl "sigs.k8s.io/controller-runtime"
29 "sigs.k8s.io/controller-runtime/pkg/client"
30
31 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
32 )
33
34
35 type Reconciler struct {
36
37 Object runtime.Object
38
39
40 client.Client
41
42 Recorder record.EventRecorder
43
44 Log logr.Logger
45 }
46
47 type StatusAndReason struct {
48 Status corev1.ConditionStatus
49 Reason string
50 }
51
52 func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
53 obj := r.Object.DeepCopyObject().(v1alpha1.InnerObjectWithSelector)
54 if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
55 if apierrors.IsNotFound(err) {
56 r.Log.Info("chaos not found")
57 } else {
58
59 r.Log.Error(err, "unable to get chaos")
60 }
61 return ctrl.Result{}, nil
62 }
63
64 updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
65 conditionMap := make(map[v1alpha1.ChaosConditionType]StatusAndReason)
66 for _, c := range obj.GetStatus().Conditions {
67 conditionMap[c.Type] = StatusAndReason{
68 Status: c.Status,
69 Reason: c.Reason,
70 }
71 }
72
73 newConditionMap := make(map[v1alpha1.ChaosConditionType]StatusAndReason)
74 if obj.GetStatus().Experiment.Records != nil {
75 newConditionMap[v1alpha1.ConditionSelected] = StatusAndReason{
76 Status: corev1.ConditionTrue,
77 }
78 } else {
79 newConditionMap[v1alpha1.ConditionSelected] = StatusAndReason{
80 Status: corev1.ConditionFalse,
81 }
82 }
83
84 allInjected := corev1.ConditionTrue
85 allRecovered := corev1.ConditionTrue
86 for _, record := range obj.GetStatus().Experiment.Records {
87 if record.Phase != v1alpha1.NotInjected {
88 allRecovered = corev1.ConditionFalse
89 }
90
91 if record.Phase != v1alpha1.Injected {
92 allInjected = corev1.ConditionFalse
93 }
94 }
95 newConditionMap[v1alpha1.ConditionAllInjected] = StatusAndReason{
96 Status: allInjected,
97 }
98 newConditionMap[v1alpha1.ConditionAllRecovered] = StatusAndReason{
99 Status: allRecovered,
100 }
101
102 if obj.IsPaused() {
103 newConditionMap[v1alpha1.ConditionPaused] = StatusAndReason{
104 Status: corev1.ConditionTrue,
105 }
106 } else {
107 newConditionMap[v1alpha1.ConditionPaused] = StatusAndReason{
108 Status: corev1.ConditionFalse,
109 }
110 }
111
112 if !reflect.DeepEqual(newConditionMap, conditionMap) {
113 conditions := make([]v1alpha1.ChaosCondition, 0, 5)
114 for k, v := range newConditionMap {
115 conditions = append(conditions, v1alpha1.ChaosCondition{
116 Type: k,
117 Status: v.Status,
118 Reason: v.Reason,
119 })
120 }
121
122 r.Log.Info("updating conditions", "conditions", conditions)
123 obj := r.Object.DeepCopyObject().(v1alpha1.InnerObjectWithSelector)
124
125 if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
126 r.Log.Error(err, "unable to get chaos")
127 return err
128 }
129
130 obj.GetStatus().Conditions = conditions
131 return r.Client.Update(context.TODO(), obj)
132 }
133
134 return nil
135 })
136
137 if updateError != nil {
138 r.Log.Error(updateError, "fail to update")
139 r.Recorder.Eventf(obj, "Normal", "Failed", "Failed to update conditions: %s", updateError.Error())
140 return ctrl.Result{}, nil
141 }
142 return ctrl.Result{}, nil
143 }
144