Skip to content
7 changes: 3 additions & 4 deletions pkg/controller/perconaservermongodb/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package perconaservermongodb

import (
"context"
"maps"

"github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1"
Expand Down Expand Up @@ -183,12 +184,10 @@ func (r *ReconcilePerconaServerMongoDB) getStatefulsetFromReplset(ctx context.Co
if err != nil {
return nil, errors.Wrap(err, "failed to get ssl annotations")
}
for k, v := range sslAnn {
sfsSpec.Template.Annotations[k] = v
}
maps.Copy(sfsSpec.Template.Annotations, sslAnn)

if preservedValue, exists := cr.Annotations[api.AnnotationPreservedRestartedAt(sfs.Name)]; exists {
sfsSpec.Template.Annotations["kubectl.kubernetes.io/restartedAt"] = preservedValue
sfsSpec.Template.Annotations[naming.AnnotationKubectlRestartedAt] = preservedValue
}

return sfs, nil
Expand Down
5 changes: 0 additions & 5 deletions pkg/controller/perconaservermongodb/volume_autoscaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,6 @@ func (r *ReconcilePerconaServerMongoDB) calculateNewSize(
newSizeBytes := currentSize.Value() + config.GrowthStep.Value()
newSize := *resource.NewQuantity(newSizeBytes, resource.BinarySI)

gib, err := RoundUpGiB(newSize.Value())
if err == nil {
newSize = *resource.NewQuantity(gib*GiB, resource.BinarySI)
}

if !config.MaxSize.IsZero() && newSize.Cmp(config.MaxSize) > 0 {
newSize = config.MaxSize
}
Expand Down
113 changes: 57 additions & 56 deletions pkg/controller/perconaservermongodb/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package perconaservermongodb

import (
"context"
"math"
"maps"
"slices"
"strings"
"time"
Comment thread
pooknull marked this conversation as resolved.
Expand All @@ -19,19 +19,14 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"

api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1"
psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1"
"github.com/percona/percona-server-mongodb-operator/pkg/k8s"
"github.com/percona/percona-server-mongodb-operator/pkg/naming"
"github.com/percona/percona-server-mongodb-operator/pkg/psmdb/config"
"github.com/percona/percona-server-mongodb-operator/pkg/util"
)

const (
GiB = int64(1024 * 1024 * 1024)
)

func (r *ReconcilePerconaServerMongoDB) reconcilePVCs(ctx context.Context, cr *api.PerconaServerMongoDB, sts *appsv1.StatefulSet, ls map[string]string, volumeSpec *api.VolumeSpec) error {
func (r *ReconcilePerconaServerMongoDB) reconcilePVCs(ctx context.Context, cr *psmdbv1.PerconaServerMongoDB, sts *appsv1.StatefulSet, ls map[string]string, volumeSpec *psmdbv1.VolumeSpec) error {
if err := r.fixVolumeLabels(ctx, sts, ls, volumeSpec.PersistentVolumeClaim); err != nil {
return errors.Wrap(err, "fix volume labels")
}
Expand All @@ -47,7 +42,7 @@ func validatePVCName(pvc corev1.PersistentVolumeClaim, sts *appsv1.StatefulSet)
return strings.HasPrefix(pvc.Name, config.MongodDataVolClaimName+"-"+sts.Name)
}

func (r *ReconcilePerconaServerMongoDB) resizeVolumesIfNeeded(ctx context.Context, cr *psmdbv1.PerconaServerMongoDB, sts *appsv1.StatefulSet, ls map[string]string, volumeSpec *api.VolumeSpec) error {
func (r *ReconcilePerconaServerMongoDB) resizeVolumesIfNeeded(ctx context.Context, cr *psmdbv1.PerconaServerMongoDB, sts *appsv1.StatefulSet, ls map[string]string, volumeSpec *psmdbv1.VolumeSpec) error {
if cr.Spec.IsExternalVolumeAutoscalingEnabled() {
return nil
}
Expand Down Expand Up @@ -130,13 +125,6 @@ func (r *ReconcilePerconaServerMongoDB) resizeVolumesIfNeeded(ctx context.Contex
}

requested := pvcSpec.Resources.Requests[corev1.ResourceStorage]
originalRequested := requested.DeepCopy()
gib, err := RoundUpGiB(requested.Value())
if err != nil {
return errors.Wrap(err, "round GiB value")
}

requested = *resource.NewQuantity(gib*GiB, resource.BinarySI)
configured := volumeTemplate.Spec.Resources.Requests[corev1.ResourceStorage]

if sts.Annotations[psmdbv1.AnnotationPVCResizeInProgress] != "" {
Expand All @@ -147,11 +135,11 @@ func (r *ReconcilePerconaServerMongoDB) resizeVolumesIfNeeded(ctx context.Contex

updatedPVCs := 0
for _, pvc := range pvcList.Items {
if !validatePVCName(pvc, sts) {
if !slices.Contains(pvcsToUpdate, pvc.Name) {
continue
}

if pvc.Status.Capacity.Storage().Cmp(requested) == 0 {
if pvc.Status.Capacity.Storage().Cmp(requested) >= 0 {
updatedPVCs++
log.Info("PVC resize finished", "name", pvc.Name, "size", pvc.Status.Capacity.Storage())
continue
Expand Down Expand Up @@ -207,17 +195,8 @@ func (r *ReconcilePerconaServerMongoDB) resizeVolumesIfNeeded(ctx context.Contex
if updatedPVCs == len(pvcsToUpdate) {
log.Info("Deleting statefulset")

if restartedAtValue, exists := sts.Spec.Template.Annotations["kubectl.kubernetes.io/restartedAt"]; exists {
if err := k8s.AnnotateObject(ctx, r.client, cr, map[string]string{psmdbv1.AnnotationPreservedRestartedAt(sts.Name): restartedAtValue}); err != nil {
log.V(1).Info("Failed to preserve restartedAt annotation, continuing", "error", err, "sts", sts.Name)
}
}

if err := r.client.Delete(ctx, sts, client.PropagationPolicy("Orphan")); err != nil {
if k8serrors.IsNotFound(err) {
return nil
}
return errors.Wrapf(err, "delete statefulset/%s", sts.Name)
if err := r.deleteStatefulSetForResize(ctx, cr, sts); err != nil {
return err
}

log.Info("PVC resize completed")
Expand All @@ -227,10 +206,32 @@ func (r *ReconcilePerconaServerMongoDB) resizeVolumesIfNeeded(ctx context.Contex
}

if requested.Cmp(actual) < 0 {
return errors.Errorf("requested storage (%s) is less than actual storage (%s)", requested.String(), actual.String())
if configured.Cmp(requested) == 0 {
return nil
}
if configured.Cmp(requested) < 0 {
log.Info("Deleting statefulset with stale volume claim template")

if err := r.deleteStatefulSetForResize(ctx, cr, sts); err != nil {
return err
}
Comment thread
pooknull marked this conversation as resolved.
return nil
}
if err := r.revertVolumeTemplate(ctx, cr, sts, configured); err != nil {
return errors.Wrapf(err, "revert volume template for sts/%s", sts.Name)
}
if cr.Spec.IsVolumeExpansionEnabled() {
return errors.Errorf("requested storage (%s) is less than actual storage (%s)", requested.String(), actual.String())
}
}
if requested.Cmp(actual) == 0 {
if configured.Cmp(requested) != 0 {
log.Info("Deleting statefulset with stale volume claim template")

if actual.Cmp(originalRequested) >= 0 {
if err := r.deleteStatefulSetForResize(ctx, cr, sts); err != nil {
return err
}
Comment thread
pooknull marked this conversation as resolved.
}
return nil
}

Expand Down Expand Up @@ -296,6 +297,29 @@ func (r *ReconcilePerconaServerMongoDB) resizeVolumesIfNeeded(ctx context.Contex
return nil
}

func (r *ReconcilePerconaServerMongoDB) deleteStatefulSetForResize(
ctx context.Context,
cr *psmdbv1.PerconaServerMongoDB,
sts *appsv1.StatefulSet,
) error {
log := logf.FromContext(ctx).WithName("PVCResize").WithValues("sts", sts.Name)

if restartedAtValue, exists := sts.Spec.Template.Annotations[naming.AnnotationKubectlRestartedAt]; exists {
if err := k8s.AnnotateObject(ctx, r.client, cr, map[string]string{psmdbv1.AnnotationPreservedRestartedAt(sts.Name): restartedAtValue}); err != nil {
log.V(1).Info("Failed to preserve restartedAt annotation, continuing", "error", err)
}
}

if err := r.client.Delete(ctx, sts, client.PropagationPolicy(metav1.DeletePropagationOrphan)); err != nil {
if k8serrors.IsNotFound(err) {
return nil
}
return errors.Wrapf(err, "delete statefulset/%s", sts.Name)
}

return nil
}

func (r *ReconcilePerconaServerMongoDB) handlePVCResizeFailure(ctx context.Context, cr *psmdbv1.PerconaServerMongoDB, sts *appsv1.StatefulSet, originalSize resource.Quantity) error {
if err := r.revertVolumeTemplate(ctx, cr, sts, originalSize); err != nil {
return errors.Wrapf(err, "revert volume template for sts/%s", sts.Name)
Expand Down Expand Up @@ -353,19 +377,13 @@ func (r *ReconcilePerconaServerMongoDB) fixVolumeLabels(ctx context.Context, sts
if pvc.Labels == nil {
pvc.Labels = make(map[string]string)
}
for k, v := range pvcSpec.Labels {
pvc.Labels[k] = v
}
for k, v := range sts.Labels {
pvc.Labels[k] = v
}
maps.Copy(pvc.Labels, pvcSpec.Labels)
maps.Copy(pvc.Labels, sts.Labels)

if pvc.Annotations == nil {
pvc.Annotations = make(map[string]string)
}
for k, v := range pvcSpec.Annotations {
pvc.Annotations[k] = v
}
maps.Copy(pvc.Annotations, pvcSpec.Annotations)

if util.MapEqual(orig.Labels, pvc.Labels) && util.MapEqual(orig.Annotations, pvc.Annotations) {
continue
Expand All @@ -379,20 +397,3 @@ func (r *ReconcilePerconaServerMongoDB) fixVolumeLabels(ctx context.Context, sts

return nil
}
Comment thread
pooknull marked this conversation as resolved.

func roundUpSize(volumeSizeBytes int64, allocationUnitBytes int64) int64 {
if allocationUnitBytes == 0 {
return 0 // Avoid division by zero
}
return (volumeSizeBytes + allocationUnitBytes - 1) / allocationUnitBytes
}

// RoundUpGiB rounds up the volume size in bytes upto multiplications of GiB
// in the unit of GiB
func RoundUpGiB(volumeSizeBytes int64) (int64, error) {
result := roundUpSize(volumeSizeBytes, GiB)
if result > int64(math.MaxInt64) {
return 0, errors.Errorf("rounded up size exceeds maximum value of int64: %d", result)
}
return result, nil
}
Loading
Loading