Skip to content

Commit 6f86459

Browse files
Allow multiple volume handles with different mount options
1 parent bd50eca commit 6f86459

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

pkg/csi_driver/utils.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ const (
6868
tokenServerSidecarMinVersion = "v1.12.2-gke.0" // #nosec G101
6969
)
7070

71+
var volumeIDRegEx = regexp.MustCompile(`:.*$`)
72+
7173
func NewVolumeCapabilityAccessMode(mode csi.VolumeCapability_AccessMode_Mode) *csi.VolumeCapability_AccessMode {
7274
return &csi.VolumeCapability_AccessMode{Mode: mode}
7375
}
@@ -272,13 +274,14 @@ func parseRequestArguments(req *csi.NodePublishVolumeRequest) (string, string, [
272274

273275
vc := req.GetVolumeContext()
274276
bucketName := req.GetVolumeId()
277+
275278
if vc[VolumeContextKeyEphemeral] == util.TrueStr {
276279
bucketName = vc[VolumeContextKeyBucketName]
277280
if len(bucketName) == 0 {
278281
return "", "", nil, false, false, fmt.Errorf("NodePublishVolume VolumeContext %q must be provided for ephemeral storage", VolumeContextKeyBucketName)
279282
}
280283
}
281-
284+
bucketName = parseVolumeID(bucketName)
282285
fuseMountOptions := []string{}
283286
if req.GetReadonly() {
284287
fuseMountOptions = joinMountOptions(fuseMountOptions, []string{"ro"})
@@ -302,6 +305,13 @@ func parseRequestArguments(req *csi.NodePublishVolumeRequest) (string, string, [
302305
return targetPath, bucketName, fuseMountOptions, skipCSIBucketAccessCheck, enableMetricsCollection, nil
303306
}
304307

308+
// The format allows customers to specify a fake volume handle for static provisioning,
309+
// enabling multiple PVs in the same pod to mount the same bucket. This prevents Kubelet from
310+
// skipping mounts of volumes with the same volume handle, which can cause the pod to be stuck in container creation.
311+
func parseVolumeID(bucketHandle string) string {
312+
return volumeIDRegEx.ReplaceAllString(bucketHandle, "")
313+
}
314+
305315
func putExitFile(pod *corev1.Pod, targetPath string) error {
306316
podIsTerminating := pod.DeletionTimestamp != nil
307317
podRestartPolicyIsNever := pod.Spec.RestartPolicy == corev1.RestartPolicyNever

pkg/csi_driver/utils_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,51 @@ const (
2929
TraceStr = "trace"
3030
)
3131

32+
func TestRemoveBucketSuffixIfPresentAndReturnVolumeId(t *testing.T) {
33+
t.Parallel()
34+
t.Run("removing bucket suffix if present and returning volume id", func(t *testing.T) {
35+
t.Parallel()
36+
testCases := []struct {
37+
name string
38+
bucketName string
39+
expectedValue string
40+
}{
41+
{
42+
name: "should return bucket name without suffix",
43+
bucketName: "bucket-name:1234567890123456789",
44+
expectedValue: "bucket-name",
45+
},
46+
{
47+
name: "should return bucket name without suffix",
48+
bucketName: "bucket-name:1234567890123456789@us-central1",
49+
expectedValue: "bucket-name",
50+
},
51+
{
52+
name: "should return bucket name without suffix",
53+
bucketName: "bucket-name@us-central1",
54+
expectedValue: "bucket-name@us-central1",
55+
},
56+
{
57+
name: "should return bucket name without suffix",
58+
bucketName: "bucket-name:1234567890123456789:12",
59+
expectedValue: "bucket-name",
60+
},
61+
{
62+
name: "should return bucket name without suffix",
63+
bucketName: "bucket-name",
64+
expectedValue: "bucket-name",
65+
},
66+
}
67+
68+
for _, tc := range testCases {
69+
t.Logf("test case: %s", tc.name)
70+
actual := parseVolumeID(tc.bucketName)
71+
if actual != tc.expectedValue {
72+
t.Errorf("Got value %v, but expected %v", actual, tc.expectedValue)
73+
}
74+
}
75+
})
76+
}
3277
func TestJoinMountOptions(t *testing.T) {
3378
t.Parallel()
3479
t.Run("joining mount options into one", func(t *testing.T) {

0 commit comments

Comments
 (0)