Skip to content

Commit 1d37aa2

Browse files
committed
feat: add volume resize support
fix
1 parent 8813b5b commit 1d37aa2

10 files changed

+272
-16
lines changed

charts/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ The following table lists the configurable parameters of the latest NFS CSI Driv
7979
| `controller.resources.csiProvisioner.limits.memory` | csi-provisioner memory limits | 100Mi |
8080
| `controller.resources.csiProvisioner.requests.cpu` | csi-provisioner cpu requests limits | 10m |
8181
| `controller.resources.csiProvisioner.requests.memory` | csi-provisioner memory requests limits | 20Mi |
82+
| `controller.resources.csiResizer.limits.memory` | csi-resizer memory limits | 400Mi |
83+
| `controller.resources.csiResizer.requests.cpu` | csi-resizer cpu requests | 10m |
84+
| `controller.resources.csiResizer.requests.memory` | csi-resizer memory requests | 20Mi |
8285
| `controller.resources.livenessProbe.limits.memory` | liveness-probe memory limits | 100Mi |
8386
| `controller.resources.livenessProbe.requests.cpu` | liveness-probe cpu requests limits | 10m |
8487
| `controller.resources.livenessProbe.requests.memory` | liveness-probe memory requests limits | 20Mi |
89 Bytes
Binary file not shown.

charts/latest/csi-driver-nfs/templates/csi-nfs-controller.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,30 @@ spec:
7575
capabilities:
7676
drop:
7777
- ALL
78+
- name: csi-resizer
79+
{{- if hasPrefix "/" .Values.image.csiResizer.repository }}
80+
image: "{{ .Values.image.baseRepo }}{{ .Values.image.csiResizer.repository }}:{{ .Values.image.csiResizer.tag }}"
81+
{{- else }}
82+
image: "{{ .Values.image.csiResizer.repository }}:{{ .Values.image.csiResizer.tag }}"
83+
{{- end }}
84+
args:
85+
- "-csi-address=$(ADDRESS)"
86+
- "-v=2"
87+
- "-leader-election"
88+
- "--leader-election-namespace={{ .Release.Namespace }}"
89+
- '-handle-volume-inuse-error=false'
90+
env:
91+
- name: ADDRESS
92+
value: /csi/csi.sock
93+
imagePullPolicy: {{ .Values.image.csiResizer.pullPolicy }}
94+
volumeMounts:
95+
- name: socket-dir
96+
mountPath: /csi
97+
resources: {{- toYaml .Values.controller.resources.csiResizer | nindent 12 }}
98+
securityContext:
99+
capabilities:
100+
drop:
101+
- ALL
78102
- name: csi-snapshotter
79103
{{- if hasPrefix "/" .Values.image.csiSnapshotter.repository }}
80104
image: "{{ .Values.image.baseRepo }}{{ .Values.image.csiSnapshotter.repository }}:{{ .Values.image.csiSnapshotter.tag }}"

charts/latest/csi-driver-nfs/values.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ image:
99
repository: registry.k8s.io/sig-storage/csi-provisioner
1010
tag: v5.1.0
1111
pullPolicy: IfNotPresent
12+
csiResizer:
13+
repository: registry.k8s.io/sig-storage/csi-resizer
14+
tag: v1.12.0
15+
pullPolicy: IfNotPresent
1216
csiSnapshotter:
1317
repository: registry.k8s.io/sig-storage/csi-snapshotter
1418
tag: v8.1.0
@@ -81,6 +85,12 @@ controller:
8185
requests:
8286
cpu: 10m
8387
memory: 20Mi
88+
csiResizer:
89+
limits:
90+
memory: 400Mi
91+
requests:
92+
cpu: 10m
93+
memory: 20Mi
8494
csiSnapshotter:
8595
limits:
8696
memory: 200Mi

