From 4ad00ca1dcbad0832fa0349ef7963d7a758f6c6d Mon Sep 17 00:00:00 2001 From: kabicin Date: Wed, 13 Jul 2022 17:21:49 -0400 Subject: [PATCH 1/2] Add volume to StatefulSet after initial creation --- controllers/runtimecomponent_controller.go | 56 +++++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/controllers/runtimecomponent_controller.go b/controllers/runtimecomponent_controller.go index 2b7bae737..60e000f60 100644 --- a/controllers/runtimecomponent_controller.go +++ b/controllers/runtimecomponent_controller.go @@ -354,22 +354,40 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req reqLogger.Error(err, "Failed to reconcile headless Service") return r.ManageError(err, common.StatusConditionTypeReconciled, instance) } - statefulSet := &appsv1.StatefulSet{ObjectMeta: defaultMeta} - err = r.CreateOrUpdate(statefulSet, instance, func() error { - appstacksutils.CustomizeStatefulSet(statefulSet, instance) - appstacksutils.CustomizePodSpec(&statefulSet.Spec.Template, instance) - if err := appstacksutils.CustomizePodWithSVCCertificate(&statefulSet.Spec.Template, instance, r.GetClient()); err != nil { - return err - } - appstacksutils.CustomizePersistence(statefulSet, instance) - return nil - }) + err = r.CreateOrUpdate(statefulSet, instance, getStatefulSetMutateFn(statefulSet, instance, r.GetClient())) if err != nil { - reqLogger.Error(err, "Failed to reconcile StatefulSet") - return r.ManageError(err, common.StatusConditionTypeReconciled, instance) + // if the StatefulSet exists + if err = r.GetClient().Get(context.TODO(), req.NamespacedName, statefulSet); err == nil { + var isStatefulSetStorageLoaded bool + if len(statefulSet.Spec.Template.Spec.Containers) > 0 && len(statefulSet.Spec.VolumeClaimTemplates) > 0 { + appContainer := appstacksutils.GetAppContainer(statefulSet.Spec.Template.Spec.Containers) + for i := 0; i < len(appContainer.VolumeMounts); i++ { + if appContainer.VolumeMounts[i].Name == statefulSet.Spec.VolumeClaimTemplates[0].Name { + isStatefulSetStorageLoaded = true + } + } + } + // if storage has already been initialized recreate the StatefulSet + if !isStatefulSetStorageLoaded { + statefulSet = &appsv1.StatefulSet{ObjectMeta: defaultMeta} + err = r.DeleteResource(statefulSet) + if err != nil { + reqLogger.Error(err, "Failed to delete Statefulset") + return r.ManageError(err, common.StatusConditionTypeReconciled, instance) + } + err = r.CreateOrUpdate(statefulSet, instance, getStatefulSetMutateFn(statefulSet, instance, r.GetClient())) + if err != nil { + reqLogger.Error(err, "Failed to recreate Statefulset") + return r.ManageError(err, common.StatusConditionTypeReconciled, instance) + } + } + } + if err != nil { + reqLogger.Error(err, "Failed to reconcile StatefulSet") + return r.ManageError(err, common.StatusConditionTypeReconciled, instance) + } } - } else { // Delete StatefulSet if exists statefulSet := &appsv1.StatefulSet{ObjectMeta: defaultMeta} @@ -622,3 +640,15 @@ func (r *RuntimeComponentReconciler) SetupWithManager(mgr ctrl.Manager) error { func getMonitoringEnabledLabelName(ba common.BaseComponent) string { return "monitor." + ba.GetGroupName() + "/enabled" } + +func getStatefulSetMutateFn(statefulSet *appsv1.StatefulSet, ba common.BaseComponent, client client.Client) func() error { + return func() error { + appstacksutils.CustomizeStatefulSet(statefulSet, ba) + appstacksutils.CustomizePodSpec(&statefulSet.Spec.Template, ba) + if err := appstacksutils.CustomizePodWithSVCCertificate(&statefulSet.Spec.Template, ba, client); err != nil { + return err + } + appstacksutils.CustomizePersistence(statefulSet, ba) + return nil + } +} From e27aaaac781737a38a3874c25c91d43be8698bfa Mon Sep 17 00:00:00 2001 From: kabicin Date: Thu, 14 Jul 2022 13:13:18 -0400 Subject: [PATCH 2/2] Added isStatefulSetStorageUninitialized helper --- controllers/runtimecomponent_controller.go | 52 +++++++++++----------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/controllers/runtimecomponent_controller.go b/controllers/runtimecomponent_controller.go index 60e000f60..306be3e0a 100644 --- a/controllers/runtimecomponent_controller.go +++ b/controllers/runtimecomponent_controller.go @@ -357,33 +357,20 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req statefulSet := &appsv1.StatefulSet{ObjectMeta: defaultMeta} err = r.CreateOrUpdate(statefulSet, instance, getStatefulSetMutateFn(statefulSet, instance, r.GetClient())) if err != nil { - // if the StatefulSet exists - if err = r.GetClient().Get(context.TODO(), req.NamespacedName, statefulSet); err == nil { - var isStatefulSetStorageLoaded bool - if len(statefulSet.Spec.Template.Spec.Containers) > 0 && len(statefulSet.Spec.VolumeClaimTemplates) > 0 { - appContainer := appstacksutils.GetAppContainer(statefulSet.Spec.Template.Spec.Containers) - for i := 0; i < len(appContainer.VolumeMounts); i++ { - if appContainer.VolumeMounts[i].Name == statefulSet.Spec.VolumeClaimTemplates[0].Name { - isStatefulSetStorageLoaded = true - } - } + // if storage is uninitialized, recreate the StatefulSet + if isStatefulSetStorageUninitialized(statefulSet, req.NamespacedName, r.GetClient()) { + statefulSet = &appsv1.StatefulSet{ObjectMeta: defaultMeta} + err = r.DeleteResource(statefulSet) + if err != nil { + reqLogger.Error(err, "Failed to delete StatefulSet") + return r.ManageError(err, common.StatusConditionTypeReconciled, instance) } - // if storage has already been initialized recreate the StatefulSet - if !isStatefulSetStorageLoaded { - statefulSet = &appsv1.StatefulSet{ObjectMeta: defaultMeta} - err = r.DeleteResource(statefulSet) - if err != nil { - reqLogger.Error(err, "Failed to delete Statefulset") - return r.ManageError(err, common.StatusConditionTypeReconciled, instance) - } - err = r.CreateOrUpdate(statefulSet, instance, getStatefulSetMutateFn(statefulSet, instance, r.GetClient())) - if err != nil { - reqLogger.Error(err, "Failed to recreate Statefulset") - return r.ManageError(err, common.StatusConditionTypeReconciled, instance) - } + err = r.CreateOrUpdate(statefulSet, instance, getStatefulSetMutateFn(statefulSet, instance, r.GetClient())) + if err != nil { + reqLogger.Error(err, "Failed to create StatefulSet") + return r.ManageError(err, common.StatusConditionTypeReconciled, instance) } - } - if err != nil { + } else { reqLogger.Error(err, "Failed to reconcile StatefulSet") return r.ManageError(err, common.StatusConditionTypeReconciled, instance) } @@ -652,3 +639,18 @@ func getStatefulSetMutateFn(statefulSet *appsv1.StatefulSet, ba common.BaseCompo return nil } } + +func isStatefulSetStorageUninitialized(statefulSet *appsv1.StatefulSet, namespacedName types.NamespacedName, client client.Client) bool { + if statefulSetErr := client.Get(context.TODO(), namespacedName, statefulSet); statefulSetErr != nil { + return false + } + if len(statefulSet.Spec.Template.Spec.Containers) > 0 && len(statefulSet.Spec.VolumeClaimTemplates) > 0 { + appContainer := appstacksutils.GetAppContainer(statefulSet.Spec.Template.Spec.Containers) + for i := 0; i < len(appContainer.VolumeMounts); i++ { + if appContainer.VolumeMounts[i].Name == statefulSet.Spec.VolumeClaimTemplates[0].Name { + return false + } + } + } + return true +}