Skip to content

Commit

Permalink
feat: add volume resize support
Browse files Browse the repository at this point in the history
fix

fix test
  • Loading branch information
andyzhangx committed Dec 8, 2024
1 parent 8813b5b commit f03f02a
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 19 deletions.
3 changes: 3 additions & 0 deletions charts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ The following table lists the configurable parameters of the latest NFS CSI Driv
| `controller.resources.csiProvisioner.limits.memory` | csi-provisioner memory limits | 100Mi |
| `controller.resources.csiProvisioner.requests.cpu` | csi-provisioner cpu requests limits | 10m |
| `controller.resources.csiProvisioner.requests.memory` | csi-provisioner memory requests limits | 20Mi |
| `controller.resources.csiResizer.limits.memory` | csi-resizer memory limits | 400Mi |
| `controller.resources.csiResizer.requests.cpu` | csi-resizer cpu requests | 10m |
| `controller.resources.csiResizer.requests.memory` | csi-resizer memory requests | 20Mi |
| `controller.resources.livenessProbe.limits.memory` | liveness-probe memory limits | 100Mi |
| `controller.resources.livenessProbe.requests.cpu` | liveness-probe cpu requests limits | 10m |
| `controller.resources.livenessProbe.requests.memory` | liveness-probe memory requests limits | 20Mi |
Expand Down
Binary file modified charts/latest/csi-driver-nfs-v0.0.0.tgz
Binary file not shown.
24 changes: 24 additions & 0 deletions charts/latest/csi-driver-nfs/templates/csi-nfs-controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,30 @@ spec:
capabilities:
drop:
- ALL
- name: csi-resizer
{{- if hasPrefix "/" .Values.image.csiResizer.repository }}
image: "{{ .Values.image.baseRepo }}{{ .Values.image.csiResizer.repository }}:{{ .Values.image.csiResizer.tag }}"
{{- else }}
image: "{{ .Values.image.csiResizer.repository }}:{{ .Values.image.csiResizer.tag }}"
{{- end }}
args:
- "-csi-address=$(ADDRESS)"
- "-v=2"
- "-leader-election"
- "--leader-election-namespace={{ .Release.Namespace }}"
- '-handle-volume-inuse-error=false'
env:
- name: ADDRESS
value: /csi/csi.sock
imagePullPolicy: {{ .Values.image.csiResizer.pullPolicy }}
volumeMounts:
- name: socket-dir
mountPath: /csi
resources: {{- toYaml .Values.controller.resources.csiResizer | nindent 12 }}
securityContext:
capabilities:
drop:
- ALL
- name: csi-snapshotter
{{- if hasPrefix "/" .Values.image.csiSnapshotter.repository }}
image: "{{ .Values.image.baseRepo }}{{ .Values.image.csiSnapshotter.repository }}:{{ .Values.image.csiSnapshotter.tag }}"
Expand Down
10 changes: 10 additions & 0 deletions charts/latest/csi-driver-nfs/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ image:
repository: registry.k8s.io/sig-storage/csi-provisioner
tag: v5.1.0
pullPolicy: IfNotPresent
csiResizer:
repository: registry.k8s.io/sig-storage/csi-resizer
tag: v1.12.0
pullPolicy: IfNotPresent
csiSnapshotter:
repository: registry.k8s.io/sig-storage/csi-snapshotter
tag: v8.1.0
Expand Down Expand Up @@ -81,6 +85,12 @@ controller:
requests:
cpu: 10m
memory: 20Mi
csiResizer:
limits:
memory: 400Mi
requests:
cpu: 10m
memory: 20Mi
csiSnapshotter:
limits:
memory: 200Mi
Expand Down
24 changes: 24 additions & 0 deletions deploy/csi-nfs-controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,30 @@ spec:
capabilities:
drop:
- ALL
- name: csi-resizer
image: registry.k8s.io/sig-storage/csi-resizer:v1.12.0
args:
- "-csi-address=$(ADDRESS)"
- "-v=2"
- "-leader-election"
- "--leader-election-namespace=kube-system"
- '-handle-volume-inuse-error=false'
env:
- name: ADDRESS
value: /csi/csi.sock
volumeMounts:
- name: socket-dir
mountPath: /csi
resources:
limits:
memory: 400Mi
requests:
cpu: 10m
memory: 20Mi
securityContext:
capabilities:
drop:
- ALL
- name: csi-snapshotter
image: registry.k8s.io/sig-storage/csi-snapshotter:v8.1.0
args:
Expand Down
7 changes: 4 additions & 3 deletions hack/verify-helm-chart.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ pip install yq --ignore-installed PyYAML