deploy/csi-nfs-controller.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,30 @@ spec:
6363
capabilities:
6464
drop:
6565
- ALL
66+
- name: csi-resizer
67+
image: registry.k8s.io/sig-storage/csi-resizer:v1.12.0
68+
args:
69+
- "-csi-address=$(ADDRESS)"
70+
- "-v=2"
71+
- "-leader-election"
72+
- "--leader-election-namespace=kube-system"
73+
- '-handle-volume-inuse-error=false'
74+
env:
75+
- name: ADDRESS
76+
value: /csi/csi.sock
77+
volumeMounts:
78+
- name: socket-dir
79+
mountPath: /csi
80+
resources:
81+
limits:
82+
memory: 400Mi
83+
requests:
84+
cpu: 10m
85+
memory: 20Mi
86+
securityContext:
87+
capabilities:
88+
drop:
89+
- ALL
6690
- name: csi-snapshotter
6791
image: registry.k8s.io/sig-storage/csi-snapshotter:v8.1.0
6892
args:

pkg/nfs/controllerserver.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,19 @@ func (cs *ControllerServer) ListSnapshots(_ context.Context, _ *csi.ListSnapshot
476476
return nil, status.Error(codes.Unimplemented, "")
477477
}
478478

479-
func (cs *ControllerServer) ControllerExpandVolume(_ context.Context, _ *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) {
480-
return nil, status.Error(codes.Unimplemented, "")
479+
func (cs *ControllerServer) ControllerExpandVolume(_ context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) {
480+
if len(req.GetVolumeId()) == 0 {
481+
return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request")
482+
}
483+
484+
if req.GetCapacityRange() == nil {
485+
return nil, status.Error(codes.InvalidArgument, "Capacity Range missing in request")
486+
}
487+
488+
volSizeBytes := int64(req.GetCapacityRange().GetRequiredBytes())
489+
klog.V(2).Infof("ControllerExpandVolume(%s) successfully, currentQuota: %d bytes", req.VolumeId, volSizeBytes)
490+
491+
return &csi.ControllerExpandVolumeResponse{CapacityBytes: req.GetCapacityRange().GetRequiredBytes()}, nil
481492
}
482493

483494
// Mount nfs server at base-dir

pkg/nfs/controllerserver_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,13 @@ func TestControllerGetCapabilities(t *testing.T) {
372372
},
373373
},
374374
},
375+
{
376+
Type: &csi.ControllerServiceCapability_Rpc{
377+
Rpc: &csi.ControllerServiceCapability_RPC{
378+
Type: csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
379+
},
380+
},
381+
},
375382
},
376383
},
377384
expectedErr: nil,
@@ -1057,6 +1064,60 @@ func TestDeleteSnapshot(t *testing.T) {
10571064
}
10581065
}
10591066

