From b382148915b3fc130423fbc38df6aa06f9eec251 Mon Sep 17 00:00:00 2001 From: Fabio Bertinatto Date: Thu, 19 Jan 2023 14:57:59 -0300 Subject: [PATCH] Trim out suffix added to backing file path of loopback device When a block device, say /dev/sdc, is unexpectedly disconnected from a node, the corresponding backing file path found at /sys/block/loop*/backing_file gets a "(deleted)" suffix. This patch trims that suffix out, allowing the Kubelet to unmount the volume correctly. --- .../volume_path_handler_linux.go | 10 ++- .../volume_path_handler_linux_test.go | 65 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 pkg/volume/util/volumepathhandler/volume_path_handler_linux_test.go 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) + } + }) + } +}