# Extract images from csi-nfs-controller.yaml
expected_csi_provisioner_image="$(cat ${PKG_ROOT}/deploy/csi-nfs-controller.yaml | yq -r .spec.template.spec.containers[0].image | head -n 1)"
expected_csi_snapshotter_image="$(cat ${PKG_ROOT}/deploy/csi-nfs-controller.yaml | yq -r .spec.template.spec.containers[1].image | head -n 1)"
expected_liveness_probe_image="$(cat ${PKG_ROOT}/deploy/csi-nfs-controller.yaml | yq -r .spec.template.spec.containers[2].image | head -n 1)"
expected_nfs_image="$(cat ${PKG_ROOT}/deploy/csi-nfs-controller.yaml | yq -r .spec.template.spec.containers[3].image | head -n 1)"
expected_csi_resizer_image="$(cat ${PKG_ROOT}/deploy/csi-nfs-controller.yaml | yq -r .spec.template.spec.containers[1].image | head -n 1)"
expected_csi_snapshotter_image="$(cat ${PKG_ROOT}/deploy/csi-nfs-controller.yaml | yq -r .spec.template.spec.containers[2].image | head -n 1)"
expected_liveness_probe_image="$(cat ${PKG_ROOT}/deploy/csi-nfs-controller.yaml | yq -r .spec.template.spec.containers[3].image | head -n 1)"
expected_nfs_image="$(cat ${PKG_ROOT}/deploy/csi-nfs-controller.yaml | yq -r .spec.template.spec.containers[4].image | head -n 1)"

csi_provisioner_image="$(get_image_from_helm_chart "csiProvisioner")"
validate_image "${expected_csi_provisioner_image}" "${csi_provisioner_image}"
Expand Down
15 changes: 13 additions & 2 deletions pkg/nfs/controllerserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,19 @@ func (cs *ControllerServer) ListSnapshots(_ context.Context, _ *csi.ListSnapshot
return nil, status.Error(codes.Unimplemented, "")
}

func (cs *ControllerServer) ControllerExpandVolume(_ context.Context, _ *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) {
return nil, status.Error(codes.Unimplemented, "")
func (cs *ControllerServer) ControllerExpandVolume(_ context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) {
if len(req.GetVolumeId()) == 0 {
return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request")
}

if req.GetCapacityRange() == nil {
return nil, status.Error(codes.InvalidArgument, "Capacity Range missing in request")
}

volSizeBytes := int64(req.GetCapacityRange().GetRequiredBytes())
klog.V(2).Infof("ControllerExpandVolume(%s) successfully, currentQuota: %d bytes", req.VolumeId, volSizeBytes)

return &csi.ControllerExpandVolumeResponse{CapacityBytes: req.GetCapacityRange().GetRequiredBytes()}, nil
}

// Mount nfs server at base-dir
Expand Down
61 changes: 61 additions & 0 deletions pkg/nfs/controllerserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,13 @@ func TestControllerGetCapabilities(t *testing.T) {
},
},
},
{
Type: &csi.ControllerServiceCapability_Rpc{
Rpc: &csi.ControllerServiceCapability_RPC{
Type: csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
},
},
},
},
},
expectedErr: nil,
Expand Down Expand Up @@ -1057,6 +1064,60 @@ func TestDeleteSnapshot(t *testing.T) {
}
}

