From bd26522307969d8c156bc79daa576ce290347642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Mart=C3=ADnez=20del=20Horno?= Date: Wed, 3 Dec 2025 13:03:14 +0100 Subject: [PATCH] feat: add emptyDir configuration for persistence volume --- api/v1beta1/rabbitmqcluster_types.go | 18 +++++++++++++ api/v1beta1/zz_generated.deepcopy.go | 25 +++++++++++++++++++ .../bases/rabbitmq.com_rabbitmqclusters.yaml | 21 ++++++++++++++++ docs/api/rabbitmq.com.ref.asciidoc | 24 ++++++++++++++++++ internal/resource/statefulset.go | 12 ++++++--- internal/resource/statefulset_test.go | 24 ++++++++++++++++++ 6 files changed, 121 insertions(+), 3 deletions(-) diff --git a/api/v1beta1/rabbitmqcluster_types.go b/api/v1beta1/rabbitmqcluster_types.go index 5b0173e7c..2f4b171bb 100644 --- a/api/v1beta1/rabbitmqcluster_types.go +++ b/api/v1beta1/rabbitmqcluster_types.go @@ -412,6 +412,24 @@ type RabbitmqClusterPersistenceSpec struct { // See https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity for more info on the format of this field. // +kubebuilder:default:="10Gi" Storage *k8sresource.Quantity `json:"storage,omitempty"` + // EmptyDir configuration to be used when Storage is set to 0Gi. + // +optional + EmptyDir *RabbitmqClusterEmptyDirSpec `json:"emptyDir,omitempty"` +} + +// RabbitmqClusterEmptyDirSpec contains configuration for EmptyDir volumes. +type RabbitmqClusterEmptyDirSpec struct { + // Medium represents the storage medium for the EmptyDir volume. + // The default is "" which means to use the node's default medium. + // Must be an empty string (default) or Memory. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + // +optional + Medium corev1.StorageMedium `json:"medium,omitempty"` + // SizeLimit sets the size limit for EmptyDir volumes. + // The format of this field matches that defined by kubernetes/apimachinery. + // See https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity for more info on the format of this field. + // +optional + SizeLimit *k8sresource.Quantity `json:"sizeLimit,omitempty"` } // Settable attributes for the Service resource. diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index a855f7974..9f8b1c417 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -195,6 +195,26 @@ func (in *RabbitmqClusterDefaultUser) DeepCopy() *RabbitmqClusterDefaultUser { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RabbitmqClusterEmptyDirSpec) DeepCopyInto(out *RabbitmqClusterEmptyDirSpec) { + *out = *in + if in.SizeLimit != nil { + in, out := &in.SizeLimit, &out.SizeLimit + x := (*in).DeepCopy() + *out = &x + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RabbitmqClusterEmptyDirSpec. +func (in *RabbitmqClusterEmptyDirSpec) DeepCopy() *RabbitmqClusterEmptyDirSpec { + if in == nil { + return nil + } + out := new(RabbitmqClusterEmptyDirSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RabbitmqClusterList) DeepCopyInto(out *RabbitmqClusterList) { *out = *in @@ -265,6 +285,11 @@ func (in *RabbitmqClusterPersistenceSpec) DeepCopyInto(out *RabbitmqClusterPersi x := (*in).DeepCopy() *out = &x } + if in.EmptyDir != nil { + in, out := &in.EmptyDir, &out.EmptyDir + *out = new(RabbitmqClusterEmptyDirSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RabbitmqClusterPersistenceSpec. diff --git a/config/crd/bases/rabbitmq.com_rabbitmqclusters.yaml b/config/crd/bases/rabbitmq.com_rabbitmqclusters.yaml index b24330544..d09a0874c 100644 --- a/config/crd/bases/rabbitmq.com_rabbitmqclusters.yaml +++ b/config/crd/bases/rabbitmq.com_rabbitmqclusters.yaml @@ -5069,6 +5069,27 @@ spec: storage: 10Gi description: The desired persistent storage configuration for each Pod in the cluster. properties: + emptyDir: + description: EmptyDir configuration to be used when Storage is set to 0Gi. + properties: + medium: + description: |- + Medium represents the storage medium for the EmptyDir volume. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: |- + SizeLimit sets the size limit for EmptyDir volumes. + The format of this field matches that defined by kubernetes/apimachinery. + See https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity for more info on the format of this field. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object storage: anyOf: - type: integer diff --git a/docs/api/rabbitmq.com.ref.asciidoc b/docs/api/rabbitmq.com.ref.asciidoc index 690b463f0..08bcc5daa 100644 --- a/docs/api/rabbitmq.com.ref.asciidoc +++ b/docs/api/rabbitmq.com.ref.asciidoc @@ -227,6 +227,29 @@ user. |=== +[id="{anchor_prefix}-github-com-rabbitmq-cluster-operator-v2-api-v1beta1-rabbitmqclusteremptydirspec"] +==== RabbitmqClusterEmptyDirSpec + +RabbitmqClusterEmptyDirSpec contains configuration for EmptyDir volumes. + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-rabbitmq-cluster-operator-v2-api-v1beta1-rabbitmqclusterpersistencespec[$$RabbitmqClusterPersistenceSpec$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`medium`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#storagemedium-v1-core[$$StorageMedium$$]__ | Medium represents the storage medium for the EmptyDir volume. +The default is "" which means to use the node's default medium. +Must be an empty string (default) or Memory. +More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir +| *`sizeLimit`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#quantity-resource-api[$$Quantity$$]__ | SizeLimit sets the size limit for EmptyDir volumes. +The format of this field matches that defined by kubernetes/apimachinery. +See https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity for more info on the format of this field. +|=== + + [id="{anchor_prefix}-github-com-rabbitmq-cluster-operator-v2-api-v1beta1-rabbitmqclusterlist"] ==== RabbitmqClusterList @@ -289,6 +312,7 @@ The settings for the persistent storage desired for each Pod in the RabbitmqClus | *`storage`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#quantity-resource-api[$$Quantity$$]__ | The requested size of the persistent volume attached to each Pod in the RabbitmqCluster. The format of this field matches that defined by kubernetes/apimachinery. See https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity for more info on the format of this field. +| *`emptyDir`* __xref:{anchor_prefix}-github-com-rabbitmq-cluster-operator-v2-api-v1beta1-rabbitmqclusteremptydirspec[$$RabbitmqClusterEmptyDirSpec$$]__ | EmptyDir configuration to be used when Storage is set to 0Gi. |=== diff --git a/internal/resource/statefulset.go b/internal/resource/statefulset.go index 27d62eb1b..776831970 100644 --- a/internal/resource/statefulset.go +++ b/internal/resource/statefulset.go @@ -20,6 +20,8 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" + "maps" + rabbitmqv1beta1 "github.com/rabbitmq/cluster-operator/v2/api/v1beta1" "github.com/rabbitmq/cluster-operator/v2/internal/metadata" appsv1 "k8s.io/api/apps/v1" @@ -29,7 +31,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/utils/ptr" - "maps" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) @@ -456,12 +457,17 @@ func (builder *StatefulSetBuilder) podTemplateSpec(previousPodAnnotations map[st zero := k8sresource.MustParse("0Gi") if builder.Instance.Spec.Persistence.Storage.Cmp(zero) == 0 { - volumes = append(volumes, corev1.Volume{ + volume := corev1.Volume{ Name: "persistence", VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, - }) + } + if builder.Instance.Spec.Persistence.EmptyDir != nil { + volume.VolumeSource.EmptyDir.SizeLimit = builder.Instance.Spec.Persistence.EmptyDir.SizeLimit + volume.VolumeSource.EmptyDir.Medium = builder.Instance.Spec.Persistence.EmptyDir.Medium + } + volumes = append(volumes, volume) } rabbitmqContainerVolumeMounts := []corev1.VolumeMount{ diff --git a/internal/resource/statefulset_test.go b/internal/resource/statefulset_test.go index bb1b9da30..4e4e50926 100644 --- a/internal/resource/statefulset_test.go +++ b/internal/resource/statefulset_test.go @@ -1334,6 +1334,30 @@ default_pass = {{ .Data.data.password }} Expect(statefulSet.Spec.Template.Spec.Volumes).To(ContainElement(expectedVolume)) }) + + It("defines an emptyDir volume with sizeLimit and medium when storage == 0 and emptyDir config received", func() { + zero, _ := k8sresource.ParseQuantity("0") + + stsBuilder := builder.StatefulSet() + stsBuilder.Instance.Spec.Persistence.Storage = &zero + stsBuilder.Instance.Spec.Persistence.EmptyDir = &rabbitmqv1beta1.RabbitmqClusterEmptyDirSpec{ + SizeLimit: ptr.To(k8sresource.MustParse("500Mi")), + Medium: corev1.StorageMediumMemory, + } + Expect(stsBuilder.Update(statefulSet)).To(Succeed()) + + expectedVolume := corev1.Volume{ + Name: "persistence", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + SizeLimit: ptr.To(k8sresource.MustParse("500Mi")), + Medium: corev1.StorageMediumMemory, + }, + }, + } + + Expect(statefulSet.Spec.Template.Spec.Volumes).To(ContainElement(expectedVolume)) + }) }) It("uses the correct service account", func() {