From fea142774aa90b937d112a79b01b7f40778a538c Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Wed, 9 Apr 2025 18:32:13 +0300 Subject: [PATCH] Delete a Workload if the related object is absent Signed-off-by: Timofei Larkin --- cmd/cozystack-controller/main.go | 9 +++ internal/controller/workload_controller.go | 87 ++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 internal/controller/workload_controller.go diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index 22471047..f1c10c10 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -178,6 +178,15 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "WorkloadMonitor") os.Exit(1) } + + if err = (&controller.WorkloadReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Workload") + os.Exit(1) + } + // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/internal/controller/workload_controller.go b/internal/controller/workload_controller.go new file mode 100644 index 00000000..7b7f8406 --- /dev/null +++ b/internal/controller/workload_controller.go @@ -0,0 +1,87 @@ +package controller + +import ( + "context" + "strings" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" +) + +// WorkloadMonitorReconciler reconciles a WorkloadMonitor object +type WorkloadReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +func (r *WorkloadReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + w := &cozyv1alpha1.Workload{} + err := r.Get(ctx, req.NamespacedName, w) + if err != nil { + if apierrors.IsNotFound(err) { + return ctrl.Result{}, nil + } + logger.Error(err, "Unable to fetch Workload") + return ctrl.Result{}, err + } + + // it's being deleted, nothing to handle + if w.DeletionTimestamp != nil { + return ctrl.Result{}, nil + } + + t := getMonitoredObject(w) + err = r.Get(ctx, types.NamespacedName{Name: t.GetName(), Namespace: t.GetNamespace()}, t) + + // found object, nothing to do + if err == nil { + return ctrl.Result{}, nil + } + + // error getting object but not 404 -- requeue + if !apierrors.IsNotFound(err) { + logger.Error(err, "failed to get dependent object", "kind", t.GetObjectKind(), "dependent-object-name", t.GetName()) + return ctrl.Result{}, err + } + + err = r.Delete(ctx, w) + if err != nil { + logger.Error(err, "failed to delete workload") + } + return ctrl.Result{}, err +} + +// SetupWithManager registers our controller with the Manager and sets up watches. +func (r *WorkloadReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + // Watch WorkloadMonitor objects + For(&cozyv1alpha1.Workload{}). + Complete(r) +} + +func getMonitoredObject(w *cozyv1alpha1.Workload) client.Object { + if strings.HasPrefix(w.Name, "pvc-") { + obj := &corev1.PersistentVolumeClaim{} + obj.Name = strings.TrimPrefix(w.Name, "pvc-") + obj.Namespace = w.Namespace + return obj + } + if strings.HasPrefix(w.Name, "svc-") { + obj := &corev1.Service{} + obj.Name = strings.TrimPrefix(w.Name, "svc-") + obj.Namespace = w.Namespace + return obj + } + obj := &corev1.Pod{} + obj.Name = w.Name + obj.Namespace = w.Namespace + return obj +}