From d71f63fae4b792dbf1009845853f907fd242eac0 Mon Sep 17 00:00:00 2001 From: Ivan Volynkin Date: Mon, 23 Jan 2023 09:42:18 +0300 Subject: [PATCH] Support other filesystem types (#77) --- Dockerfile | 2 +- examples/csi-pvc-xfs.yaml | 11 +++++ examples/csi-storageclass-linear-xfs.yaml | 11 +++++ pkg/lvm/lvm.go | 49 +++++++++++++++++------ pkg/lvm/nodeserver.go | 2 +- tests/bats/test.bats | 27 +++++++++++++ tests/files/xfs.yaml | 20 +++++++++ 7 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 examples/csi-pvc-xfs.yaml create mode 100644 examples/csi-storageclass-linear-xfs.yaml create mode 100644 tests/files/xfs.yaml diff --git a/Dockerfile b/Dockerfile index 48c73e55..1a02ac4d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ FROM alpine:3.16 LABEL maintainers="Metal Authors" LABEL description="LVM Driver" -RUN apk add lvm2 lvm2-extra e2fsprogs e2fsprogs-extra smartmontools nvme-cli util-linux device-mapper +RUN apk add lvm2 lvm2-extra e2fsprogs e2fsprogs-extra smartmontools nvme-cli util-linux device-mapper xfsprogs xfsprogs-extra COPY --from=builder /work/bin/lvmplugin /lvmplugin USER root ENTRYPOINT ["/lvmplugin"] diff --git a/examples/csi-pvc-xfs.yaml b/examples/csi-pvc-xfs.yaml new file mode 100644 index 00000000..eac0e488 --- /dev/null +++ b/examples/csi-pvc-xfs.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: csi-pvc-xfs +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi + storageClassName: csi-lvm-sc-linear-xfs diff --git a/examples/csi-storageclass-linear-xfs.yaml b/examples/csi-storageclass-linear-xfs.yaml new file mode 100644 index 00000000..b705c0c4 --- /dev/null +++ b/examples/csi-storageclass-linear-xfs.yaml @@ -0,0 +1,11 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: csi-lvm-sc-linear-xfs +provisioner: lvm.csi.metal-stack.io +reclaimPolicy: Delete +volumeBindingMode: WaitForFirstConsumer +allowVolumeExpansion: true +parameters: + type: "linear" + fsType: xfs diff --git a/pkg/lvm/lvm.go b/pkg/lvm/lvm.go index b98c38e8..6b70fc7d 100644 --- a/pkg/lvm/lvm.go +++ b/pkg/lvm/lvm.go @@ -22,6 +22,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strconv" "strings" "time" @@ -78,12 +79,17 @@ type volumeAction struct { } const ( - linearType = "linear" - stripedType = "striped" - mirrorType = "mirror" - actionTypeCreate = "create" - actionTypeDelete = "delete" - pullIfNotPresent = "ifnotpresent" + linearType = "linear" + stripedType = "striped" + mirrorType = "mirror" + actionTypeCreate = "create" + actionTypeDelete = "delete" + pullIfNotPresent = "ifnotpresent" + fsTypeRegexpString = `TYPE="(\w+)"` +) + +var ( + fsTypeRegexp = regexp.MustCompile(fsTypeRegexpString) ) // NewLvmDriver creates the driver @@ -143,23 +149,42 @@ func (lvm *Lvm) Run() error { return nil } -func mountLV(lvname, mountPath string, vgName string) (string, error) { +func mountLV(lvname, mountPath string, vgName string, fsType string) (string, error) { lvPath := fmt.Sprintf("/dev/%s/%s", vgName, lvname) formatted := false + forceFormat := false + if fsType == "" { + fsType = "ext4" + } // check for already formatted cmd := exec.Command("blkid", lvPath) out, err := cmd.CombinedOutput() if err != nil { klog.Infof("unable to check if %s is already formatted:%v", lvPath, err) } - if strings.Contains(string(out), "ext4") { - formatted = true + matches := fsTypeRegexp.FindStringSubmatch(string(out)) + if len(matches) > 1 { + if matches[1] == "xfs_external_log" { // If old xfs signature was found + forceFormat = true + } else { + if matches[1] != fsType { + return string(out), fmt.Errorf("target fsType is %s but %s found", fsType, matches[1]) + } + + formatted = true + } } if !formatted { - klog.Infof("formatting with mkfs.ext4 %s", lvPath) - cmd = exec.Command("mkfs.ext4", lvPath) + formatArgs := []string{} + if forceFormat { + formatArgs = append(formatArgs, "-f") + } + formatArgs = append(formatArgs, lvPath) + + klog.Infof("formatting with mkfs.%s %s", fsType, strings.Join(formatArgs, " ")) + cmd = exec.Command(fmt.Sprintf("mkfs.%s", fsType), formatArgs...) //nolint:gosec out, err = cmd.CombinedOutput() if err != nil { return string(out), fmt.Errorf("unable to format lv:%s err:%w", lvname, err) @@ -172,7 +197,7 @@ func mountLV(lvname, mountPath string, vgName string) (string, error) { } // --make-shared is required that this mount is visible outside this container. - mountArgs := []string{"--make-shared", "-t", "ext4", lvPath, mountPath} + mountArgs := []string{"--make-shared", "-t", fsType, lvPath, mountPath} klog.Infof("mountlv command: mount %s", mountArgs) cmd = exec.Command("mount", mountArgs...) out, err = cmd.CombinedOutput() diff --git a/pkg/lvm/nodeserver.go b/pkg/lvm/nodeserver.go index a13e8188..469a09db 100644 --- a/pkg/lvm/nodeserver.go +++ b/pkg/lvm/nodeserver.go @@ -143,7 +143,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis } else if req.GetVolumeCapability().GetMount() != nil { - output, err := mountLV(req.GetVolumeId(), targetPath, ns.vgName) + output, err := mountLV(req.GetVolumeId(), targetPath, ns.vgName, req.GetVolumeCapability().GetMount().GetFsType()) if err != nil { return nil, fmt.Errorf("unable to mount lv: %w output:%s", err, output) } diff --git a/tests/bats/test.bats b/tests/bats/test.bats index df585610..e88057ba 100644 --- a/tests/bats/test.bats +++ b/tests/bats/test.bats @@ -108,6 +108,33 @@ [ "${lines[0]}" = "persistentvolumeclaim \"lvm-pvc-block\" deleted" ] [ "${lines[1]}" = "persistentvolumeclaim \"lvm-pvc-linear\" deleted" ] } + +@test "deploy inline xfs pod with ephemeral volume" { + run sleep 10 + run kubectl apply -f files/xfs.yaml + [ "$status" -eq 0 ] + [ "${lines[0]}" = "pod/volume-test-inline-xfs created" ] +} + +@test "inline xfs pod running" { + run kubectl wait --for=condition=ready pod/volume-test-inline-xfs --timeout=180s + run kubectl get pods volume-test-inline-xfs -o jsonpath="{.metadata.name},{.status.phase}" + [ "$status" -eq 0 ] + [ "$output" = "volume-test-inline-xfs,Running" ] +} + +@test "check fsType" { + run kubectl exec -it volume-test-inline-xfs -c inline -- sh -c "mount | grep /data" + [ "$status" -eq 0 ] + [[ "$output" == *"xfs"* ]] +} + +@test "delete inline xfs linear pod" { + run kubectl delete -f files/xfs.yaml + [ "$status" -eq 0 ] + [ "${lines[0]}" = "pod \"volume-test-inline-xfs\" deleted" ] +} + @test "clean up " { run sleep 60 run helm uninstall csi-driver-lvm diff --git a/tests/files/xfs.yaml b/tests/files/xfs.yaml new file mode 100644 index 00000000..fc339cea --- /dev/null +++ b/tests/files/xfs.yaml @@ -0,0 +1,20 @@ +kind: Pod +apiVersion: v1 +metadata: + name: volume-test-inline-xfs +spec: + containers: + - name: inline + image: nginx:stable-alpine + imagePullPolicy: IfNotPresent + volumeMounts: + - mountPath: "/data" + name: lvm-pvc-inline-xfs + volumes: + - name: lvm-pvc-inline-xfs + csi: + driver: lvm.csi.metal-stack.io + volumeAttributes: + size: "20MB" + type: "linear" + fsType: xfs \ No newline at end of file