github.com/percona/percona-xtradb-cluster-operator@v1.14.0/pkg/controller/pxc/volumes.go (about) 1 package pxc 2 3 import ( 4 "context" 5 "slices" 6 "strings" 7 8 "github.com/pkg/errors" 9 corev1 "k8s.io/api/core/v1" 10 k8serrors "k8s.io/apimachinery/pkg/api/errors" 11 "sigs.k8s.io/controller-runtime/pkg/client" 12 logf "sigs.k8s.io/controller-runtime/pkg/log" 13 14 api "github.com/percona/percona-xtradb-cluster-operator/pkg/apis/pxc/v1" 15 "github.com/percona/percona-xtradb-cluster-operator/pkg/k8s" 16 "github.com/percona/percona-xtradb-cluster-operator/pkg/pxc/app/statefulset" 17 ) 18 19 func (r *ReconcilePerconaXtraDBCluster) reconcilePersistentVolumes(ctx context.Context, cr *api.PerconaXtraDBCluster) error { 20 log := logf.FromContext(ctx) 21 22 pxcSet := statefulset.NewNode(cr) 23 sts := pxcSet.StatefulSet() 24 25 labels := map[string]string{ 26 "app.kubernetes.io/component": "pxc", 27 "app.kubernetes.io/instance": cr.Name, 28 "app.kubernetes.io/managed-by": "percona-xtradb-cluster-operator", 29 "app.kubernetes.io/name": "percona-xtradb-cluster", 30 "app.kubernetes.io/part-of": "percona-xtradb-cluster", 31 } 32 33 pvcList := corev1.PersistentVolumeClaimList{} 34 if err := r.client.List(ctx, &pvcList, client.InNamespace(cr.Namespace), client.MatchingLabels(labels)); err != nil { 35 return errors.Wrap(err, "list persistentvolumeclaims") 36 } 37 38 if cr.PVCResizeInProgress() { 39 resizeInProgress := false 40 for _, pvc := range pvcList.Items { 41 if !strings.HasPrefix(pvc.Name, "datadir-"+sts.Name) { 42 continue 43 } 44 45 for _, condition := range pvc.Status.Conditions { 46 if condition.Status != corev1.ConditionTrue { 47 continue 48 } 49 50 switch condition.Type { 51 case corev1.PersistentVolumeClaimResizing, corev1.PersistentVolumeClaimFileSystemResizePending: 52 resizeInProgress = true 53 log.V(1).Info(condition.Message, "pvc", pvc.Name, "type", condition.Type, "lastTransitionTime", condition.LastTransitionTime) 54 log.Info("PVC resize in progress", "pvc", pvc.Name, "lastTransitionTime", condition.LastTransitionTime) 55 } 56 } 57 } 58 59 if !resizeInProgress { 60 if err := k8s.DeannotateObject(ctx, r.client, cr, api.AnnotationPVCResizeInProgress); err != nil { 61 return errors.Wrap(err, "deannotate pxc") 62 } 63 64 log.Info("PVC resize completed") 65 66 return nil 67 } 68 } 69 70 err := r.client.Get(ctx, client.ObjectKeyFromObject(sts), sts) 71 if err != nil { 72 if k8serrors.IsNotFound(err) { 73 return nil 74 } 75 return errors.Wrapf(err, "get statefulset/%s", sts.Name) 76 } 77 78 if cr.Spec.PXC.VolumeSpec.PersistentVolumeClaim == nil { 79 return nil 80 } 81 82 var volumeTemplate corev1.PersistentVolumeClaim 83 for _, vct := range sts.Spec.VolumeClaimTemplates { 84 if vct.Name == "datadir" { 85 volumeTemplate = vct 86 } 87 } 88 89 requested := cr.Spec.PXC.VolumeSpec.PersistentVolumeClaim.Resources.Requests[corev1.ResourceStorage] 90 actual := volumeTemplate.Spec.Resources.Requests[corev1.ResourceStorage] 91 92 if requested.Cmp(actual) < 0 { 93 return errors.Wrap(err, "requested storage is less than actual") 94 } 95 96 if requested.Cmp(actual) == 0 { 97 return nil 98 } 99 100 err = k8s.AnnotateObject(ctx, r.client, cr, map[string]string{api.AnnotationPVCResizeInProgress: "true"}) 101 if err != nil { 102 return errors.Wrap(err, "annotate pxc") 103 } 104 105 podList := corev1.PodList{} 106 if err := r.client.List(ctx, &podList, client.InNamespace(cr.Namespace), client.MatchingLabels(labels)); err != nil { 107 return errors.Wrap(err, "list pods") 108 } 109 110 podNames := make([]string, 0, len(podList.Items)) 111 for _, pod := range podList.Items { 112 podNames = append(podNames, pod.Name) 113 } 114 115 pvcsToUpdate := make([]string, 0, len(pvcList.Items)) 116 for _, pvc := range pvcList.Items { 117 if !strings.HasPrefix(pvc.Name, "datadir-"+sts.Name) { 118 continue 119 } 120 121 podName := strings.SplitN(pvc.Name, "-", 2)[1] 122 if !slices.Contains(podNames, podName) { 123 continue 124 } 125 126 pvcsToUpdate = append(pvcsToUpdate, pvc.Name) 127 } 128 129 log.Info("Resizing PVCs", "requested", requested, "actual", actual, "pvcList", strings.Join(pvcsToUpdate, ",")) 130 131 log.Info("Deleting statefulset", "name", sts.Name) 132 133 if err := r.client.Delete(ctx, sts, client.PropagationPolicy("Orphan")); err != nil { 134 return errors.Wrapf(err, "delete statefulset/%s", sts.Name) 135 } 136 137 for _, pvc := range pvcList.Items { 138 if !slices.Contains(pvcsToUpdate, pvc.Name) { 139 continue 140 } 141 142 log.Info("Resizing PVC", "name", pvc.Name) 143 pvc.Spec.Resources.Requests[corev1.ResourceStorage] = requested 144 145 if err := r.client.Update(ctx, &pvc); err != nil { 146 return errors.Wrapf(err, "update persistentvolumeclaim/%s", pvc.Name) 147 } 148 } 149 150 return nil 151 }