Unverified Commit d7012f26 authored by Cwen Yin's avatar Cwen Yin Committed by GitHub
Browse files

Add cleanFinalizer controller (#3584)


* fix conflicts
Signed-off-by: default avatarCwen Yin <cwenyin0@gmail.com>

* address comments
Signed-off-by: default avatarCwen Yin <cwenyin0@gmail.com>

* update comments
Signed-off-by: default avatarCwen Yin <cwenyin0@gmail.com>

* fix CI
Signed-off-by: default avatarCwen Yin <cwenyin0@gmail.com>

* address comments
Signed-off-by: default avatarCwen Yin <cwenyin0@gmail.com>

* fix CI
Signed-off-by: default avatarCwen Yin <cwenyin0@gmail.com>
Signed-off-by: default avatarCwen Yin <cwenyin0@gmail.com>
Showing with 98 additions and 46 deletions
+98 -46
......@@ -38,6 +38,7 @@ For more information and how-to, see [RFC: Keep A Changelog](https://github.com/
- Fix BlockChaos can't show Chinese name. [#3536](https://github.com/chaos-mesh/chaos-mesh/pull/3536)
- Add `omitempty` JSON tag to optional fields of the CRD objects. [#3531](https://github.com/chaos-mesh/chaos-mesh/pull/3531)
- Fix "sidecar config" e2e test cases run failed in some scenario.[#3564](https://github.com/chaos-mesh/chaos-mesh/pull/3564)
- Fix recover bug when setting force recover to true [#3578](https://github.com/chaos-mesh/chaos-mesh/pull/3578)
- Fix Integration test with bumping kubectl version. [#3589](https://github.com/chaos-mesh/chaos-mesh/pull/3589)
### Security
......
......@@ -2,7 +2,7 @@
Death controller controls the `.ObjectMeta.Finalizers` field:
1. If the object has been deleted, iterate over the `records`, and if all of them are "not injected", remove the finalizer
and go to step 3
2. If the object don't have a finalizer, add one for it.
3. If the finalizer has been updated, upload them to kubernetes server.
1. If the object don't have a finalizer, add one for it.
2. If the finalizer has been updated, upload them to kubernetes server.
3. If the object has been deleted, and it includes `clenFinalizerForced` annotation, removes the finalizer,
or iterates over the `records`, and if all of them are "not injected", remove the finalizer.
......@@ -38,8 +38,8 @@ const (
RecordFinalizer = "chaos-mesh/records"
)
// Reconciler for common chaos
type Reconciler struct {
// ReconcilerMeta defines the meta of InitReconciler and CleanReconciler struct.
type ReconcilerMeta struct {
// Object is used to mark the target type of this Reconciler
Object v1alpha1.InnerObject
......@@ -51,8 +51,43 @@ type Reconciler struct {
Log logr.Logger
}
// Reconcile the common chaos
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// InitReconciler for common chaos to init the finalizer
type InitReconciler struct {
ReconcilerMeta
}
// Reconcile the common chaos to init the finalizer
func (r *InitReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject)
if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
if apierrors.IsNotFound(err) {
r.Log.Info("chaos not found")
} else {
// TODO: handle this error
r.Log.Error(err, "unable to get chaos")
}
return ctrl.Result{}, nil
}
if !obj.IsDeleted() {
if !ContainsFinalizer(obj.(metav1.Object), RecordFinalizer) {
r.Recorder.Event(obj, recorder.FinalizerInited{})
finalizers := append(obj.GetFinalizers(), RecordFinalizer)
return updateFinalizer(r.ReconcilerMeta, obj, req, finalizers)
}
}
return ctrl.Result{}, nil
}
// CleanReconciler for common chaos to clean the finalizer
type CleanReconciler struct {
ReconcilerMeta
}
// Reconcile the common chaos to clean the finalizer
func (r *CleanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject)
if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
......@@ -67,7 +102,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
finalizers := obj.GetFinalizers()
records := obj.GetStatus().Experiment.Records
shouldUpdate := false
if obj.IsDeleted() {
resumed := true
for _, record := range records {
......@@ -79,42 +113,38 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
if obj.GetAnnotations()[AnnotationCleanFinalizer] == AnnotationCleanFinalizerForced || (resumed && len(finalizers) != 0) {
r.Recorder.Event(obj, recorder.FinalizerRemoved{})
finalizers = []string{}
shouldUpdate = true
}
} else {
if !ContainsFinalizer(obj.(metav1.Object), RecordFinalizer) {
r.Recorder.Event(obj, recorder.FinalizerInited{})
shouldUpdate = true
finalizers = append(obj.GetFinalizers(), RecordFinalizer)
return updateFinalizer(r.ReconcilerMeta, obj, req, finalizers)
}
}
if shouldUpdate {
updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject)
return ctrl.Result{}, nil
}
if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
r.Log.Error(err, "unable to get chaos")
return err
}
func updateFinalizer(r ReconcilerMeta, obj v1alpha1.InnerObject, req ctrl.Request, finalizers []string) (ctrl.Result, error) {
updateError := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
obj := r.Object.DeepCopyObject().(v1alpha1.InnerObject)
obj.SetFinalizers(finalizers)
return r.Client.Update(context.TODO(), obj)
})
if updateError != nil {
// TODO: handle this error
r.Log.Error(updateError, "fail to update")
r.Recorder.Event(obj, recorder.Failed{
Activity: "update finalizer",
Err: "updateError.Error()",
})
return ctrl.Result{}, nil
if err := r.Client.Get(context.TODO(), req.NamespacedName, obj); err != nil {
r.Log.Error(err, "unable to get chaos")
return err
}
r.Recorder.Event(obj, recorder.Updated{
Field: "finalizer",
obj.SetFinalizers(finalizers)
return r.Client.Update(context.TODO(), obj)
})
if updateError != nil {
// TODO: handle this error
r.Log.Error(updateError, "fail to update")
r.Recorder.Event(obj, recorder.Failed{
Activity: "update finalizer",
Err: "updateError.Error()",
})
return ctrl.Result{}, nil
}
r.Recorder.Event(obj, recorder.Updated{
Field: "finalizer",
})
return ctrl.Result{}, nil
}
......
......@@ -22,19 +22,40 @@ import (
"github.com/chaos-mesh/chaos-mesh/controllers/config"
)
func Step(ctx *pipeline.PipelineContext) reconcile.Reconciler {
setupLog := ctx.Logger.WithName("setup-finalizers")
name := ctx.Object.Name + "-finalizers"
func InitStep(ctx *pipeline.PipelineContext) reconcile.Reconciler {
setupLog := ctx.Logger.WithName("setup-initFinalizers")
name := ctx.Object.Name + "-initFinalizers"
if !config.ShouldSpawnController(name) {
return nil
}
setupLog.Info("setting up controller", "name", name)
return &Reconciler{
Object: ctx.Object.Object,
Client: ctx.Client,
Recorder: ctx.RecorderBuilder.Build("finalizers"),
Log: ctx.Logger.WithName("finalizers"),
return &InitReconciler{
ReconcilerMeta{
Object: ctx.Object.Object,
Client: ctx.Client,
Recorder: ctx.RecorderBuilder.Build("initFinalizers"),
Log: ctx.Logger.WithName("initFinalizers"),
},
}
}
func CleanStep(ctx *pipeline.PipelineContext) reconcile.Reconciler {
setupLog := ctx.Logger.WithName("setup-cleanFinalizers")
name := ctx.Object.Name + "-cleanFinalizers"
if !config.ShouldSpawnController(name) {
return nil
}
setupLog.Info("setting up controller", "name", name)
return &CleanReconciler{
ReconcilerMeta{
Object: ctx.Object.Object,
Client: ctx.Client,
Recorder: ctx.RecorderBuilder.Build("initFinalizers"),
Log: ctx.Logger.WithName("initFinalizers"),
},
}
}
......@@ -24,5 +24,5 @@ import (
)
func AllSteps() []pipeline.PipelineStep {
return []pipeline.PipelineStep{finalizers.Step, desiredphase.Step, condition.Step, records.Step}
return []pipeline.PipelineStep{finalizers.InitStep, desiredphase.Step, condition.Step, records.Step, finalizers.CleanStep}
}
......@@ -100,7 +100,7 @@ var _ = BeforeSuite(func() {
selector.Module,
fx.Provide(chaosdaemon.New),
fx.Provide(func() []pipeline.PipelineStep {
return []pipeline.PipelineStep{finalizers.Step, desiredphase.Step, condition.Step}
return []pipeline.PipelineStep{finalizers.InitStep, desiredphase.Step, condition.Step, finalizers.CleanStep}
}),
fx.Invoke(Bootstrap),
fx.Supply(cfg),
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment