diff --git a/pkg/controller/main-controller.go b/pkg/controller/main-controller.go index 9e6ccab8aa0..b7f0d52a4c2 100644 --- a/pkg/controller/main-controller.go +++ b/pkg/controller/main-controller.go @@ -1324,6 +1324,12 @@ func (c *Controller) syncHandler(key string) (Result, error) { } } + // Handle PVC expansion + err = ExpandPVCs(ctx, c.kubeClientSet, tenant, namespace) + if err != nil { + return WrapResult(Result{}, err) + } + if tenant.HasPrometheusOperatorEnabled() { err := c.checkAndCreatePrometheusAddlConfig(ctx, tenant, string(tenantConfiguration["accesskey"]), string(tenantConfiguration["secretkey"])) if err != nil { diff --git a/pkg/controller/pvc.go b/pkg/controller/pvc.go new file mode 100644 index 00000000000..34e3c417580 --- /dev/null +++ b/pkg/controller/pvc.go @@ -0,0 +1,44 @@ +package controller + +import ( + "context" + "fmt" + + miniov2 "github.com/minio/operator/pkg/apis/minio.min.io/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" +) + +// ExpandPVCs expands the PVCs for a given tenant +func ExpandPVCs(ctx context.Context, kubeClientSet kubernetes.Interface, tenant *miniov2.Tenant, namespace string) error { + uOpts := metav1.UpdateOptions{} + + for _, pool := range tenant.Spec.Pools { + opts := metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s,%s=%s", miniov2.TenantLabel, tenant.Name, miniov2.PoolLabel, pool.Name), + } + pvcList, err := kubeClientSet.CoreV1().PersistentVolumeClaims(namespace).List(ctx, opts) + if err != nil { + return err + } + + for _, pvc := range pvcList.Items { + if pool.VolumeClaimTemplate != nil { + requestedStorage := pool.VolumeClaimTemplate.Spec.Resources.Requests[corev1.ResourceStorage] + currentStorage := pvc.Spec.Resources.Requests[corev1.ResourceStorage] + if requestedStorage.Cmp(currentStorage) > 0 { + pvc.Spec.Resources.Requests[corev1.ResourceStorage] = requestedStorage + _, err = kubeClientSet.CoreV1().PersistentVolumeClaims(namespace).Update(ctx, &pvc, uOpts) + if err != nil { + return err + } + klog.Infof("Expanded PVC %s from %s to %s", pvc.Name, currentStorage.String(), requestedStorage.String()) + } + } + } + } + + return nil +} diff --git a/pkg/controller/pvc_test.go b/pkg/controller/pvc_test.go new file mode 100644 index 00000000000..74214c69ca0 --- /dev/null +++ b/pkg/controller/pvc_test.go @@ -0,0 +1,72 @@ +package controller + +import ( + "context" + "testing" + + miniov2 "github.com/minio/operator/pkg/apis/minio.min.io/v2" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" +) + +func TestExpandPVCs(t *testing.T) { + ctx := context.Background() + + tenant := &miniov2.Tenant{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-tenant", + }, + Spec: miniov2.TenantSpec{ + Pools: []miniov2.Pool{ + { + Name: "pool1", + VolumeClaimTemplate: &corev1.PersistentVolumeClaim{ + Spec: corev1.PersistentVolumeClaimSpec{ + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("2Gi"), + }, + }, + }, + }, + }, + }, + }, + } + + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pvc", + Namespace: "test-namespace", + Labels: map[string]string{ + miniov2.TenantLabel: tenant.Name, + miniov2.PoolLabel: "pool1", + }, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), + }, + }, + }, + } + + kubeClient := fake.NewSimpleClientset(pvc) + + err := ExpandPVCs(ctx, kubeClient, tenant, "test-namespace") + if err != nil { + t.Fatalf("ExpandPVCs failed: %v", err) + } + + updatedPVC, err := kubeClient.CoreV1().PersistentVolumeClaims("test-namespace").Get(ctx, "test-pvc", metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get PVC: %v", err) + } + + if updatedPVC.Spec.Resources.Requests[corev1.ResourceStorage] != resource.MustParse("2Gi") { + t.Errorf("Expected PVC storage to be 2Gi, but got %v", updatedPVC.Spec.Resources.Requests[corev1.ResourceStorage]) + } +}