From e95729b44fdd0147f3df4e273af9fcbf544a4211 Mon Sep 17 00:00:00 2001 From: Leon Date: Sat, 7 Oct 2023 10:24:15 +0800 Subject: [PATCH] feat: support to specify volume mode when creating clusters --- apis/apps/v1alpha1/cluster_types.go | 34 +++++++++---------- apis/apps/v1alpha1/cluster_types_test.go | 21 +++++++++--- apis/apps/v1alpha1/zz_generated.deepcopy.go | 5 +++ .../bases/apps.kubeblocks.io_clusters.yaml | 5 +++ controllers/apps/components/component.go | 4 +-- .../crds/apps.kubeblocks.io_clusters.yaml | 5 +++ internal/controller/factory/builder.go | 21 ++++-------- 7 files changed, 57 insertions(+), 38 deletions(-) diff --git a/apis/apps/v1alpha1/cluster_types.go b/apis/apps/v1alpha1/cluster_types.go index f6ff22c0b8b..b4cb11aebf9 100644 --- a/apis/apps/v1alpha1/cluster_types.go +++ b/apis/apps/v1alpha1/cluster_types.go @@ -439,10 +439,12 @@ type ClusterComponentVolumeClaimTemplate struct { } func (r *ClusterComponentVolumeClaimTemplate) toVolumeClaimTemplate() corev1.PersistentVolumeClaimTemplate { - t := corev1.PersistentVolumeClaimTemplate{} - t.ObjectMeta.Name = r.Name - t.Spec = r.Spec.ToV1PersistentVolumeClaimSpec() - return t + return corev1.PersistentVolumeClaimTemplate{ + ObjectMeta: metav1.ObjectMeta{ + Name: r.Name, + }, + Spec: r.Spec.ToV1PersistentVolumeClaimSpec(), + } } type PersistentVolumeClaimSpec struct { @@ -463,12 +465,10 @@ type PersistentVolumeClaimSpec struct { // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1. // +optional StorageClassName *string `json:"storageClassName,omitempty" protobuf:"bytes,5,opt,name=storageClassName"` - // TODO: - // // preferStorageClassNames added support specifying storageclasses.storage.k8s.io names, in order - // // to adapt multi-cloud deployment, where storageclasses are all distinctly different among clouds. - // // +listType=set - // // +optional - // PreferSCNames []string `json:"preferStorageClassNames,omitempty"` + // volumeMode defines what type of volume is required by the claim. + // Value of Filesystem is implied when not included in claim spec. + // +optional + VolumeMode *corev1.PersistentVolumeMode `json:"volumeMode,omitempty" protobuf:"bytes,6,opt,name=volumeMode,casttype=PersistentVolumeMode"` } // ToV1PersistentVolumeClaimSpec converts to corev1.PersistentVolumeClaimSpec. @@ -476,21 +476,21 @@ func (r *PersistentVolumeClaimSpec) ToV1PersistentVolumeClaimSpec() corev1.Persi return corev1.PersistentVolumeClaimSpec{ AccessModes: r.AccessModes, Resources: r.Resources, - StorageClassName: r.GetStorageClassName(viper.GetString(constant.CfgKeyDefaultStorageClass)), + StorageClassName: r.getStorageClassName(viper.GetString(constant.CfgKeyDefaultStorageClass)), + VolumeMode: r.VolumeMode, } } -// GetStorageClassName returns PersistentVolumeClaimSpec.StorageClassName if a value is assigned; otherwise, +// getStorageClassName returns PersistentVolumeClaimSpec.StorageClassName if a value is assigned; otherwise, // it returns preferSC argument. -func (r *PersistentVolumeClaimSpec) GetStorageClassName(preferSC string) *string { +func (r *PersistentVolumeClaimSpec) getStorageClassName(preferSC string) *string { if r.StorageClassName != nil && *r.StorageClassName != "" { return r.StorageClassName } - - if preferSC == "" { - return nil + if preferSC != "" { + return &preferSC } - return &preferSC + return nil } type Affinity struct { diff --git a/apis/apps/v1alpha1/cluster_types_test.go b/apis/apps/v1alpha1/cluster_types_test.go index b2f02073a2c..9e5e7e0e206 100644 --- a/apis/apps/v1alpha1/cluster_types_test.go +++ b/apis/apps/v1alpha1/cluster_types_test.go @@ -24,6 +24,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/yaml" @@ -33,7 +34,6 @@ import ( ) var _ = Describe("", func() { - It("test GetMinAvailable", func() { prefer := intstr.IntOrString{} clusterCompSpec := &ClusterComponentSpec{} @@ -58,7 +58,8 @@ var _ = Describe("", func() { pvcSpec := r.ToV1PersistentVolumeClaimSpec() Expect(pvcSpec.AccessModes).Should(BeEquivalentTo(r.AccessModes)) Expect(pvcSpec.Resources).Should(BeEquivalentTo(r.Resources)) - Expect(pvcSpec.StorageClassName).Should(BeEquivalentTo(r.GetStorageClassName(viper.GetString(constant.CfgKeyDefaultStorageClass)))) + Expect(pvcSpec.StorageClassName).Should(BeEquivalentTo(r.getStorageClassName(viper.GetString(constant.CfgKeyDefaultStorageClass)))) + Expect(pvcSpec.VolumeMode).Should(BeEquivalentTo(r.VolumeMode)) }) It("test ToV1PersistentVolumeClaimSpec with default storage class", func() { @@ -70,14 +71,24 @@ var _ = Describe("", func() { viper.Set(constant.CfgKeyDefaultStorageClass, "") }) - It("test GetStorageClassName", func() { + It("test ToV1PersistentVolumeClaimSpec with volume mode", func() { + for _, mode := range []corev1.PersistentVolumeMode{corev1.PersistentVolumeBlock, corev1.PersistentVolumeFilesystem} { + r := PersistentVolumeClaimSpec{ + VolumeMode: &mode, + } + pvcSpec := r.ToV1PersistentVolumeClaimSpec() + Expect(pvcSpec.VolumeMode).Should(BeEquivalentTo(r.VolumeMode)) + } + }) + + It("test getStorageClassName", func() { preferSC := "prefer-sc" r := PersistentVolumeClaimSpec{} r.StorageClassName = nil - Expect(r.GetStorageClassName(preferSC)).Should(BeEquivalentTo(&preferSC)) + Expect(r.getStorageClassName(preferSC)).Should(BeEquivalentTo(&preferSC)) scName := "test-sc" r.StorageClassName = &scName - Expect(r.GetStorageClassName(preferSC)).Should(BeEquivalentTo(&scName)) + Expect(r.getStorageClassName(preferSC)).Should(BeEquivalentTo(&scName)) }) It("test IsDeleting", func() { diff --git a/apis/apps/v1alpha1/zz_generated.deepcopy.go b/apis/apps/v1alpha1/zz_generated.deepcopy.go index fa5956b72f4..96610f5edcf 100644 --- a/apis/apps/v1alpha1/zz_generated.deepcopy.go +++ b/apis/apps/v1alpha1/zz_generated.deepcopy.go @@ -2924,6 +2924,11 @@ func (in *PersistentVolumeClaimSpec) DeepCopyInto(out *PersistentVolumeClaimSpec *out = new(string) **out = **in } + if in.VolumeMode != nil { + in, out := &in.VolumeMode, &out.VolumeMode + *out = new(v1.PersistentVolumeMode) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaimSpec. diff --git a/config/crd/bases/apps.kubeblocks.io_clusters.yaml b/config/crd/bases/apps.kubeblocks.io_clusters.yaml index d741c62fef4..af3f002d724 100644 --- a/config/crd/bases/apps.kubeblocks.io_clusters.yaml +++ b/config/crd/bases/apps.kubeblocks.io_clusters.yaml @@ -623,6 +623,11 @@ spec: description: 'storageClassName is the name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1.' type: string + volumeMode: + description: volumeMode defines what type of volume + is required by the claim. Value of Filesystem is + implied when not included in claim spec. + type: string type: object required: - name diff --git a/controllers/apps/components/component.go b/controllers/apps/components/component.go index 1469cab519b..03c8eebcba8 100644 --- a/controllers/apps/components/component.go +++ b/controllers/apps/components/component.go @@ -746,9 +746,9 @@ func (c *rsmComponent) restart(reqCtx intctrlutil.RequestCtx, cli client.Client) func (c *rsmComponent) expandVolume(reqCtx intctrlutil.RequestCtx, cli client.Client) error { for _, vct := range c.runningWorkload.Spec.VolumeClaimTemplates { var proto *corev1.PersistentVolumeClaimTemplate - for _, v := range c.component.VolumeClaimTemplates { + for i, v := range c.component.VolumeClaimTemplates { if v.Name == vct.Name { - proto = &v + proto = &c.component.VolumeClaimTemplates[i] break } } diff --git a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml index d741c62fef4..af3f002d724 100644 --- a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml +++ b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml @@ -623,6 +623,11 @@ spec: description: 'storageClassName is the name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1.' type: string + volumeMode: + description: volumeMode defines what type of volume + is required by the claim. Value of Filesystem is + implied when not included in claim spec. + type: string type: object required: - name diff --git a/internal/controller/factory/builder.go b/internal/controller/factory/builder.go index 72469c2a08f..f343f729735 100644 --- a/internal/controller/factory/builder.go +++ b/internal/controller/factory/builder.go @@ -207,15 +207,15 @@ func BuildCommonLabels(cluster *appsv1alpha1.Cluster, } } -func BuildSts(reqCtx intctrlutil.RequestCtx, cluster *appsv1alpha1.Cluster, - component *component.SynthesizedComponent, envConfigName string) (*appsv1.StatefulSet, error) { - vctToPVC := func(vct corev1.PersistentVolumeClaimTemplate) corev1.PersistentVolumeClaim { - return corev1.PersistentVolumeClaim{ - ObjectMeta: vct.ObjectMeta, - Spec: vct.Spec, - } +func vctToPVC(vct corev1.PersistentVolumeClaimTemplate) corev1.PersistentVolumeClaim { + return corev1.PersistentVolumeClaim{ + ObjectMeta: vct.ObjectMeta, + Spec: vct.Spec, } +} +func BuildSts(reqCtx intctrlutil.RequestCtx, cluster *appsv1alpha1.Cluster, + component *component.SynthesizedComponent, envConfigName string) (*appsv1.StatefulSet, error) { commonLabels := BuildCommonLabels(cluster, component) podBuilder := builder.NewPodBuilder("", ""). AddLabelsInMap(commonLabels). @@ -274,13 +274,6 @@ func buildWellKnownLabels(clusterDefName, clusterName, componentName string) map func BuildRSM(reqCtx intctrlutil.RequestCtx, cluster *appsv1alpha1.Cluster, component *component.SynthesizedComponent, envConfigName string) (*workloads.ReplicatedStateMachine, error) { - vctToPVC := func(vct corev1.PersistentVolumeClaimTemplate) corev1.PersistentVolumeClaim { - return corev1.PersistentVolumeClaim{ - ObjectMeta: vct.ObjectMeta, - Spec: vct.Spec, - } - } - commonLabels := buildWellKnownLabels(component.ClusterDefName, cluster.Name, component.Name) addCommonLabels := func(service *corev1.Service) { if service == nil {