Skip to content

Commit d2e57a8

Browse files
[Shared Mount] E2E Same Bucket Different Volume
1 parent cc52522 commit d2e57a8

2 files changed

Lines changed: 76 additions & 3 deletions

File tree

test/e2e/specs/specs.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ const (
7373
ForceNewBucketPrefix = "gcsfuse-csi-force-new-bucket"
7474
SubfolderInBucketPrefix = "gcsfuse-csi-subfolder-in-bucket"
7575
MultipleBucketsPrefix = "gcsfuse-csi-multiple-buckets"
76+
BucketWithTwoUniqueVolSuffixPrefix = "gcsfuse-csi-bucket-with-two-unique-vol-suffix"
7677
EnableFileCacheForceNewBucketPrefix = "gcsfuse-csi-enable-file-cache-force-new-bucket"
7778
EnableFileCacheForceNewBucketAndMetricsPrefix = "gcsfuse-csi-enable-file-cache-force-new-bucket-and-metrics"
7879
EnableFileCachePrefix = "gcsfuse-csi-enable-file-cache"
@@ -598,7 +599,7 @@ func (t *TestPod) setupVolumeMount(name, mountPath string, readOnly bool, subPat
598599
// For shared-mount PreprovisionedPV, it creates the PV with an explicit name instead of
599600
// GenerateName, because upstream's GenerateName leaves pv.Name empty during webhook CREATE
600601
// admission, preventing the webhook from populating csi.storage.k8s.io/pv/name.
601-
func CreateVolumeResource(ctx context.Context, driver storageframework.TestDriver, config *storageframework.PerTestConfig, pattern storageframework.TestPattern, testVolumeSizeRange e2evolume.SizeRange) *storageframework.VolumeResource {
602+
func CreateVolumeResource(ctx context.Context, driver storageframework.TestDriver, config *storageframework.PerTestConfig, pattern storageframework.TestPattern, testVolumeSizeRange e2evolume.SizeRange, customVolumeHandleSuffix ...string) *storageframework.VolumeResource {
602603
gcsDriver, ok := driver.(*GCSFuseCSITestDriver)
603604
if !ok || !gcsDriver.EnableSharedMount || pattern.VolType != storageframework.PreprovisionedPV {
604605
return storageframework.CreateVolumeResource(ctx, driver, config, pattern, testVolumeSizeRange)
@@ -622,6 +623,10 @@ func CreateVolumeResource(ctx context.Context, driver storageframework.TestDrive
622623
framework.Failf("Failed to get PersistentVolumeSource for volume")
623624
}
624625

626+
if len(customVolumeHandleSuffix) > 0 && customVolumeHandleSuffix[0] != "" && pvSource.CSI != nil {
627+
pvSource.CSI.VolumeHandle += customVolumeHandleSuffix[0]
628+
}
629+
625630
pvName := fmt.Sprintf("gcsfuse-shared-pv-%s", rand.String(8))
626631
pvcName := fmt.Sprintf("pvc-%s", rand.String(8))
627632

test/e2e/testsuites/multivolume.go

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ import (
2525
"strings"
2626
"time"
2727

28+
"github.com/googlecloudplatform/gcs-fuse-csi-driver/pkg/util"
29+
"github.com/googlecloudplatform/gcs-fuse-csi-driver/pkg/webhook"
2830
"github.com/onsi/ginkgo/v2"
31+
"github.com/onsi/gomega"
32+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2933
utilerrors "k8s.io/apimachinery/pkg/util/errors"
3034
"k8s.io/klog/v2"
3135
"k8s.io/kubernetes/test/e2e/framework"
@@ -87,8 +91,16 @@ func (t *gcsFuseCSIMultiVolumeTestSuite) DefineTests(driver storageframework.Tes
8791
}
8892

8993
l.volumeResourceList = []*storageframework.VolumeResource{}
90-
for range volumeNumber {
91-
l.volumeResourceList = append(l.volumeResourceList, specs.CreateVolumeResource(ctx, driver, l.config, pattern, e2evolume.SizeRange{}))
94+
for i := range volumeNumber {
95+
suffix := ""
96+
if len(configPrefix) > 0 && configPrefix[0] == specs.BucketWithTwoUniqueVolSuffixPrefix {
97+
if i == 0 {
98+
suffix = ":rwx"
99+
} else if i == 1 {
100+
suffix = ":rox"
101+
}
102+
}
103+
l.volumeResourceList = append(l.volumeResourceList, specs.CreateVolumeResource(ctx, driver, l.config, pattern, e2evolume.SizeRange{}, suffix))
92104
}
93105
}
94106

@@ -396,4 +408,60 @@ func (t *gcsFuseCSIMultiVolumeTestSuite) DefineTests(driver storageframework.Tes
396408

397409
testOnePodMultipleBuckets()
398410
})
411+
412+
// This tests mounting two volumes via a unique suffix using shared mount as seen in https://docs.cloud.google.com/kubernetes-engine/docs/how-to/cloud-storage-fuse-csi-driver-pv#mount-same-bucket-different-pv.
413+
ginkgo.It("[shared-mount] should access the same bucket via different PV's with unique volumeHandles from different Pods on the same node", func() {
414+
if pattern.VolType != storageframework.PreprovisionedPV {
415+
e2eskipper.Skipf("skip for volume type %v", pattern.VolType)
416+
}
417+
418+
init(2, specs.BucketWithTwoUniqueVolSuffixPrefix)
419+
l.volumeResourceList[1].VolSource.PersistentVolumeClaim.ReadOnly = true
420+
defer cleanup()
421+
422+
// 1. Deploy Pod 1 (ReadWriteMany).
423+
ginkgo.By("Configuring the first pod (ReadWriteMany)")
424+
tPod1 := specs.NewTestPod(f.ClientSet, f.Namespace)
425+
tPod1.SetupVolume(l.volumeResourceList[0], volumeName, mountPath, false /* readOnly */)
426+
427+
ginkgo.By("Deploying the first pod")
428+
tPod1.Create(ctx)
429+
defer tPod1.Cleanup(ctx)
430+
431+
ginkgo.By("Checking that the first pod is running")
432+
tPod1.WaitForRunning(ctx)
433+
nodeName := tPod1.GetNode()
434+
435+
// 2. Deploy Pod 2 (ReadOnlyMany) on the same node.
436+
ginkgo.By("Configuring the second pod (ReadOnlyMany) on the same node")
437+
tPod2 := specs.NewTestPod(f.ClientSet, f.Namespace)
438+
tPod2.SetupVolume(l.volumeResourceList[1], volumeName, mountPath, true /* readOnly */)
439+
tPod2.SetNodeAffinity(nodeName, true /* sameNode */)
440+
441+
ginkgo.By("Deploying the second pod")
442+
tPod2.Create(ctx)
443+
defer tPod2.Cleanup(ctx)
444+
445+
ginkgo.By("Checking that the second pod is running")
446+
tPod2.WaitForRunning(ctx)
447+
448+
// 3. Verify distinct Mounter Pods exist for each volumeHandle in our ns.
449+
ginkgo.By("Verifying distinct Mounter Pods exist for each volumeHandle")
450+
mounterPods, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).List(ctx, metav1.ListOptions{
451+
LabelSelector: fmt.Sprintf("%s=%s", webhook.SharedMountLabel, util.TrueStr),
452+
})
453+
framework.ExpectNoError(err, "failed to list mounter pods")
454+
gomega.Expect(mounterPods.Items).To(gomega.HaveLen(2), "expected 2 distinct Mounter Pods for unique volumeHandles")
455+
456+
// 4. Verify Pod 1 (RWX) operations.
457+
ginkgo.By("Verifying RWX pod read and write operations")
458+
tPod1.VerifyExecInPodSucceed(f, specs.TesterContainerName, fmt.Sprintf("mount | grep %v | grep rw,", mountPath))
459+
tPod1.VerifyExecInPodSucceed(f, specs.TesterContainerName, fmt.Sprintf("echo 'hello world rwx' > %v/data-rwx && grep 'hello world rwx' %v/data-rwx", mountPath, mountPath))
460+
461+
// 5. Verify Pod 2 (ROX) operations and access mode enforcement.
462+
ginkgo.By("Verifying ROX pod read operation and write restriction enforcement")
463+
tPod2.VerifyExecInPodSucceed(f, specs.TesterContainerName, fmt.Sprintf("mount | grep %v | grep ro,", mountPath))
464+
tPod2.VerifyExecInPodSucceed(f, specs.TesterContainerName, fmt.Sprintf("grep 'hello world rwx' %v/data-rwx", mountPath))
465+
tPod2.VerifyExecInPodFail(f, specs.TesterContainerName, fmt.Sprintf("echo 'hello world rox' > %v/data-rox", mountPath), 1)
466+
})
399467
}

0 commit comments

Comments
 (0)