1067+
func TestControllerExpandVolume(t *testing.T) {
1068+
testCases := []struct {
1069+
name string
1070+
testFunc func(t *testing.T)
1071+
}{
1072+
{
1073+
name: "volume ID missing",
1074+
testFunc: func(t *testing.T) {
1075+
d := initTestController(t)
1076+
req := &csi.ControllerExpandVolumeRequest{}
1077+
_, err := d.ControllerExpandVolume(context.Background(), req)
1078+
expectedErr := status.Error(codes.InvalidArgument, "Volume ID missing in request")
1079+
if !reflect.DeepEqual(err, expectedErr) {
1080+
t.Errorf("actualErr: (%v), expectedErr: (%v)", err, expectedErr)
1081+
}
1082+
},
1083+
},
1084+
{
1085+
name: "Capacity Range missing",
1086+
testFunc: func(t *testing.T) {
1087+
d := initTestController(t)
1088+
req := &csi.ControllerExpandVolumeRequest{
1089+
VolumeId: "unit-test",
1090+
}
1091+
_, err := d.ControllerExpandVolume(context.Background(), req)
1092+
expectedErr := status.Error(codes.InvalidArgument, "Capacity Range missing in request")
1093+
if !reflect.DeepEqual(err, expectedErr) {
1094+
t.Errorf("actualErr: (%v), expectedErr: (%v)", err, expectedErr)
1095+
}
1096+
},
1097+
},
1098+
{
1099+
name: "Error = nil",
1100+
testFunc: func(t *testing.T) {
1101+
d := initTestController(t)
1102+
req := &csi.ControllerExpandVolumeRequest{
1103+
VolumeId: "unit-test",
1104+
CapacityRange: &csi.CapacityRange{
1105+
RequiredBytes: 10000,
1106+
},
1107+
}
1108+
_, err := d.ControllerExpandVolume(context.Background(), req)
1109+
if !reflect.DeepEqual(err, nil) {
1110+
t.Errorf("actualErr: (%v), expectedErr: (%v)", err, nil)
1111+
}
1112+
},
1113+
},
1114+
}
1115+
1116+
for _, tc := range testCases {
1117+
t.Run(tc.name, tc.testFunc)
1118+
}
1119+
}
1120+
10601121
func matchCreateSnapshotResponse(e, r *csi.CreateSnapshotResponse) error {
10611122
if e == nil && r == nil {
10621123
return nil

pkg/nfs/nfs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ func NewDriver(options *DriverOptions) *Driver {
103103
csi.ControllerServiceCapability_RPC_SINGLE_NODE_MULTI_WRITER,
104104
csi.ControllerServiceCapability_RPC_CLONE_VOLUME,
105105
csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
106+
csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
106107
})
107108

108109
n.AddNodeServiceCapabilities([]csi.NodeServiceCapability_RPC_Type{

test/e2e/dynamic_provisioning_test.go

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
5252
})
5353

5454
testDriver = driver.InitNFSDriver()
55-
ginkgo.It("should create a volume on demand with mount options [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
55+
ginkgo.It("should create a volume on demand with mount options", func(ctx ginkgo.SpecContext) {
5656
pods := []testsuites.PodDetails{
5757
{
5858
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
@@ -75,7 +75,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
7575
test.Run(ctx, cs, ns)
7676
})
7777

78-
ginkgo.It("should create a volume on demand with zero mountPermissions [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
78+
ginkgo.It("should create a volume on demand with zero mountPermissions", func(ctx ginkgo.SpecContext) {
7979
pods := []testsuites.PodDetails{
8080
{
8181
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
@@ -98,7 +98,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
9898
test.Run(ctx, cs, ns)
9999
})
100100

101-
ginkgo.It("should create multiple PV objects, bind to PVCs and attach all to different pods on the same node [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
101+
ginkgo.It("should create multiple PV objects, bind to PVCs and attach all to different pods on the same node", func(ctx ginkgo.SpecContext) {
102102
pods := []testsuites.PodDetails{
103103
{
104104
Cmd: "while true; do echo $(date -u) >> /mnt/test-1/data; sleep 100; done",
@@ -135,7 +135,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
135135
})
136136

137137
// Track issue https://github.com/kubernetes/kubernetes/issues/70505
138-
ginkgo.It("should create a volume on demand and mount it as readOnly in a pod [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
138+
ginkgo.It("should create a volume on demand and mount it as readOnly in a pod", func(ctx ginkgo.SpecContext) {
139139
pods := []testsuites.PodDetails{
140140
{
141141
Cmd: "touch /mnt/test-1/data",
@@ -159,7 +159,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
159159
test.Run(ctx, cs, ns)
160160
})
161161

162-
ginkgo.It("should create a deployment object, write and read to it, delete the pod and write and read to it again [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
162+
ginkgo.It("should create a deployment object, write and read to it, delete the pod and write and read to it again", func(ctx ginkgo.SpecContext) {
163163
pod := testsuites.PodDetails{
164164
Cmd: "echo 'hello world' >> /mnt/test-1/data && while true; do sleep 100; done",
165165
Volumes: []testsuites.VolumeDetails{
@@ -188,7 +188,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
188188
test.Run(ctx, cs, ns)
189189
})
190190

191-
ginkgo.It("[subDir]should create a deployment object, write and read to it, delete the pod and write and read to it again [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
191+
ginkgo.It("[subDir]should create a deployment object, write and read to it, delete the pod and write and read to it again", func(ctx ginkgo.SpecContext) {
192192
pod := testsuites.PodDetails{
193193
Cmd: "echo 'hello world' >> /mnt/test-1/data && while true; do sleep 100; done",
194194
Volumes: []testsuites.VolumeDetails{
@@ -217,7 +217,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
217217
test.Run(ctx, cs, ns)
218218
})
219219

220-
ginkgo.It(fmt.Sprintf("should delete PV with reclaimPolicy %q [nfs.csi.k8s.io]", v1.PersistentVolumeReclaimDelete), func(ctx ginkgo.SpecContext) {
220+
ginkgo.It(fmt.Sprintf("should delete PV with reclaimPolicy %q", v1.PersistentVolumeReclaimDelete), func(ctx ginkgo.SpecContext) {
221221
reclaimPolicy := v1.PersistentVolumeReclaimDelete
222222
volumes := []testsuites.VolumeDetails{
223223
{
@@ -234,7 +234,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
234234
test.Run(ctx, cs, ns)
235235
})
236236

237-
ginkgo.It(fmt.Sprintf("should retain PV with reclaimPolicy %q [nfs.csi.k8s.io]", v1.PersistentVolumeReclaimRetain), func(ctx ginkgo.SpecContext) {
237+
ginkgo.It(fmt.Sprintf("should retain PV with reclaimPolicy %q", v1.PersistentVolumeReclaimRetain), func(ctx ginkgo.SpecContext) {
238238
reclaimPolicy := v1.PersistentVolumeReclaimRetain
239239
volumes := []testsuites.VolumeDetails{
240240
{
@@ -251,7 +251,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
251251
test.Run(ctx, cs, ns)
252252
})
253253

254-
ginkgo.It("should create a pod with multiple volumes [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
254+
ginkgo.It("should create a pod with multiple volumes", func(ctx ginkgo.SpecContext) {
255255
volumes := []testsuites.VolumeDetails{}
256256
for i := 1; i <= 6; i++ {
257257
volume := testsuites.VolumeDetails{
@@ -278,7 +278,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
278278
test.Run(ctx, cs, ns)
279279
})
280280

281-
ginkgo.It("should create a pod with volume mount subpath [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
281+
ginkgo.It("should create a pod with volume mount subpath", func(ctx ginkgo.SpecContext) {
282282
pods := []testsuites.PodDetails{
283283
{
284284
Cmd: convertToPowershellCommandIfNecessary("echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data"),
@@ -301,7 +301,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
301301
test.Run(ctx, cs, ns)
302302
})
303303

304-
ginkgo.It("should create a CSI inline volume [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
304+
ginkgo.It("should create a CSI inline volume", func(ctx ginkgo.SpecContext) {
305305
pods := []testsuites.PodDetails{
306306
{
307307
Cmd: convertToPowershellCommandIfNecessary("echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data"),
@@ -328,7 +328,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
328328
test.Run(ctx, cs, ns)
329329
})
330330

331-
ginkgo.It("should create a volume on demand with retaining subdir on delete [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
331+
ginkgo.It("should create a volume on demand with retaining subdir on delete", func(ctx ginkgo.SpecContext) {
332332
pods := []testsuites.PodDetails{
333333
{
334334
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
@@ -351,7 +351,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
351351
test.Run(ctx, cs, ns)
352352
})
353353

354-
ginkgo.It("should create a volume on demand with archive on delete [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
354+
ginkgo.It("should create a volume on demand with archive on delete", func(ctx ginkgo.SpecContext) {
355355
pods := []testsuites.PodDetails{
356356
{
357357
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
@@ -374,7 +374,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
374374
test.Run(ctx, cs, ns)
375375
})
376376

377-
ginkgo.It("should create a volume on demand with archive subdir on delete [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
377+
ginkgo.It("should create a volume on demand with archive subdir on delete", func(ctx ginkgo.SpecContext) {
378378
pods := []testsuites.PodDetails{
379379
{
380380
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
@@ -396,4 +396,27 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
396396
}
397397
test.Run(ctx, cs, ns)
398398
})
399+
400+
ginkgo.It("should create a volume on demand and resize it", func(ctx ginkgo.SpecContext) {
401+
pods := []testsuites.PodDetails{
402+
{
403+
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
404+
Volumes: []testsuites.VolumeDetails{
405+
{
406+
ClaimSize: "10Gi",
407+
VolumeMount: testsuites.VolumeMountDetails{
408+
NameGenerate: "test-volume-",
409+
MountPathGenerate: "/mnt/test-",
410+
},
411+
},
412+
},
413+
},
414+
}
415+
test := testsuites.DynamicallyProvisionedResizeVolumeTest{
416+
CSIDriver: testDriver,
417+
Pods: pods,
418+
StorageClassParameters: archiveSubDirStorageClassParameters,
419+
}
420+
test.Run(ctx, cs, ns)
421+
})
399422
})

0 commit comments

Comments
 (0)