From c714b3a080eac9dd5453c781a214e93e58a6f567 Mon Sep 17 00:00:00 2001 From: Andrew Obuchowicz Date: Tue, 26 Apr 2022 09:29:19 -0400 Subject: [PATCH 1/3] feat: Configurable PVC size (fix #740) Both common and per-workspace storage class PVC sizes can be configured through CRD's Signed-off-by: Andrew Obuchowicz --- .../devworkspaceoperatorconfig_types.go | 16 +++++++++++++- pkg/config/defaults.go | 15 +++++++++---- pkg/config/sync.go | 21 +++++++++++++++++++ pkg/provision/storage/commonStorage_test.go | 3 ++- pkg/provision/storage/perWorkspaceStorage.go | 11 ++-------- pkg/provision/storage/shared.go | 15 +++++++------ 6 files changed, 58 insertions(+), 23 deletions(-) diff --git a/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go b/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go index ac380288e..6b7b936e0 100644 --- a/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go +++ b/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go @@ -17,6 +17,7 @@ package v1alpha1 import ( corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -67,6 +68,16 @@ type Proxy struct { NoProxy string `json:"noProxy,omitempty"` } +type StorageSizes struct { + // The default Persistent Volume Claim size for the "common" storage class. + // Note that the "async" storage class also uses the PVC size set for the "common" storage class. + // If not specified, the "common" and "async" Persistent Volume Claim sizes are set to 10Gi + Common *resource.Quantity `json:"common,omitempty"` + // The default Persistent Volume Claim size for the "per-workspace" storage class. + // If not specified, the "per-workspace" Persistent Volume Claim size is set to 5Gi + PerWorkspace *resource.Quantity `json:"perWorkspace,omitempty"` +} + type WorkspaceConfig struct { // ImagePullPolicy defines the imagePullPolicy used for containers in a DevWorkspace // For additional information, see Kubernetes documentation for imagePullPolicy. If @@ -83,9 +94,12 @@ type WorkspaceConfig struct { // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ // +kubebuilder:validation:MaxLength=63 PVCName string `json:"pvcName,omitempty"` - // StorageClassName defines and optional storageClass to use for persistent + // StorageClassName defines an optional storageClass to use for persistent // volume claims created to support DevWorkspaces StorageClassName *string `json:"storageClassName,omitempty"` + // DefaultStorageSize defines an optional struct with fields to specify the sizes of Persistent Volume Claims for storage + // classes used by DevWorkspaces. + DefaultStorageSize *StorageSizes `json:"defaultStorageSize,omitempty"` // IdleTimeout determines how long a workspace should sit idle before being // automatically scaled down. Proper functionality of this configuration property // requires support in the workspace being started. If not specified, the default diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index c7c976380..7fc374088 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -18,6 +18,7 @@ package config import ( "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" ) // defaultConfig represents the default configuration for the DevWorkspace Operator. @@ -29,6 +30,10 @@ var defaultConfig = &v1alpha1.OperatorConfiguration{ Workspace: &v1alpha1.WorkspaceConfig{ ImagePullPolicy: "Always", PVCName: "claim-devworkspace", + DefaultStorageSize: &v1alpha1.StorageSizes{ + Common: &commonStorageSize, + PerWorkspace: &perWorkspaceStorageSize, + }, IdleTimeout: "15m", ProgressTimeout: "5m", CleanupOnStop: &boolFalse, @@ -43,8 +48,10 @@ var defaultConfig = &v1alpha1.OperatorConfiguration{ // Necessary variables for setting pointer values var ( - boolTrue = true - boolFalse = false - int64UID = int64(1234) - int64GID = int64(0) + boolTrue = true + boolFalse = false + int64UID = int64(1234) + int64GID = int64(0) + commonStorageSize = resource.MustParse("10Gi") + perWorkspaceStorageSize = resource.MustParse("5Gi") ) diff --git a/pkg/config/sync.go b/pkg/config/sync.go index 072ec11bb..ca9c63c38 100644 --- a/pkg/config/sync.go +++ b/pkg/config/sync.go @@ -242,6 +242,19 @@ func mergeConfig(from, to *controller.OperatorConfiguration) { if from.Workspace.PodSecurityContext != nil { to.Workspace.PodSecurityContext = from.Workspace.PodSecurityContext } + if from.Workspace.DefaultStorageSize != nil { + if to.Workspace.DefaultStorageSize == nil { + to.Workspace.DefaultStorageSize = &controller.StorageSizes{} + } + if from.Workspace.DefaultStorageSize.Common != nil { + commonSizeCopy := from.Workspace.DefaultStorageSize.Common.DeepCopy() + to.Workspace.DefaultStorageSize.Common = &commonSizeCopy + } + if from.Workspace.DefaultStorageSize.PerWorkspace != nil { + perWorkspaceSizeCopy := from.Workspace.DefaultStorageSize.PerWorkspace.DeepCopy() + to.Workspace.DefaultStorageSize.PerWorkspace = &perWorkspaceSizeCopy + } + } } } @@ -276,6 +289,14 @@ func logCurrentConfig() { config = append(config, fmt.Sprintf("workspace.ignoredUnrecoverableEvents=%s", strings.Join(Workspace.IgnoredUnrecoverableEvents, ";"))) } + if Workspace.DefaultStorageSize != nil { + if Workspace.DefaultStorageSize.Common != nil { + config = append(config, fmt.Sprintf("workspace.defaultStorageSize.common=%s", Workspace.DefaultStorageSize.Common.String())) + } + if Workspace.DefaultStorageSize.PerWorkspace != nil { + config = append(config, fmt.Sprintf("workspace.defaultStorageSize.perWorkspace=%s", Workspace.DefaultStorageSize.PerWorkspace.String())) + } + } } if internalConfig.EnableExperimentalFeatures != nil && *internalConfig.EnableExperimentalFeatures { config = append(config, "enableExperimentalFeatures=true") diff --git a/pkg/provision/storage/commonStorage_test.go b/pkg/provision/storage/commonStorage_test.go index e8b5b8cbe..9007dfdaa 100644 --- a/pkg/provision/storage/commonStorage_test.go +++ b/pkg/provision/storage/commonStorage_test.go @@ -28,6 +28,7 @@ import ( "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" @@ -106,7 +107,7 @@ func TestRewriteContainerVolumeMountsForCommonStorageClass(t *testing.T) { tests := loadAllTestCasesOrPanic(t, "testdata/common-storage") setupControllerCfg() commonStorage := CommonStorageProvisioner{} - commonPVC, err := getPVCSpec("claim-devworkspace", "test-namespace", "10Gi") + commonPVC, err := getPVCSpec("claim-devworkspace", "test-namespace", resource.MustParse("10Gi")) if err != nil { t.Fatalf("Failure during setup: %s", err) } diff --git a/pkg/provision/storage/perWorkspaceStorage.go b/pkg/provision/storage/perWorkspaceStorage.go index 7069712fb..71000f786 100644 --- a/pkg/provision/storage/perWorkspaceStorage.go +++ b/pkg/provision/storage/perWorkspaceStorage.go @@ -22,9 +22,9 @@ import ( dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" "github.com/devfile/devworkspace-operator/pkg/common" + "github.com/devfile/devworkspace-operator/pkg/config" "github.com/devfile/devworkspace-operator/pkg/constants" devfileConstants "github.com/devfile/devworkspace-operator/pkg/library/constants" - nsconfig "github.com/devfile/devworkspace-operator/pkg/provision/config" "github.com/devfile/devworkspace-operator/pkg/provision/sync" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -148,16 +148,9 @@ func (p *PerWorkspaceStorageProvisioner) rewriteContainerVolumeMounts(workspaceI } func syncPerWorkspacePVC(workspace *dw.DevWorkspace, clusterAPI sync.ClusterAPI) (*corev1.PersistentVolumeClaim, error) { - namespace := workspace.Namespace - - namespacedConfig, err := nsconfig.ReadNamespacedConfig(namespace, clusterAPI) - if err != nil { - return nil, fmt.Errorf("failed to read namespace-specific configuration: %w", err) - } - // TODO: Determine the storage size that is needed by iterating through workspace volumes, // adding the sizes specified and figuring out overrides/defaults - pvcSize := constants.PVCStorageSize + pvcSize := *config.Workspace.DefaultStorageSize.PerWorkspace if namespacedConfig != nil && namespacedConfig.PerWorkspacePVCSize != "" { pvcSize = namespacedConfig.PerWorkspacePVCSize } diff --git a/pkg/provision/storage/shared.go b/pkg/provision/storage/shared.go index fa8e92255..85cf2afd4 100644 --- a/pkg/provision/storage/shared.go +++ b/pkg/provision/storage/shared.go @@ -35,11 +35,7 @@ import ( nsconfig "github.com/devfile/devworkspace-operator/pkg/provision/config" ) -func getPVCSpec(name, namespace string, size string) (*corev1.PersistentVolumeClaim, error) { - pvcStorageQuantity, err := resource.ParseQuantity(size) - if err != nil { - return nil, err - } +func getPVCSpec(name, namespace string, size resource.Quantity) (*corev1.PersistentVolumeClaim, error) { return &corev1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ @@ -52,7 +48,7 @@ func getPVCSpec(name, namespace string, size string) (*corev1.PersistentVolumeCl }, Resources: corev1.ResourceRequirements{ Requests: corev1.ResourceList{ - "storage": pvcStorageQuantity, + "storage": size, }, }, StorageClassName: config.Workspace.StorageClassName, @@ -93,9 +89,12 @@ func syncCommonPVC(namespace string, clusterAPI sync.ClusterAPI) (*corev1.Persis if err != nil { return nil, fmt.Errorf("failed to read namespace-specific configuration: %w", err) } - pvcSize := constants.PVCStorageSize + pvcSize := *config.Workspace.DefaultStorageSize.Common if namespacedConfig != nil && namespacedConfig.CommonPVCSize != "" { - pvcSize = namespacedConfig.CommonPVCSize + pvcSize, err = resource.ParseQuantity(namespacedConfig.CommonPVCSize) + if err != nil { + return nil, err + } } pvc, err := getPVCSpec(config.Workspace.PVCName, namespace, pvcSize) From 8c81e42820f27bc02332ddd5a5bac56399c5d54a Mon Sep 17 00:00:00 2001 From: Andrew Obuchowicz Date: Tue, 26 Apr 2022 09:32:37 -0400 Subject: [PATCH 2/3] Generate config. option for configurable PVC size Part of #740 Signed-off-by: Andrew Obuchowicz --- .../v1alpha1/zz_generated.deepcopy.go | 30 +++++++++++++++++++ ...evfile.io_devworkspaceoperatorconfigs.yaml | 20 ++++++++++++- deploy/deployment/kubernetes/combined.yaml | 28 ++++++++++++++++- ...r.devfile.io.CustomResourceDefinition.yaml | 28 ++++++++++++++++- deploy/deployment/openshift/combined.yaml | 28 ++++++++++++++++- ...r.devfile.io.CustomResourceDefinition.yaml | 28 ++++++++++++++++- ...evfile.io_devworkspaceoperatorconfigs.yaml | 28 ++++++++++++++++- 7 files changed, 184 insertions(+), 6 deletions(-) diff --git a/apis/controller/v1alpha1/zz_generated.deepcopy.go b/apis/controller/v1alpha1/zz_generated.deepcopy.go index 648e81080..b6ea2c79d 100644 --- a/apis/controller/v1alpha1/zz_generated.deepcopy.go +++ b/apis/controller/v1alpha1/zz_generated.deepcopy.go @@ -477,6 +477,31 @@ func (in *RoutingConfig) DeepCopy() *RoutingConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StorageSizes) DeepCopyInto(out *StorageSizes) { + *out = *in + if in.Common != nil { + in, out := &in.Common, &out.Common + x := (*in).DeepCopy() + *out = &x + } + if in.PerWorkspace != nil { + in, out := &in.PerWorkspace, &out.PerWorkspace + x := (*in).DeepCopy() + *out = &x + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageSizes. +func (in *StorageSizes) DeepCopy() *StorageSizes { + if in == nil { + return nil + } + out := new(StorageSizes) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkspaceConfig) DeepCopyInto(out *WorkspaceConfig) { *out = *in @@ -485,6 +510,11 @@ func (in *WorkspaceConfig) DeepCopyInto(out *WorkspaceConfig) { *out = new(string) **out = **in } + if in.DefaultStorageSize != nil { + in, out := &in.DefaultStorageSize, &out.DefaultStorageSize + *out = new(StorageSizes) + (*in).DeepCopyInto(*out) + } if in.IgnoredUnrecoverableEvents != nil { in, out := &in.IgnoredUnrecoverableEvents, &out.IgnoredUnrecoverableEvents *out = make([]string, len(*in)) diff --git a/deploy/bundle/manifests/controller.devfile.io_devworkspaceoperatorconfigs.yaml b/deploy/bundle/manifests/controller.devfile.io_devworkspaceoperatorconfigs.yaml index 49432e524..ec0bac0a6 100644 --- a/deploy/bundle/manifests/controller.devfile.io_devworkspaceoperatorconfigs.yaml +++ b/deploy/bundle/manifests/controller.devfile.io_devworkspaceoperatorconfigs.yaml @@ -62,6 +62,24 @@ spec: cleanupOnStop: description: CleanupOnStop governs how the Operator handles stopped DevWorkspaces. If set to true, additional resources associated with a DevWorkspace (e.g. services, deployments, configmaps, etc.) will be removed from the cluster when a DevWorkspace has .spec.started = false. If set to false, resources will be scaled down (e.g. deployments but the objects will be left on the cluster). The default value is false. type: boolean + defaultStorageSize: + description: DefaultStorageSize defines an optional struct with fields to specify the sizes of Persistent Volume Claims for storage classes used by DevWorkspaces. + properties: + common: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for the "common" storage class. Note that the "async" storage class also uses the PVC size set for the "common" storage class. If not specified, the "common" and "async" Persistent Volume Claim sizes are set to 10Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perWorkspace: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for the "per-workspace" storage class. If not specified, the "per-workspace" Persistent Volume Claim size is set to 5Gi + 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 idleTimeout: description: IdleTimeout determines how long a workspace should sit idle before being automatically scaled down. Proper functionality of this configuration property requires support in the workspace being started. If not specified, the default value of "15m" is used. type: string @@ -171,7 +189,7 @@ spec: pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string storageClassName: - description: StorageClassName defines and optional storageClass to use for persistent volume claims created to support DevWorkspaces + description: StorageClassName defines an optional storageClass to use for persistent volume claims created to support DevWorkspaces type: string type: object type: object diff --git a/deploy/deployment/kubernetes/combined.yaml b/deploy/deployment/kubernetes/combined.yaml index ac3cca4a1..5d96e4d41 100644 --- a/deploy/deployment/kubernetes/combined.yaml +++ b/deploy/deployment/kubernetes/combined.yaml @@ -97,6 +97,32 @@ spec: down (e.g. deployments but the objects will be left on the cluster). The default value is false. type: boolean + defaultStorageSize: + description: DefaultStorageSize defines an optional struct with + fields to specify the sizes of Persistent Volume Claims for + storage classes used by DevWorkspaces. + properties: + common: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "common" storage class. Note that the "async" storage + class also uses the PVC size set for the "common" storage + class. If not specified, the "common" and "async" Persistent + Volume Claim sizes are set to 10Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perWorkspace: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "per-workspace" storage class. If not specified, the + "per-workspace" Persistent Volume Claim size is set to 5Gi + 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 idleTimeout: description: IdleTimeout determines how long a workspace should sit idle before being automatically scaled down. Proper functionality @@ -296,7 +322,7 @@ spec: pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string storageClassName: - description: StorageClassName defines and optional storageClass + description: StorageClassName defines an optional storageClass to use for persistent volume claims created to support DevWorkspaces type: string type: object diff --git a/deploy/deployment/kubernetes/objects/devworkspaceoperatorconfigs.controller.devfile.io.CustomResourceDefinition.yaml b/deploy/deployment/kubernetes/objects/devworkspaceoperatorconfigs.controller.devfile.io.CustomResourceDefinition.yaml index c28cc7f31..589e2a665 100644 --- a/deploy/deployment/kubernetes/objects/devworkspaceoperatorconfigs.controller.devfile.io.CustomResourceDefinition.yaml +++ b/deploy/deployment/kubernetes/objects/devworkspaceoperatorconfigs.controller.devfile.io.CustomResourceDefinition.yaml @@ -97,6 +97,32 @@ spec: down (e.g. deployments but the objects will be left on the cluster). The default value is false. type: boolean + defaultStorageSize: + description: DefaultStorageSize defines an optional struct with + fields to specify the sizes of Persistent Volume Claims for + storage classes used by DevWorkspaces. + properties: + common: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "common" storage class. Note that the "async" storage + class also uses the PVC size set for the "common" storage + class. If not specified, the "common" and "async" Persistent + Volume Claim sizes are set to 10Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perWorkspace: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "per-workspace" storage class. If not specified, the + "per-workspace" Persistent Volume Claim size is set to 5Gi + 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 idleTimeout: description: IdleTimeout determines how long a workspace should sit idle before being automatically scaled down. Proper functionality @@ -296,7 +322,7 @@ spec: pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string storageClassName: - description: StorageClassName defines and optional storageClass + description: StorageClassName defines an optional storageClass to use for persistent volume claims created to support DevWorkspaces type: string type: object diff --git a/deploy/deployment/openshift/combined.yaml b/deploy/deployment/openshift/combined.yaml index 5e2033bfb..c98494084 100644 --- a/deploy/deployment/openshift/combined.yaml +++ b/deploy/deployment/openshift/combined.yaml @@ -97,6 +97,32 @@ spec: down (e.g. deployments but the objects will be left on the cluster). The default value is false. type: boolean + defaultStorageSize: + description: DefaultStorageSize defines an optional struct with + fields to specify the sizes of Persistent Volume Claims for + storage classes used by DevWorkspaces. + properties: + common: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "common" storage class. Note that the "async" storage + class also uses the PVC size set for the "common" storage + class. If not specified, the "common" and "async" Persistent + Volume Claim sizes are set to 10Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perWorkspace: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "per-workspace" storage class. If not specified, the + "per-workspace" Persistent Volume Claim size is set to 5Gi + 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 idleTimeout: description: IdleTimeout determines how long a workspace should sit idle before being automatically scaled down. Proper functionality @@ -296,7 +322,7 @@ spec: pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string storageClassName: - description: StorageClassName defines and optional storageClass + description: StorageClassName defines an optional storageClass to use for persistent volume claims created to support DevWorkspaces type: string type: object diff --git a/deploy/deployment/openshift/objects/devworkspaceoperatorconfigs.controller.devfile.io.CustomResourceDefinition.yaml b/deploy/deployment/openshift/objects/devworkspaceoperatorconfigs.controller.devfile.io.CustomResourceDefinition.yaml index c28cc7f31..589e2a665 100644 --- a/deploy/deployment/openshift/objects/devworkspaceoperatorconfigs.controller.devfile.io.CustomResourceDefinition.yaml +++ b/deploy/deployment/openshift/objects/devworkspaceoperatorconfigs.controller.devfile.io.CustomResourceDefinition.yaml @@ -97,6 +97,32 @@ spec: down (e.g. deployments but the objects will be left on the cluster). The default value is false. type: boolean + defaultStorageSize: + description: DefaultStorageSize defines an optional struct with + fields to specify the sizes of Persistent Volume Claims for + storage classes used by DevWorkspaces. + properties: + common: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "common" storage class. Note that the "async" storage + class also uses the PVC size set for the "common" storage + class. If not specified, the "common" and "async" Persistent + Volume Claim sizes are set to 10Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perWorkspace: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "per-workspace" storage class. If not specified, the + "per-workspace" Persistent Volume Claim size is set to 5Gi + 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 idleTimeout: description: IdleTimeout determines how long a workspace should sit idle before being automatically scaled down. Proper functionality @@ -296,7 +322,7 @@ spec: pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string storageClassName: - description: StorageClassName defines and optional storageClass + description: StorageClassName defines an optional storageClass to use for persistent volume claims created to support DevWorkspaces type: string type: object diff --git a/deploy/templates/crd/bases/controller.devfile.io_devworkspaceoperatorconfigs.yaml b/deploy/templates/crd/bases/controller.devfile.io_devworkspaceoperatorconfigs.yaml index 2eb7c70a9..e642539cc 100644 --- a/deploy/templates/crd/bases/controller.devfile.io_devworkspaceoperatorconfigs.yaml +++ b/deploy/templates/crd/bases/controller.devfile.io_devworkspaceoperatorconfigs.yaml @@ -96,6 +96,32 @@ spec: down (e.g. deployments but the objects will be left on the cluster). The default value is false. type: boolean + defaultStorageSize: + description: DefaultStorageSize defines an optional struct with + fields to specify the sizes of Persistent Volume Claims for + storage classes used by DevWorkspaces. + properties: + common: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "common" storage class. Note that the "async" storage + class also uses the PVC size set for the "common" storage + class. If not specified, the "common" and "async" Persistent + Volume Claim sizes are set to 10Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perWorkspace: + anyOf: + - type: integer + - type: string + description: The default Persistent Volume Claim size for + the "per-workspace" storage class. If not specified, the + "per-workspace" Persistent Volume Claim size is set to 5Gi + 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 idleTimeout: description: IdleTimeout determines how long a workspace should sit idle before being automatically scaled down. Proper functionality @@ -295,7 +321,7 @@ spec: pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string storageClassName: - description: StorageClassName defines and optional storageClass + description: StorageClassName defines an optional storageClass to use for persistent volume claims created to support DevWorkspaces type: string type: object From ac607df70fa717ab9cdd92e48ed5b8652c0275e9 Mon Sep 17 00:00:00 2001 From: Andrew Obuchowicz Date: Fri, 13 May 2022 12:10:11 -0400 Subject: [PATCH 3/3] feat: configmap option for perWorkspace PVC size Fix #836 Signed-off-by: Andrew Obuchowicz --- pkg/provision/storage/perWorkspaceStorage.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/provision/storage/perWorkspaceStorage.go b/pkg/provision/storage/perWorkspaceStorage.go index 71000f786..4dafe8bdd 100644 --- a/pkg/provision/storage/perWorkspaceStorage.go +++ b/pkg/provision/storage/perWorkspaceStorage.go @@ -25,8 +25,10 @@ import ( "github.com/devfile/devworkspace-operator/pkg/config" "github.com/devfile/devworkspace-operator/pkg/constants" devfileConstants "github.com/devfile/devworkspace-operator/pkg/library/constants" + nsconfig "github.com/devfile/devworkspace-operator/pkg/provision/config" "github.com/devfile/devworkspace-operator/pkg/provision/sync" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) @@ -148,11 +150,18 @@ func (p *PerWorkspaceStorageProvisioner) rewriteContainerVolumeMounts(workspaceI } func syncPerWorkspacePVC(workspace *dw.DevWorkspace, clusterAPI sync.ClusterAPI) (*corev1.PersistentVolumeClaim, error) { + namespacedConfig, err := nsconfig.ReadNamespacedConfig(workspace.Namespace, clusterAPI) + if err != nil { + return nil, fmt.Errorf("failed to read namespace-specific configuration: %w", err) + } // TODO: Determine the storage size that is needed by iterating through workspace volumes, // adding the sizes specified and figuring out overrides/defaults pvcSize := *config.Workspace.DefaultStorageSize.PerWorkspace if namespacedConfig != nil && namespacedConfig.PerWorkspacePVCSize != "" { - pvcSize = namespacedConfig.PerWorkspacePVCSize + pvcSize, err = resource.ParseQuantity(namespacedConfig.PerWorkspacePVCSize) + if err != nil { + return nil, err + } } pvc, err := getPVCSpec(common.PerWorkspacePVCName(workspace.Status.DevWorkspaceId), workspace.Namespace, pvcSize)