diff --git a/pkg/volume/util/volumepathhandler/volume_path_handler_linux.go b/pkg/volume/util/volumepathhandler/volume_path_handler_linux.go index aae1b39acb1..2e55df4cca8 100644 --- a/pkg/volume/util/volumepathhandler/volume_path_handler_linux.go +++ b/pkg/volume/util/volumepathhandler/volume_path_handler_linux.go @@ -139,7 +139,7 @@ func getLoopDeviceFromSysfs(path string) (string, error) { } // Return the first match. - backingFilePath := strings.TrimSpace(string(data)) + backingFilePath := cleanBackingFilePath(string(data)) if backingFilePath == path || backingFilePath == realPath { return fmt.Sprintf("/dev/%s", filepath.Base(device)), nil } @@ -148,6 +148,14 @@ func getLoopDeviceFromSysfs(path string) (string, error) { return "", errors.New(ErrDeviceNotFound) } +// cleanPath remove any trailing substrings that are not part of the backing file path. +func cleanBackingFilePath(path string) string { + // If the block device was deleted, the path will contain a "(deleted)" suffix + path = strings.TrimSpace(path) + path = strings.TrimSuffix(path, "(deleted)") + return strings.TrimSpace(path) +} + // FindGlobalMapPathUUIDFromPod finds {pod uuid} bind mount under globalMapPath // corresponding to map path symlink, and then return global map path with pod uuid. // (See pkg/volume/volume.go for details on a global map path and a pod device map path.) diff --git a/pkg/volume/util/volumepathhandler/volume_path_handler_linux_test.go b/pkg/volume/util/volumepathhandler/volume_path_handler_linux_test.go new file mode 100644 index 00000000000..bc695e7593f --- /dev/null +++ b/pkg/volume/util/volumepathhandler/volume_path_handler_linux_test.go @@ -0,0 +1,65 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package volumepathhandler + +import ( + "fmt" + "testing" +) + +func pathWithSuffix(suffix string) string { + return fmt.Sprintf("%s%s", "/var/lib/kubelet/plugins/kubernetes.io/csi/volumeDevices/pvc-1d205234-06cd-4fe4-a7ea-0e8f3e2faf5f/dev/e196ebd3-2ab1-4185-bed4-b997ba38d1dc", suffix) +} + +func TestCleanBackingFilePath(t *testing.T) { + const defaultPath = "/var/lib/kubelet/plugins/kubernetes.io/csi/volumeDevices/pvc-1d205234-06cd-4fe4-a7ea-0e8f3e2faf5f/dev/e196ebd3-2ab1-4185-bed4-b997ba38d1dc" + testCases := []struct { + name string + input string + expectedOuput string + }{ + { + name: "regular path", + input: defaultPath, + expectedOuput: defaultPath, + }, + { + name: "path is suffixed with whitespaces", + input: fmt.Sprintf("%s\r\t\n ", defaultPath), + expectedOuput: defaultPath, + }, + { + name: "path is suffixed with \"(deleted)\"", + input: pathWithSuffix("(deleted)"), + expectedOuput: defaultPath, + }, + { + name: "path is suffixed with \"(deleted)\" and whitespaces", + input: pathWithSuffix(" (deleted)\t"), + expectedOuput: defaultPath, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + output := cleanBackingFilePath(tc.input) + if output != tc.expectedOuput { + t.Fatalf("expected %q, got %q", tc.expectedOuput, output) + } + }) + } +}