Skip to content

Commit 2b13831

Browse files
committed
feat : [CRW-5722] Add configuration option in DevWorkspaceOperatorConfig for storage access mode (#1019)
- Add configuration option named StorageAccessMode in WorkspaceConfig struct - Set PVC accessMode if abovementioned option is set in WorkspaceConfig, default to ReadWriteOnce Signed-off-by: Rohan Kumar <[email protected]>
1 parent 2e7face commit 2b13831

File tree

6 files changed

+79
-11
lines changed

6 files changed

+79
-11
lines changed

apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ type WorkspaceConfig struct {
134134
StorageClassName *string `json:"storageClassName,omitempty"`
135135
// DefaultStorageSize defines an optional struct with fields to specify the sizes of Persistent Volume Claims for storage
136136
// classes used by DevWorkspaces.
137-
DefaultStorageSize *StorageSizes `json:"defaultStorageSize,omitempty"`
137+
DefaultStorageSize *StorageSizes `json:"defaultStorageSize,omitempty"`
138+
StorageAccessMode []corev1.PersistentVolumeAccessMode `json:"storageAccessMode,omitempty"`
138139
// PersistUserHome defines configuration options for persisting the `/home/user/`
139140
// directory in workspaces.
140141
PersistUserHome *PersistentHomeConfig `json:"persistUserHome,omitempty"`

apis/controller/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/provision/storage/commonStorage_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,13 @@ func TestUseCommonStorageProvisionerForPerUserStorageClass(t *testing.T) {
130130
func TestProvisionStorageForCommonStorageClass(t *testing.T) {
131131
tests := loadAllTestCasesOrPanic(t, "testdata/common-storage")
132132
commonStorage := CommonStorageProvisioner{}
133-
commonPVC, err := getPVCSpec("claim-devworkspace", "test-namespace", nil, resource.MustParse("10Gi"))
133+
commonPVC, err := getPVCSpec("claim-devworkspace", "test-namespace", nil, resource.MustParse("10Gi"), nil)
134134
if err != nil {
135135
t.Fatalf("Failure during setup: %s", err)
136136
}
137137
commonPVC.Status.Phase = corev1.ClaimBound
138138
clusterAPI := sync.ClusterAPI{
139-
Client: fake.NewFakeClientWithScheme(scheme, commonPVC),
139+
Client: fake.NewClientBuilder().WithScheme(scheme).WithObjects(commonPVC).Build(),
140140
Logger: zap.New(),
141141
}
142142

@@ -166,15 +166,15 @@ func TestProvisionStorageForCommonStorageClass(t *testing.T) {
166166

167167
func TestTerminatingPVC(t *testing.T) {
168168
commonStorage := CommonStorageProvisioner{}
169-
commonPVC, err := getPVCSpec("claim-devworkspace", "test-namespace", nil, resource.MustParse("10Gi"))
169+
commonPVC, err := getPVCSpec("claim-devworkspace", "test-namespace", nil, resource.MustParse("10Gi"), nil)
170170
if err != nil {
171171
t.Fatalf("Failure during setup: %s", err)
172172
}
173173
testTime := metav1.Now()
174174
commonPVC.SetDeletionTimestamp(&testTime)
175175

176176
clusterAPI := sync.ClusterAPI{
177-
Client: fake.NewFakeClientWithScheme(scheme, commonPVC),
177+
Client: fake.NewClientBuilder().WithScheme(scheme).WithObjects(commonPVC).Build(),
178178
Logger: zap.New(),
179179
}
180180
testCase := loadTestCaseOrPanic(t, "testdata/common-storage/rewrites-volumes-for-common-pvc-strategy.yaml")

pkg/provision/storage/perWorkspaceStorage.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ func syncPerWorkspacePVC(workspace *common.DevWorkspaceWithConfig, clusterAPI sy
219219
}
220220

221221
storageClass := workspace.Config.Workspace.StorageClassName
222-
pvc, err := getPVCSpec(common.PerWorkspacePVCName(workspace.Status.DevWorkspaceId), workspace.Namespace, storageClass, *pvcSize)
222+
pvc, err := getPVCSpec(common.PerWorkspacePVCName(workspace.Status.DevWorkspaceId), workspace.Namespace, storageClass, *pvcSize, workspace.Config.Workspace.StorageAccessMode)
223223
if err != nil {
224224
return nil, err
225225
}

pkg/provision/storage/shared.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,18 @@ func WorkspaceNeedsStorage(workspace *dw.DevWorkspaceTemplateSpec) bool {
6060
return containerlib.AnyMountSources(workspace.Components)
6161
}
6262

63-
func getPVCSpec(name, namespace string, storageClass *string, size resource.Quantity) (*corev1.PersistentVolumeClaim, error) {
63+
func getPVCSpec(name, namespace string, storageClass *string, size resource.Quantity, storageAccessMode []corev1.PersistentVolumeAccessMode) (*corev1.PersistentVolumeClaim, error) {
64+
if storageAccessMode == nil || len(storageAccessMode) == 0 {
65+
storageAccessMode = []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce}
66+
}
6467

6568
return &corev1.PersistentVolumeClaim{
6669
ObjectMeta: metav1.ObjectMeta{
6770
Name: name,
6871
Namespace: namespace,
6972
},
7073
Spec: corev1.PersistentVolumeClaimSpec{
71-
AccessModes: []corev1.PersistentVolumeAccessMode{
72-
corev1.ReadWriteOnce,
73-
},
74+
AccessModes: storageAccessMode,
7475
Resources: corev1.ResourceRequirements{
7576
Requests: corev1.ResourceList{
7677
"storage": size,
@@ -99,7 +100,7 @@ func syncCommonPVC(namespace string, config *v1alpha1.OperatorConfiguration, clu
99100
}
100101
}
101102

102-
pvc, err := getPVCSpec(config.Workspace.PVCName, namespace, config.Workspace.StorageClassName, pvcSize)
103+
pvc, err := getPVCSpec(config.Workspace.PVCName, namespace, config.Workspace.StorageClassName, pvcSize, config.Workspace.StorageAccessMode)
103104
if err != nil {
104105
return nil, err
105106
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// Copyright (c) 2019-2025 Red Hat, Inc.
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
package storage
17+
18+
import (
19+
"testing"
20+
21+
"github.com/stretchr/testify/assert"
22+
corev1 "k8s.io/api/core/v1"
23+
"k8s.io/apimachinery/pkg/api/resource"
24+
)
25+
26+
func TestGetPVCSpecWithDefaultStorageAccessMode(t *testing.T) {
27+
// Given
28+
name := "test-pvc"
29+
namespace := "default"
30+
storageClass := "standard"
31+
32+
// When
33+
pvc, err := getPVCSpec(name, namespace, &storageClass, resource.MustParse("5Gi"), nil)
34+
35+
// Then
36+
assert.NoError(t, err, "Expected no error")
37+
assert.Equal(t, name, pvc.Name, "PVC name should match")
38+
assert.Equal(t, namespace, pvc.Namespace, "PVC namespace should match")
39+
assert.Equal(t, storageClass, *pvc.Spec.StorageClassName, "Storage class should match")
40+
assert.Equal(t, []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce}, pvc.Spec.AccessModes, "Access modes should match")
41+
assert.Equal(t, "5Gi", pvc.Spec.Resources.Requests.Storage().String(), "Storage size should match")
42+
}
43+
44+
func TestGetPVCSpecWithCustomStorageAccessMode(t *testing.T) {
45+
// Given
46+
name := "test-pvc"
47+
namespace := "default"
48+
storageClass := "standard"
49+
storageAccessMode := []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOncePod}
50+
51+
// When
52+
pvc, err := getPVCSpec(name, namespace, &storageClass, resource.MustParse("5Gi"), storageAccessMode)
53+
54+
// Then
55+
assert.NoError(t, err, "Expected no error")
56+
assert.Equal(t, name, pvc.Name, "PVC name should match")
57+
assert.Equal(t, namespace, pvc.Namespace, "PVC namespace should match")
58+
assert.Equal(t, storageClass, *pvc.Spec.StorageClassName, "Storage class should match")
59+
assert.Equal(t, []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOncePod}, pvc.Spec.AccessModes, "Access modes should match")
60+
assert.Equal(t, "5Gi", pvc.Spec.Resources.Requests.Storage().String(), "Storage size should match")
61+
}

0 commit comments

Comments
 (0)