Skip to content

Commit 14b32ca

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

2 files changed

Lines changed: 82 additions & 3 deletions

File tree

test/e2e/specs/specs.go

Lines changed: 9 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,13 @@ 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] != "" {
627+
if pvSource.CSI == nil || pvSource.CSI.VolumeHandle == "" {
628+
framework.Failf("Failed to apply custom volume handle suffix")
629+
}
630+
pvSource.CSI.VolumeHandle += customVolumeHandleSuffix[0]
631+
}
632+
625633
pvName := fmt.Sprintf("gcsfuse-shared-pv-%s", rand.String(8))
626634
pvcName := fmt.Sprintf("pvc-%s", rand.String(8))
627635

test/e2e/testsuites/multivolume.go

Lines changed: 73 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,63 @@ 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+
420+
gomega.Expect(l.volumeResourceList[1].VolSource).ToNot(gomega.BeNil())
421+
gomega.Expect(l.volumeResourceList[1].VolSource.PersistentVolumeClaim).ToNot(gomega.BeNil())
422+
l.volumeResourceList[1].VolSource.PersistentVolumeClaim.ReadOnly = true
423+
defer cleanup()
424+
425+
// 1. Deploy Pod 1 (ReadWriteMany).
426+
ginkgo.By("Configuring the first pod (ReadWriteMany)")
427+
tPod1 := specs.NewTestPod(f.ClientSet, f.Namespace)
428+
tPod1.SetupVolume(l.volumeResourceList[0], volumeName, mountPath, false /* readOnly */)
429+
430+
ginkgo.By("Deploying the first pod")
431+
tPod1.Create(ctx)
432+
defer tPod1.Cleanup(ctx)
433+
434+
ginkgo.By("Checking that the first pod is running")
435+
tPod1.WaitForRunning(ctx)
436+
nodeName := tPod1.GetNode()
437+
438+
// 2. Deploy Pod 2 (ReadOnlyMany) on the same node.
439+
ginkgo.By("Configuring the second pod (ReadOnlyMany) on the same node")
440+
tPod2 := specs.NewTestPod(f.ClientSet, f.Namespace)
441+
tPod2.SetupVolume(l.volumeResourceList[1], volumeName, mountPath, true /* readOnly */)
442+
tPod2.SetNodeAffinity(nodeName, true /* sameNode */)
443+
444+
ginkgo.By("Deploying the second pod")
445+
tPod2.Create(ctx)
446+
defer tPod2.Cleanup(ctx)
447+
448+
ginkgo.By("Checking that the second pod is running")
449+
tPod2.WaitForRunning(ctx)
450+
451+
// 3. Verify distinct Mounter Pods exist for each volumeHandle in our ns.
452+
ginkgo.By("Verifying distinct Mounter Pods exist for each volumeHandle")
453+
mounterPods, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).List(ctx, metav1.ListOptions{
454+
LabelSelector: fmt.Sprintf("%s=%s", webhook.SharedMountLabel, util.TrueStr),
455+
})
456+
framework.ExpectNoError(err, "failed to list mounter pods")
457+
gomega.Expect(mounterPods.Items).To(gomega.HaveLen(2), "expected 2 distinct Mounter Pods for unique volumeHandles")
458+
459+
// 4. Verify Pod 1 (RWX) operations.
460+
ginkgo.By("Verifying RWX pod read and write operations")
461+
tPod1.VerifyExecInPodSucceed(f, specs.TesterContainerName, fmt.Sprintf("mount | grep %v | grep rw,", mountPath))
462+
tPod1.VerifyExecInPodSucceed(f, specs.TesterContainerName, fmt.Sprintf("echo 'hello world rwx' > %v/data-rwx && grep 'hello world rwx' %v/data-rwx", mountPath, mountPath))
463+
464+
// 5. Verify Pod 2 (ROX) operations and access mode enforcement.
465+
ginkgo.By("Verifying ROX pod read operation and write restriction enforcement")
466+
tPod2.VerifyExecInPodSucceed(f, specs.TesterContainerName, fmt.Sprintf("mount | grep %v | grep ro,", mountPath))
467+
tPod2.VerifyExecInPodSucceed(f, specs.TesterContainerName, fmt.Sprintf("grep 'hello world rwx' %v/data-rwx", mountPath))
468+
tPod2.VerifyExecInPodFail(f, specs.TesterContainerName, fmt.Sprintf("echo 'hello world rox' > %v/data-rox", mountPath), 1)
469+
})
399470
}

0 commit comments

Comments
 (0)