Skip to content

Commit 58881e0

Browse files
rohanKanojiadkwon17
authored andcommitted
feat : [CRW-5722] Add configuration option in DevWorkspaceOperatorConfig for storage access mode (#1019)
Set PVC accessMode if abovementioned option is set in WorkspaceConfig, default to ReadWriteOnce Signed-off-by: Rohan Kumar <[email protected]>
1 parent f708f0a commit 58881e0

File tree

6 files changed

+93
-10
lines changed

6 files changed

+93
-10
lines changed

pkg/config/sync.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ func mergeConfig(from, to *controller.OperatorConfiguration) {
341341
if from.Workspace.ContainerSecurityContext != nil {
342342
to.Workspace.ContainerSecurityContext = mergeContainerSecurityContext(to.Workspace.ContainerSecurityContext, from.Workspace.ContainerSecurityContext)
343343
}
344+
if from.Workspace.StorageAccessMode != nil {
345+
to.Workspace.StorageAccessMode = from.Workspace.StorageAccessMode
346+
}
344347
if from.Workspace.DefaultStorageSize != nil {
345348
if to.Workspace.DefaultStorageSize == nil {
346349
to.Workspace.DefaultStorageSize = &controller.StorageSizes{}

pkg/config/sync_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,24 @@ func TestMergeConfigLooksAtAllFields(t *testing.T) {
440440
assert.Equal(t, expectedConfig, actualConfig, "merging configs should merge all fields")
441441
}
442442

443+
func TestMergeConfigMergesStorageAccessMode(t *testing.T) {
444+
// Given
445+
expectedConfig := &v1alpha1.OperatorConfiguration{
446+
Workspace: &v1alpha1.WorkspaceConfig{
447+
StorageAccessMode: []corev1.PersistentVolumeAccessMode{
448+
corev1.ReadWriteMany,
449+
},
450+
},
451+
}
452+
actualConfig := &v1alpha1.OperatorConfiguration{}
453+
454+
// When
455+
mergeConfig(expectedConfig, actualConfig)
456+
457+
// Then
458+
assert.Equal(t, expectedConfig.Workspace.StorageAccessMode, actualConfig.Workspace.StorageAccessMode)
459+
}
460+
443461
func fuzzQuantity(q *resource.Quantity, c fuzz.Continue) {
444462
q.Set(c.Int63n(999))
445463
q.Format = resource.DecimalSI

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
}

pkg/provision/storage/shared_test.go

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)