From c8f4b101a5b859fab0f7afbe43419bfade8f8ce1 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 30 Aug 2024 20:50:17 -0500 Subject: [PATCH 1/3] add mountpoint mounter Signed-off-by: Alexander Signed-off-by: Alexander Minbaev --- Dockerfile | 42 +++++++++- pkg/constants/constants.go | 1 + pkg/mounter/mounter-mountpoint.go | 132 ++++++++++++++++++++++++++++++ pkg/mounter/mounter.go | 2 + 4 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 pkg/mounter/mounter-mountpoint.go diff --git a/Dockerfile b/Dockerfile index 858a34bc..05453494 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6-941 as s3fs-builder +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6-941 as mountpoint-builder ARG RHSM_PASS=blank ARG RHSM_USER=blank @@ -6,6 +6,39 @@ ARG RHSM_USER=blank ENV RHSM_PASS "${RHSM_PASS}" ENV RHSM_USER "${RHSM_USER}" +ADD register-sys.sh /usr/bin/ +RUN microdnf update --setopt=tsflags=nodocs && \ + microdnf install -y --nodocs hostname subscription-manager +RUN hostname; chmod 755 /usr/bin/register-sys.sh && /usr/bin/register-sys.sh +# Install build tools +RUN microdnf update --setopt=tsflags=nodocs && \ + microdnf install -y --nodocs \ + fuse \ + fuse-devel \ + cmake3 \ + clang \ + git \ + pkgconf && \ + microdnf clean all + +# Install rust +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \ + source "$HOME/.cargo/env" + +# Build mountpoint-s3 +RUN git clone --recurse-submodules https://github.com/awslabs/mountpoint-s3.git && \ + source "$HOME/.cargo/env" && \ + cd mountpoint-s3 && \ + cargo build --release + +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6-941 as s3fs-builder + +ARG RHSM_PASS="alexander.minbaev@ibm.com" +ARG RHSM_USER="bonbon14011401!!" + +ENV RHSM_PASS "${RHSM_PASS}" +ENV RHSM_USER "${RHSM_USER}" + ADD register-sys.sh /usr/bin/ RUN microdnf update --setopt=tsflags=nodocs && \ microdnf install -y --nodocs hostname subscription-manager @@ -35,9 +68,9 @@ ENV GO_VERSION=1.19 RUN echo $ARCH $GO_VERSION RUN wget -q https://dl.google.com/go/go$GO_VERSION.linux-$ARCH.tar.gz && \ - tar -xf go$GO_VERSION.linux-$ARCH.tar.gz && \ - rm go$GO_VERSION.linux-$ARCH.tar.gz && \ - mv go /usr/local +tar -xf go$GO_VERSION.linux-$ARCH.tar.gz && \ +rm go$GO_VERSION.linux-$ARCH.tar.gz && \ +mv go /usr/local ENV GOROOT /usr/local/go ENV GOPATH /go @@ -61,6 +94,7 @@ LABEL description="IBM CSI Object Storage Plugin" LABEL build-date=${build_date} LABEL git-commit-id=${git_commit_id} RUN yum update -y && yum install fuse fuse-libs fuse3 fuse3-libs -y +COPY --from=mountpoint-builder /mountpoint-s3/target/release/mount-s3 /usr/bin/mount-s3 COPY --from=s3fs-builder /usr/local/bin/s3fs /usr/bin/s3fs COPY --from=rclone-builder /usr/local/bin/rclone /usr/bin/rclone COPY ibm-object-csi-driver ibm-object-csi-driver diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 1b752ad3..cca8452b 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -8,6 +8,7 @@ const ( S3FS = "s3fs" RClone = "rclone" + MNTS3 = "mountpoint" IAMEP = "https://private.iam.cloud.ibm.com/identity/token" ResourceConfigEPPrivate = "https://config.private.cloud-object-storage.cloud.ibm.com/v1" diff --git a/pkg/mounter/mounter-mountpoint.go b/pkg/mounter/mounter-mountpoint.go new file mode 100644 index 00000000..3e9135c4 --- /dev/null +++ b/pkg/mounter/mounter-mountpoint.go @@ -0,0 +1,132 @@ +/******************************************************************************* +* IBM Confidential +* OCO Source Materials +* IBM Cloud Kubernetes Service, 5737-D43 +* (C) Copyright IBM Corp. 2023 All Rights Reserved. +* The source code for this program is not published or otherwise divested of +* its trade secrets, irrespective of what has been deposited with +* the U.S. Copyright Office. +******************************************************************************/ + +// Package mounter +package mounter + +import ( + "crypto/sha256" + "fmt" + "os" + "path" + + // "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" + "k8s.io/klog/v2" +) + +// Mounter interface defined in mounter.go +// mntS3Mounter Implements Mounter +type mntS3Mounter struct { + bucketName string //From Secret in SC + objPath string //From Secret in SC + endPoint string //From Secret in SC + locConstraint string //From Secret in SC + authType string + accessKey string + secretKey string + mountOptions []string + MounterUtils utils.MounterUtils +} + +func NewMntS3Mounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils) Mounter { + klog.Info("-newMntS3Mounter-") + + var ( + val string + check bool + mounter *mntS3Mounter + ) + + mounter = &mntS3Mounter{} + + if val, check = secretMap["cosEndpoint"]; check { + mounter.endPoint = val + } + if val, check = secretMap["locationConstraint"]; check { + mounter.locConstraint = val + } + if val, check = secretMap["bucketName"]; check { + mounter.bucketName = val + } + if val, check = secretMap["objPath"]; check { + mounter.objPath = val + } + if val, check = secretMap["accessKey"]; check { + mounter.accessKey = val + } + if val, check = secretMap["secretKey"]; check { + mounter.secretKey = val + } + + klog.Infof("newMntS3Mounter args:\n\tbucketName: [%s]\n\tobjPath: [%s]\n\tendPoint: [%s]\n\tlocationConstraint: [%s]\n\tauthType: [%s]", + mounter.bucketName, mounter.objPath, mounter.endPoint, mounter.locConstraint, mounter.authType) + + mounter.mountOptions = mountOptions + mounter.MounterUtils = mounterUtils + + return mounter +} + +const ( + mntS3Cmd = "mount-s3" + metaRootMntS3 = "/var/lib/ibmc-mntS3" +) + +func (mntS3 *mntS3Mounter) Stage(stagePath string) error { + return nil +} +func (mntS3 *mntS3Mounter) Unstage(stagePath string) error { + return nil +} +func (mntS3 *mntS3Mounter) Mount(source string, target string) error { + klog.Info("-MntS3Mounter Mount-") + klog.Infof("Mount args:\n\tsource: <%s>\n\ttarget: <%s>", source, target) + var pathExist bool + var err error + metaPath := path.Join(metaRootMntS3, fmt.Sprintf("%x", sha256.Sum256([]byte(target)))) + + if pathExist, err = checkPath(metaPath); err != nil { + klog.Errorf("MntS3Mounter Mount: Cannot stat directory %s: %v", metaPath, err) + return err + } + + if !pathExist { + if err = os.MkdirAll(metaPath, 0755); // #nosec G301: used for mntS3 + err != nil { + klog.Errorf("MntS3Mounter Mount: Cannot create directory %s: %v", metaPath, err) + return err + } + } + + os.Setenv("AWS_ACCESS_KEY_ID", mntS3.accessKey) + os.Setenv("AWS_SECRET_ACCESS_KEY", mntS3.secretKey) + + args := []string{ + fmt.Sprintf("--endpoint-url=%v", mntS3.endPoint), + mntS3.bucketName, + target, + } + + if mntS3.objPath != "" { + args = append(args, fmt.Sprintf("--prefix %s", mntS3.objPath)) + } + return mntS3.MounterUtils.FuseMount(target, mntS3Cmd, args) +} +func (mntS3 *mntS3Mounter) Unmount(target string) error { + klog.Info("-MntS3Mounter Unmount-") + metaPath := path.Join(metaRootMntS3, fmt.Sprintf("%x", sha256.Sum256([]byte(target)))) + err := os.RemoveAll(metaPath) + if err != nil { + return err + } + + return mntS3.MounterUtils.FuseUnmount(target) +} diff --git a/pkg/mounter/mounter.go b/pkg/mounter/mounter.go index 16c84221..17098449 100644 --- a/pkg/mounter/mounter.go +++ b/pkg/mounter/mounter.go @@ -47,6 +47,8 @@ func (s *CSIMounterFactory) NewMounter(attrib map[string]string, secretMap map[s return NewS3fsMounter(secretMap, mountFlags, mounterUtils) case constants.RClone: return NewRcloneMounter(secretMap, mountFlags, mounterUtils) + case constants.MNTS3: + return NewMntS3Mounter(secretMap, mountFlags, mounterUtils) default: // default to s3fs return NewS3fsMounter(secretMap, mountFlags, mounterUtils) From 41e6f04a5561974535ffe8f95af739100a67beb6 Mon Sep 17 00:00:00 2001 From: Alexander Minbaev Date: Tue, 10 Sep 2024 04:30:05 -0500 Subject: [PATCH 2/3] add unit tests Signed-off-by: Alexander Minbaev --- pkg/mounter/fake_mounter_mountpoint.go | 43 ++++ pkg/mounter/mounter-mountpoint.go | 77 ++++--- pkg/mounter/mounter-mountpoint_test.go | 284 +++++++++++++++++++++++++ pkg/mounter/mounter.go | 2 +- pkg/mounter/mounter_test.go | 22 ++ 5 files changed, 386 insertions(+), 42 deletions(-) create mode 100644 pkg/mounter/fake_mounter_mountpoint.go create mode 100644 pkg/mounter/mounter-mountpoint_test.go diff --git a/pkg/mounter/fake_mounter_mountpoint.go b/pkg/mounter/fake_mounter_mountpoint.go new file mode 100644 index 00000000..43db1e11 --- /dev/null +++ b/pkg/mounter/fake_mounter_mountpoint.go @@ -0,0 +1,43 @@ +package mounter + +import "errors" + +type fakemountpointMounter struct { + bucketName string + objPath string + endPoint string + locConstraint string + authType string + accessKeys string + kpRootKeyCrn string + uid string + gid string + + isFailedMount bool +} + +func fakenewMountpointMounter(isFailedMount bool) Mounter { + return &fakercloneMounter{ + bucketName: bucketName, + objPath: objPath, + endPoint: endPoint, + locConstraint: region, + accessKeys: keys, + authType: authType, + kpRootKeyCrn: "", + uid: "", + gid: "", + isFailedMount: isFailedMount, + } +} + +func (mnpt *fakemountpointMounter) Mount(source string, target string) error { + if mnpt.isFailedMount { + return errors.New("failed to mount mountpoint") + } + return nil +} + +func (mnpt *fakemountpointMounter) Unmount(target string) error { + return nil +} diff --git a/pkg/mounter/mounter-mountpoint.go b/pkg/mounter/mounter-mountpoint.go index 3e9135c4..b3e76829 100644 --- a/pkg/mounter/mounter-mountpoint.go +++ b/pkg/mounter/mounter-mountpoint.go @@ -23,53 +23,48 @@ import ( ) // Mounter interface defined in mounter.go -// mntS3Mounter Implements Mounter -type mntS3Mounter struct { - bucketName string //From Secret in SC - objPath string //From Secret in SC - endPoint string //From Secret in SC - locConstraint string //From Secret in SC - authType string - accessKey string - secretKey string - mountOptions []string - MounterUtils utils.MounterUtils +// MountpointMounter Implements Mounter +type MountpointMounter struct { + BucketName string //From Secret in SC + ObjPath string //From Secret in SC + EndPoint string //From Secret in SC + AccessKey string + SecretKey string + MountOptions []string + MounterUtils utils.MounterUtils } -func NewMntS3Mounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils) Mounter { - klog.Info("-newMntS3Mounter-") +func NewMountpointMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils) Mounter { + klog.Info("-newMountpointMounter-") var ( val string check bool - mounter *mntS3Mounter + mounter *MountpointMounter ) - mounter = &mntS3Mounter{} + mounter = &MountpointMounter{} if val, check = secretMap["cosEndpoint"]; check { - mounter.endPoint = val - } - if val, check = secretMap["locationConstraint"]; check { - mounter.locConstraint = val + mounter.EndPoint = val } if val, check = secretMap["bucketName"]; check { - mounter.bucketName = val + mounter.BucketName = val } if val, check = secretMap["objPath"]; check { - mounter.objPath = val + mounter.ObjPath = val } if val, check = secretMap["accessKey"]; check { - mounter.accessKey = val + mounter.AccessKey = val } if val, check = secretMap["secretKey"]; check { - mounter.secretKey = val + mounter.SecretKey = val } - klog.Infof("newMntS3Mounter args:\n\tbucketName: [%s]\n\tobjPath: [%s]\n\tendPoint: [%s]\n\tlocationConstraint: [%s]\n\tauthType: [%s]", - mounter.bucketName, mounter.objPath, mounter.endPoint, mounter.locConstraint, mounter.authType) + klog.Infof("newMntS3Mounter args:\n\tbucketName: [%s]\n\tobjPath: [%s]\n\tendPoint: [%s]", + mounter.BucketName, mounter.ObjPath, mounter.EndPoint) - mounter.mountOptions = mountOptions + mounter.MountOptions = mountOptions mounter.MounterUtils = mounterUtils return mounter @@ -80,48 +75,48 @@ const ( metaRootMntS3 = "/var/lib/ibmc-mntS3" ) -func (mntS3 *mntS3Mounter) Stage(stagePath string) error { +func (mntS3 *MountpointMounter) Stage(stagePath string) error { return nil } -func (mntS3 *mntS3Mounter) Unstage(stagePath string) error { +func (mntS3 *MountpointMounter) Unstage(stagePath string) error { return nil } -func (mntS3 *mntS3Mounter) Mount(source string, target string) error { - klog.Info("-MntS3Mounter Mount-") +func (mntS3 *MountpointMounter) Mount(source string, target string) error { + klog.Info("-MountpointMounter Mount-") klog.Infof("Mount args:\n\tsource: <%s>\n\ttarget: <%s>", source, target) var pathExist bool var err error metaPath := path.Join(metaRootMntS3, fmt.Sprintf("%x", sha256.Sum256([]byte(target)))) if pathExist, err = checkPath(metaPath); err != nil { - klog.Errorf("MntS3Mounter Mount: Cannot stat directory %s: %v", metaPath, err) + klog.Errorf("MountpointMounter Mount: Cannot stat directory %s: %v", metaPath, err) return err } if !pathExist { - if err = os.MkdirAll(metaPath, 0755); // #nosec G301: used for mntS3 + if err = mkdirAll(metaPath, 0755); // #nosec G301: used for mntS3 err != nil { - klog.Errorf("MntS3Mounter Mount: Cannot create directory %s: %v", metaPath, err) + klog.Errorf("MountpointMounter Mount: Cannot create directory %s: %v", metaPath, err) return err } } - os.Setenv("AWS_ACCESS_KEY_ID", mntS3.accessKey) - os.Setenv("AWS_SECRET_ACCESS_KEY", mntS3.secretKey) + os.Setenv("AWS_ACCESS_KEY_ID", mntS3.AccessKey) + os.Setenv("AWS_SECRET_ACCESS_KEY", mntS3.SecretKey) args := []string{ - fmt.Sprintf("--endpoint-url=%v", mntS3.endPoint), - mntS3.bucketName, + fmt.Sprintf("--endpoint-url=%v", mntS3.EndPoint), + mntS3.BucketName, target, } - if mntS3.objPath != "" { - args = append(args, fmt.Sprintf("--prefix %s", mntS3.objPath)) + if mntS3.ObjPath != "" { + args = append(args, fmt.Sprintf("--prefix %s", mntS3.ObjPath)) } return mntS3.MounterUtils.FuseMount(target, mntS3Cmd, args) } -func (mntS3 *mntS3Mounter) Unmount(target string) error { - klog.Info("-MntS3Mounter Unmount-") +func (mntS3 *MountpointMounter) Unmount(target string) error { + klog.Info("-MountpointMounter Unmount-") metaPath := path.Join(metaRootMntS3, fmt.Sprintf("%x", sha256.Sum256([]byte(target)))) err := os.RemoveAll(metaPath) if err != nil { diff --git a/pkg/mounter/mounter-mountpoint_test.go b/pkg/mounter/mounter-mountpoint_test.go new file mode 100644 index 00000000..5e489fcb --- /dev/null +++ b/pkg/mounter/mounter-mountpoint_test.go @@ -0,0 +1,284 @@ +// Package mounter +package mounter + +import ( + "errors" + "os" + "testing" + + mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" + "github.com/stretchr/testify/assert" +) + +// Mock the secretMap and mountOptions +var secretMapMountpoint = map[string]string{ + "cosEndpoint": "test-endpoint", + "bucketName": "test-bucket-name", + "objPath": "test-obj-path", + "accessKey": "test-access-key", + "secretKey": "test-secret-key", + "apiKey": "test-api-key", +} + +var mountOptionsMountpoint = []string{"opt1=val1", "opt2=val2"} + +func TestNewMountpointMounter_Success(t *testing.T) { + mounter := NewMountpointMounter(secretMapMountpoint, mountOptionsMountpoint, mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{})) + + mntpMounter, ok := mounter.(*MountpointMounter) + if !ok { + t.Errorf("NewMountpointMounter() failed to return an instance of MountpointMounter") + } + + assert.Equal(t, mntpMounter.BucketName, secretMapMountpoint["bucketName"]) + assert.Equal(t, mntpMounter.ObjPath, secretMapMountpoint["objPath"]) + assert.Equal(t, mntpMounter.EndPoint, secretMapMountpoint["cosEndpoint"]) +} + +func TestNewMountpointMounter_Success_Hmac(t *testing.T) { + // Mock the secretMap and mountOptions + secretMap := map[string]string{ + "cosEndpoint": "test-endpoint", + "bucketName": "test-bucket-name", + "objPath": "test-obj-path", + "accessKey": "test-access-key", + "secretKey": "test-secret-key", + } + + mounter := NewMountpointMounter(secretMap, mountOptionsMountpoint, mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{})) + + mntpMounter, ok := mounter.(*MountpointMounter) + if !ok { + t.Errorf("NewMountpointMounter() failed to return an instance of MountpointMounter") + } + + assert.Equal(t, mntpMounter.BucketName, secretMap["bucketName"]) + assert.Equal(t, mntpMounter.ObjPath, secretMap["objPath"]) + assert.Equal(t, mntpMounter.EndPoint, secretMap["cosEndpoint"]) +} + +func TestNewMountpointMounter_MountOptsInSecret_Invalid(t *testing.T) { + secretMap := map[string]string{ + "cosEndpoint": "test-endpoint", + "bucketName": "test-bucket-name", + "objPath": "test-obj-path", + "accessKey": "test-access-key", + "secretKey": "test-secret-key", + "apiKey": "test-api-key", + "mountOptions": "upload_concurrency", + } + mounter := NewMountpointMounter(secretMap, mountOptionsMountpoint, mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{})) + + mntpMounter, ok := mounter.(*MountpointMounter) + if !ok { + t.Errorf("NewMountpointMounter() failed to return an instance of MountpointMounter") + } + + assert.Equal(t, mntpMounter.BucketName, secretMap["bucketName"]) + assert.Equal(t, mntpMounter.ObjPath, secretMap["objPath"]) + assert.Equal(t, mntpMounter.EndPoint, secretMap["cosEndpoint"]) +} + +func Test_MountpointMount_Positive(t *testing.T) { + mounter := NewMountpointMounter(secretMapMountpoint, mountOptionsMountpoint, + mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseMountFn: func(path string, comm string, args []string) error { + return nil + }, + })) + FakeMkdirAll := func(path string, perm os.FileMode) error { + return nil + } + + // Replace mkdirAllFunc with the Fake function + mkdirAllFunc = FakeMkdirAll + defer func() { mkdirAllFunc = os.MkdirAll }() + mntpMounter, ok := mounter.(*MountpointMounter) + if !ok { + t.Fatal("NewMountpointMounter() did not return a MountpointMounter") + } + + target := "/tmp/test-mount" + + err := mntpMounter.Mount("source", target) + assert.NoError(t, err) +} + +func Test_MountpointMount_Positive_Empty_ObjPath(t *testing.T) { + secretMap := map[string]string{ + "cosEndpoint": "test-endpoint", + "bucketName": "test-bucket-name", + "accessKey": "test-access-key", + "secretKey": "test-secret-key", + "apiKey": "test-api-key", + } + mounter := NewMountpointMounter(secretMap, mountOptionsMountpoint, + mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseMountFn: func(path string, comm string, args []string) error { + return nil + }, + })) + + FakeMkdirAll := func(path string, perm os.FileMode) error { + return nil + } + + // Replace mkdirAllFunc with the Fake function + mkdirAllFunc = FakeMkdirAll + defer func() { mkdirAllFunc = os.MkdirAll }() + + mntpMounter, ok := mounter.(*MountpointMounter) + if !ok { + t.Fatal("NewMountpointMounter() did not return a MountpointMounter") + } + + target := "/tmp/test-mount" + + err := mntpMounter.Mount("source", target) + assert.NoError(t, err) +} + +func Test_MountpointMount_Error_Creating_Mount_Point(t *testing.T) { + mounter := NewMountpointMounter(secretMapMountpoint, mountOptionsMountpoint, + mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseMountFn: func(path string, comm string, args []string) error { + return nil + }, + })) + + mntpMounter, ok := mounter.(*MountpointMounter) + if !ok { + t.Fatal("NewMountpointMounter() did not return a MountpointMounter") + } + + mockMkdirAll := func(path string, perm os.FileMode) error { + return errors.New("error creating mount path") + } + + // Replace mkdirAllFunc with the mock function + mkdirAllFunc = mockMkdirAll + defer func() { mkdirAllFunc = os.MkdirAll }() + + target := "/tmp/test-mount" + + err := mntpMounter.Mount("source", target) + assert.Error(t, err, "Cannot create directory") +} + +func Test_MountpointMount_ErrorMount(t *testing.T) { + mounter := NewMountpointMounter(secretMapMountpoint, mountOptionsMountpoint, + mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseMountFn: func(path string, comm string, args []string) error { + return errors.New("error mounting volume") + }, + })) + + FakeMkdirAll := func(path string, perm os.FileMode) error { + return nil + } + + // Replace mkdirAllFunc with the Fake function + mkdirAllFunc = FakeMkdirAll + defer func() { mkdirAllFunc = os.MkdirAll }() + + mntpMounter, ok := mounter.(*MountpointMounter) + if !ok { + t.Fatal("NewMountpointMounter() did not return a MountpointMounter") + } + + target := "/tmp/test-mount" + + err := mntpMounter.Mount("source", target) + assert.Error(t, err, "error mounting volume") +} + +func Test_MountpointUnmount_Positive(t *testing.T) { + secretMap := map[string]string{ + "cosEndpoint": "test-endpoint", + "bucketName": "test-bucket-name", + "objPath": "test-obj-path", + "accessKey": "test-access-key", + "secretKey": "test-secret-key", + "apiKey": "test-api-key", + } + mounter := NewMountpointMounter(secretMap, []string{"mountOption1", "mountOption2"}, + mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return nil + }, + })) + + mntpMounter, ok := mounter.(*MountpointMounter) + if !ok { + t.Fatal("NewMountpointMounter() did not return a MountpointMounter") + } + + target := "/tmp/test-unmount" + + // Creating a directory to simulate a mounted path + err := os.MkdirAll(target, os.ModePerm) + if err != nil { + t.Fatalf("Test_MountpointUnmount_Positive() failed to create directory: %v", err) + } + + err = mntpMounter.Unmount(target) + assert.NoError(t, err) + if err != nil { + t.Errorf("Test_MountpointUnmount_Positive() failed to unmount: %v", err) + } + + err = os.RemoveAll(target) + if err != nil { + t.Errorf("Failed to remove directory: %v", err) + } +} + +func Test_MountpointUnmount_Error(t *testing.T) { + secretMap := map[string]string{ + "cosEndpoint": "test-endpoint", + "bucketName": "test-bucket-name", + "objPath": "test-obj-path", + "accessKey": "test-access-key", + "secretKey": "test-secret-key", + "apiKey": "test-api-key", + } + mounter := NewMountpointMounter(secretMap, []string{"mountOption1", "mountOption2"}, + mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return errors.New("error unmounting volume") + }, + })) + + mntpMounter := mounter.(*MountpointMounter) + + target := "/tmp/test-unmount" + + // Creating a directory to simulate a mounted path + err := os.MkdirAll(target, os.ModePerm) + if err != nil { + t.Fatalf("TestMountpointUnmount_Error() failed to create directory: %v", err) + } + + err = mntpMounter.Unmount(target) + assert.Error(t, err, "error unmounting volume") + + err = os.RemoveAll(target) + if err != nil { + t.Errorf("Failed to remove directory: %v", err) + } +} + +func TestUpdateMountpointMountOptions(t *testing.T) { + defaultMountOp := []string{"option1=value1", "option2=value2"} + secretMap := map[string]string{ + "mountOptions": "additional_option=value3", + } + + updatedOptions := updateMountOptions(defaultMountOp, secretMap) + + assert.ElementsMatch(t, updatedOptions, []string{ + "option1=value1", + "option2=value2", + "additional_option=value3", + }) +} diff --git a/pkg/mounter/mounter.go b/pkg/mounter/mounter.go index 17098449..6a7f9f41 100644 --- a/pkg/mounter/mounter.go +++ b/pkg/mounter/mounter.go @@ -48,7 +48,7 @@ func (s *CSIMounterFactory) NewMounter(attrib map[string]string, secretMap map[s case constants.RClone: return NewRcloneMounter(secretMap, mountFlags, mounterUtils) case constants.MNTS3: - return NewMntS3Mounter(secretMap, mountFlags, mounterUtils) + return NewMountpointMounter(secretMap, mountFlags, mounterUtils) default: // default to s3fs return NewS3fsMounter(secretMap, mountFlags, mounterUtils) diff --git a/pkg/mounter/mounter_test.go b/pkg/mounter/mounter_test.go index 7ca6b28c..e864163f 100644 --- a/pkg/mounter/mounter_test.go +++ b/pkg/mounter/mounter_test.go @@ -75,6 +75,28 @@ func TestNewMounter(t *testing.T) { }, expectedErr: nil, }, + { + name: "Mountpoint Mounter", + attrib: map[string]string{"mounter": constants.MNTS3}, + secretMap: map[string]string{ + "cosEndpoint": "test-endpoint", + "bucketName": "test-bucket-name", + "objPath": "test-obj-path", + "accessKey": "test-access-key", + "secretKey": "test-secret-key", + }, + mountOptions: []string{"opt1=val1", "opt2=val2"}, + expected: &MountpointMounter{ + BucketName: "test-bucket-name", + ObjPath: "test-obj-path", + EndPoint: "test-endpoint", + AccessKey: "test-access-key", + SecretKey: "test-secret-key", + MountOptions: []string{"opt1=val1", "opt2=val2"}, + MounterUtils: &(mounterUtils.MounterOptsUtils{}), + }, + expectedErr: nil, + }, { name: "Default Mounter", attrib: map[string]string{}, From f1cdbbde289c1865754fceafe9f6261a0f2d0b53 Mon Sep 17 00:00:00 2001 From: Alexander Minbaev Date: Sat, 14 Sep 2024 00:10:42 -0500 Subject: [PATCH 3/3] fix travis Signed-off-by: Alexander Minbaev --- pkg/mounter/fake_mounter.go | 2 ++ pkg/mounter/fake_mounter_mountpoint.go | 19 +++++-------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/pkg/mounter/fake_mounter.go b/pkg/mounter/fake_mounter.go index 673f74cd..f368a5ea 100644 --- a/pkg/mounter/fake_mounter.go +++ b/pkg/mounter/fake_mounter.go @@ -22,6 +22,8 @@ func (f *FakeMounterFactory) NewMounter(attrib map[string]string, secretMap map[ return fakenewS3fsMounter(f.IsFailedMount) case constants.RClone: return fakenewRcloneMounter(f.IsFailedMount) + case constants.MNTS3: + return fakenewMountpointMounter(f.IsFailedMount) default: return fakenewS3fsMounter(f.IsFailedMount) } diff --git a/pkg/mounter/fake_mounter_mountpoint.go b/pkg/mounter/fake_mounter_mountpoint.go index 43db1e11..5c3149f8 100644 --- a/pkg/mounter/fake_mounter_mountpoint.go +++ b/pkg/mounter/fake_mounter_mountpoint.go @@ -6,27 +6,18 @@ type fakemountpointMounter struct { bucketName string objPath string endPoint string - locConstraint string - authType string - accessKeys string - kpRootKeyCrn string - uid string - gid string - + accessKey string + secretKey string isFailedMount bool } func fakenewMountpointMounter(isFailedMount bool) Mounter { - return &fakercloneMounter{ + return &fakemountpointMounter{ bucketName: bucketName, objPath: objPath, endPoint: endPoint, - locConstraint: region, - accessKeys: keys, - authType: authType, - kpRootKeyCrn: "", - uid: "", - gid: "", + accessKey: keys, + secretKey: keys, isFailedMount: isFailedMount, } }