From 6c51706a921c4a848af7273c729e74bf5ef67da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D1=81=D0=B5=D0=B2=D0=BE=D0=BB=D0=BE=D0=B4=20=D0=93?= =?UTF-8?q?=D0=BE=D0=BB=D0=B5=D0=BD=D0=BA=D0=BE=D0=B2?= Date: Tue, 4 Jun 2024 14:29:34 +0300 Subject: [PATCH] add resizing operation --- internal/controller/etcdcluster_controller.go | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/internal/controller/etcdcluster_controller.go b/internal/controller/etcdcluster_controller.go index d3834494..1d24d020 100644 --- a/internal/controller/etcdcluster_controller.go +++ b/internal/controller/etcdcluster_controller.go @@ -20,6 +20,7 @@ import ( "context" goerrors "errors" "fmt" + "reflect" policyv1 "k8s.io/api/policy/v1" "sigs.k8s.io/controller-runtime/pkg/log" @@ -37,6 +38,8 @@ import ( etcdaenixiov1alpha1 "github.com/aenix-io/etcd-operator/api/v1alpha1" "github.com/aenix-io/etcd-operator/internal/controller/factory" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // EtcdClusterReconciler reconciles a EtcdCluster object @@ -67,22 +70,64 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) // Error retrieving object, requeue return reconcile.Result{}, err } + // If object is being deleted, skipping reconciliation if !instance.DeletionTimestamp.IsZero() { return reconcile.Result{}, nil } - // fill conditions - if len(instance.Status.Conditions) == 0 { - factory.FillConditions(instance) - } - - // ensure managed resources + // Ensure managed resources if err := r.ensureClusterObjects(ctx, instance); err != nil { logger.Error(err, "cannot create Cluster auxiliary objects") return r.updateStatusOnErr(ctx, instance, fmt.Errorf("cannot create Cluster auxiliary objects: %w", err)) } + // Check if StatefulSet exists + statefulSet := &appsv1.StatefulSet{} + err = r.Get(ctx, client.ObjectKey{Name: instance.Name, Namespace: instance.Namespace}, statefulSet) + if err != nil { + if errors.IsNotFound(err) { + logger.V(2).Info("StatefulSet not found, skipping storage check", "namespaced_name", req.NamespacedName) + } else { + return reconcile.Result{}, err + } + } else { + // Check if storage size has changed + if len(statefulSet.Spec.VolumeClaimTemplates) > 0 { + pvcName := statefulSet.Spec.VolumeClaimTemplates[0].Name + pvc := &corev1.PersistentVolumeClaim{} + err = r.Get(ctx, client.ObjectKey{Name: pvcName, Namespace: instance.Namespace}, pvc) + if err != nil { + if errors.IsNotFound(err) { + logger.V(2).Info("PVC not found, skipping storage check", "pvc_name", pvcName) + } else { + return reconcile.Result{}, err + } + } else { + desiredStorage := instance.Spec.Storage.VolumeClaimTemplate.Spec.Resources.Requests[corev1.ResourceStorage] + currentStorage := pvc.Spec.Resources.Requests[corev1.ResourceStorage] + + if !reflect.DeepEqual(desiredStorage, currentStorage) { + // Delete the StatefulSet with --cascade=orphan + deletePolicy := metav1.DeletePropagationOrphan + logger.Info("Deleting StatefulSet due to storage change", "statefulSet", statefulSet.Name) + err := r.Delete(ctx, statefulSet, &client.DeleteOptions{PropagationPolicy: &deletePolicy}) + if err != nil { + logger.Error(err, "failed to delete StatefulSet") + return reconcile.Result{}, err + } + } + } + } else { + logger.V(2).Info("No VolumeClaimTemplates found in StatefulSet") + } + } + + // fill conditions + if len(instance.Status.Conditions) == 0 { + factory.FillConditions(instance) + } + // set cluster initialization condition factory.SetCondition(instance, factory.NewCondition(etcdaenixiov1alpha1.EtcdConditionInitialized). WithStatus(true).