func TestControllerExpandVolume(t *testing.T) {
testCases := []struct {
name string
testFunc func(t *testing.T)
}{
{
name: "volume ID missing",
testFunc: func(t *testing.T) {
d := initTestController(t)
req := &csi.ControllerExpandVolumeRequest{}
_, err := d.ControllerExpandVolume(context.Background(), req)
expectedErr := status.Error(codes.InvalidArgument, "Volume ID missing in request")
if !reflect.DeepEqual(err, expectedErr) {
t.Errorf("actualErr: (%v), expectedErr: (%v)", err, expectedErr)
}
},
},
{
name: "Capacity Range missing",
testFunc: func(t *testing.T) {
d := initTestController(t)
req := &csi.ControllerExpandVolumeRequest{
VolumeId: "unit-test",
}
_, err := d.ControllerExpandVolume(context.Background(), req)
expectedErr := status.Error(codes.InvalidArgument, "Capacity Range missing in request")
if !reflect.DeepEqual(err, expectedErr) {
t.Errorf("actualErr: (%v), expectedErr: (%v)", err, expectedErr)
}
},
},
{
name: "Error = nil",
testFunc: func(t *testing.T) {
d := initTestController(t)
req := &csi.ControllerExpandVolumeRequest{
VolumeId: "unit-test",
CapacityRange: &csi.CapacityRange{
RequiredBytes: 10000,
},
}
_, err := d.ControllerExpandVolume(context.Background(), req)
if !reflect.DeepEqual(err, nil) {
t.Errorf("actualErr: (%v), expectedErr: (%v)", err, nil)
}
},
},
}

for _, tc := range testCases {
t.Run(tc.name, tc.testFunc)
}
}

func matchCreateSnapshotResponse(e, r *csi.CreateSnapshotResponse) error {
if e == nil && r == nil {
return nil
Expand Down
1 change: 1 addition & 0 deletions pkg/nfs/nfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ func NewDriver(options *DriverOptions) *Driver {
csi.ControllerServiceCapability_RPC_SINGLE_NODE_MULTI_WRITER,
csi.ControllerServiceCapability_RPC_CLONE_VOLUME,
csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
})

n.AddNodeServiceCapabilities([]csi.NodeServiceCapability_RPC_Type{
Expand Down
51 changes: 37 additions & 14 deletions test/e2e/dynamic_provisioning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
})

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

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

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) {
ginkgo.It("should create multiple PV objects, bind to PVCs and attach all to different pods on the same node", func(ctx ginkgo.SpecContext) {
pods := []testsuites.PodDetails{
{
Cmd: "while true; do echo $(date -u) >> /mnt/test-1/data; sleep 100; done",
Expand Down Expand Up @@ -135,7 +135,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
})

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

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) {
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) {
pod := testsuites.PodDetails{
Cmd: "echo 'hello world' >> /mnt/test-1/data && while true; do sleep 100; done",
Volumes: []testsuites.VolumeDetails{
Expand Down Expand Up @@ -188,7 +188,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
test.Run(ctx, cs, ns)
})

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) {
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) {
pod := testsuites.PodDetails{
Cmd: "echo 'hello world' >> /mnt/test-1/data && while true; do sleep 100; done",
Volumes: []testsuites.VolumeDetails{
Expand Down Expand Up @@ -217,7 +217,7 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
test.Run(ctx, cs, ns)
})

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

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

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

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

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

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

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

ginkgo.It("should create a volume on demand with archive subdir on delete [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) {
ginkgo.It("should create a volume on demand with archive subdir on delete", func(ctx ginkgo.SpecContext) {
pods := []testsuites.PodDetails{
{
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
Expand All @@ -396,4 +396,27 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
}
test.Run(ctx, cs, ns)
})

ginkgo.It("should create a volume on demand and resize it", func(ctx ginkgo.SpecContext) {
pods := []testsuites.PodDetails{
{
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
Volumes: []testsuites.VolumeDetails{
{
ClaimSize: "10Gi",
VolumeMount: testsuites.VolumeMountDetails{
NameGenerate: "test-volume-",
MountPathGenerate: "/mnt/test-",
},
},
},
},
}
test := testsuites.DynamicallyProvisionedResizeVolumeTest{
CSIDriver: testDriver,
Pods: pods,
StorageClassParameters: archiveSubDirStorageClassParameters,
}
test.Run(ctx, cs, ns)
})
})
Loading

0 comments on commit f03f02a

Please sign in to comment.