From fb6c78c90b4a8f436066ac4a528eb03f1102968e Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Wed, 8 May 2024 16:07:31 +0300 Subject: [PATCH 1/7] Use tmpfs noswap if supported use the tmpfs noswap option in order to mount memory-backed volumes if it's supported. Signed-off-by: Itamar Holder --- pkg/kubelet/util/swap/swap_util.go | 73 ++++++++++++++++++++++++++++++ pkg/volume/emptydir/empty_dir.go | 20 ++++++-- 2 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 pkg/kubelet/util/swap/swap_util.go diff --git a/pkg/kubelet/util/swap/swap_util.go b/pkg/kubelet/util/swap/swap_util.go new file mode 100644 index 0000000000000..025c36c35ff29 --- /dev/null +++ b/pkg/kubelet/util/swap/swap_util.go @@ -0,0 +1,73 @@ +/* +Copyright 2024 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 swap + +import ( + "os" + sysruntime "runtime" + "sync" + + "k8s.io/klog/v2" + "k8s.io/mount-utils" +) + +var ( + tmpfsNoswapOptionSupported bool + tmpfsNoswapOptionAvailabilityOnce sync.Once +) + +const TmpfsNoswapOption = "noswap" + +func IsTmpfsNoswapOptionSupported(mounter mount.Interface) bool { + isTmpfsNoswapOptionSupportedHelper := func() bool { + if sysruntime.GOOS == "windows" { + return false + } + + mountDir, err := os.MkdirTemp("", "tmpfs-noswap-test-") + if err != nil { + klog.InfoS("error creating dir to test if tmpfs noswap is enabled. Assuming not supported", "mount path", mountDir, "error", err) + return false + } + + defer func() { + err = os.RemoveAll(mountDir) + if err != nil { + klog.ErrorS(err, "error removing test tmpfs dir", "mount path", mountDir) + } + }() + + err = mounter.MountSensitiveWithoutSystemd("tmpfs", mountDir, "tmpfs", []string{TmpfsNoswapOption}, nil) + if err != nil { + klog.InfoS("error mounting tmpfs with the noswap option. Assuming not supported", "error", err) + return false + } + + err = mounter.Unmount(mountDir) + if err != nil { + klog.ErrorS(err, "error unmounting test tmpfs dir", "mount path", mountDir) + } + + return true + } + + tmpfsNoswapOptionAvailabilityOnce.Do(func() { + tmpfsNoswapOptionSupported = isTmpfsNoswapOptionSupportedHelper() + }) + + return tmpfsNoswapOptionSupported +} diff --git a/pkg/volume/emptydir/empty_dir.go b/pkg/volume/emptydir/empty_dir.go index d98a46197db71..d4f281a9cab1a 100644 --- a/pkg/volume/emptydir/empty_dir.go +++ b/pkg/volume/emptydir/empty_dir.go @@ -18,6 +18,7 @@ package emptydir import ( "fmt" + "k8s.io/kubernetes/pkg/kubelet/util/swap" "os" "path/filepath" @@ -327,11 +328,7 @@ func (ed *emptyDir) setupTmpfs(dir string) error { return nil } - var options []string - // Linux system default is 50% of capacity. - if ed.sizeLimit != nil && ed.sizeLimit.Value() > 0 { - options = []string{fmt.Sprintf("size=%d", ed.sizeLimit.Value())} - } + options := ed.generateTmpfsMountOptions(swap.IsTmpfsNoswapOptionSupported(ed.mounter)) klog.V(3).Infof("pod %v: mounting tmpfs for volume %v", ed.pod.UID, ed.volName) return ed.mounter.MountSensitiveWithoutSystemd("tmpfs", dir, "tmpfs", options, nil) @@ -555,3 +552,16 @@ func getVolumeSource(spec *volume.Spec) (*v1.EmptyDirVolumeSource, bool) { return volumeSource, readOnly } + +func (ed *emptyDir) generateTmpfsMountOptions(noswapSupported bool) (options []string) { + // Linux system default is 50% of capacity. + if ed.sizeLimit != nil && ed.sizeLimit.Value() > 0 { + options = append(options, fmt.Sprintf("size=%d", ed.sizeLimit.Value())) + } + + if noswapSupported { + options = append(options, swap.TmpfsNoswapOption) + } + + return options +} From 3b9b03935e65c5d716ed1fe78831d6bab95aa0ba Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Wed, 1 May 2024 13:59:47 +0300 Subject: [PATCH 2/7] unit test: Use tmpfs noswap if supported Signed-off-by: Itamar Holder --- pkg/volume/emptydir/empty_dir_test.go | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/pkg/volume/emptydir/empty_dir_test.go b/pkg/volume/emptydir/empty_dir_test.go index ff2c199cd7e7c..9aa92fe1120ea 100644 --- a/pkg/volume/emptydir/empty_dir_test.go +++ b/pkg/volume/emptydir/empty_dir_test.go @@ -21,8 +21,10 @@ package emptydir import ( "fmt" + "k8s.io/kubernetes/pkg/kubelet/util/swap" "os" "path/filepath" + "strings" "testing" v1 "k8s.io/api/core/v1" @@ -1061,3 +1063,57 @@ func TestCalculateEmptyDirMemorySize(t *testing.T) { }) } } + +func TestTmpfsMountOptions(t *testing.T) { + subQuantity := resource.MustParse("123Ki") + + doesStringArrayContainSubstring := func(strSlice []string, substr string) bool { + for _, s := range strSlice { + if strings.Contains(s, substr) { + return true + } + } + return false + } + + testCases := map[string]struct { + tmpfsNoswapSupported bool + sizeLimit resource.Quantity + }{ + "default bahavior": {}, + "tmpfs noswap is supported": { + tmpfsNoswapSupported: true, + }, + "size limit is non-zero": { + sizeLimit: subQuantity, + }, + "tmpfs noswap is supported and size limit is non-zero": { + tmpfsNoswapSupported: true, + sizeLimit: subQuantity, + }, + } + + for testCaseName, testCase := range testCases { + t.Run(testCaseName, func(t *testing.T) { + emptyDirObj := emptyDir{ + sizeLimit: &testCase.sizeLimit, + } + + options := emptyDirObj.generateTmpfsMountOptions(testCase.tmpfsNoswapSupported) + + if testCase.tmpfsNoswapSupported && !doesStringArrayContainSubstring(options, swap.TmpfsNoswapOption) { + t.Errorf("tmpfs noswap option is expected when supported. options: %v", options) + } + if !testCase.tmpfsNoswapSupported && doesStringArrayContainSubstring(options, swap.TmpfsNoswapOption) { + t.Errorf("tmpfs noswap option is not expected when unsupported. options: %v", options) + } + + if testCase.sizeLimit.IsZero() && doesStringArrayContainSubstring(options, "size=") { + t.Errorf("size is not expected when is zero. options: %v", options) + } + if expectedOption := fmt.Sprintf("size=%d", testCase.sizeLimit.Value()); !testCase.sizeLimit.IsZero() && !doesStringArrayContainSubstring(options, expectedOption) { + t.Errorf("size option is not expected when is zero. options: %v", options) + } + }) + } +} From 2a174d09fa5b4da37c9824f4f7150731a28bb715 Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Wed, 15 May 2024 10:47:45 +0300 Subject: [PATCH 3/7] If the kernel version is at least 6.4, assume tmpfs noswap is supported Signed-off-by: Itamar Holder --- pkg/kubelet/util/swap/swap_util.go | 12 ++++++++++++ pkg/util/kernel/constants.go | 2 ++ 2 files changed, 14 insertions(+) diff --git a/pkg/kubelet/util/swap/swap_util.go b/pkg/kubelet/util/swap/swap_util.go index 025c36c35ff29..62aaed45cfc04 100644 --- a/pkg/kubelet/util/swap/swap_util.go +++ b/pkg/kubelet/util/swap/swap_util.go @@ -21,7 +21,9 @@ import ( sysruntime "runtime" "sync" + "k8s.io/apimachinery/pkg/util/version" "k8s.io/klog/v2" + utilkernel "k8s.io/kubernetes/pkg/util/kernel" "k8s.io/mount-utils" ) @@ -38,6 +40,16 @@ func IsTmpfsNoswapOptionSupported(mounter mount.Interface) bool { return false } + kernelVersion, err := utilkernel.GetVersion() + if err != nil { + klog.ErrorS(err, "cannot determine kernel version, unable to determine is tmpfs noswap is supported") + return false + } + + if kernelVersion.AtLeast(version.MustParseGeneric(utilkernel.TmpfsNoswapSupportKernelVersion)) { + return true + } + mountDir, err := os.MkdirTemp("", "tmpfs-noswap-test-") if err != nil { klog.InfoS("error creating dir to test if tmpfs noswap is enabled. Assuming not supported", "mount path", mountDir, "error", err) diff --git a/pkg/util/kernel/constants.go b/pkg/util/kernel/constants.go index 86ba8f6106ca0..5354f84272e14 100644 --- a/pkg/util/kernel/constants.go +++ b/pkg/util/kernel/constants.go @@ -47,3 +47,5 @@ const IPVSConnReuseModeFixedKernelVersion = "5.9" // UserNamespacesSupportKernelVersion is the kernel version where idmap for tmpfs support was added // (ref: https://github.com/torvalds/linux/commit/05e6295f7b5e05f09e369a3eb2882ec5b40fff20) const UserNamespacesSupportKernelVersion = "6.3" + +const TmpfsNoswapSupportKernelVersion = "6.4" From e7df4d17c4730208b21d56400e7b7fa33e7df302 Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Wed, 15 May 2024 10:38:56 +0300 Subject: [PATCH 4/7] Add a isSwapOnAccordingToProcSwaps() function and swap utils unit tests Signed-off-by: Itamar Holder --- pkg/kubelet/util/swap/swap_util.go | 13 +++++ pkg/kubelet/util/swap/swap_util_test.go | 66 +++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 pkg/kubelet/util/swap/swap_util_test.go diff --git a/pkg/kubelet/util/swap/swap_util.go b/pkg/kubelet/util/swap/swap_util.go index 62aaed45cfc04..db7fdc9fcc909 100644 --- a/pkg/kubelet/util/swap/swap_util.go +++ b/pkg/kubelet/util/swap/swap_util.go @@ -17,8 +17,10 @@ limitations under the License. package swap import ( + "bytes" "os" sysruntime "runtime" + "strings" "sync" "k8s.io/apimachinery/pkg/util/version" @@ -83,3 +85,14 @@ func IsTmpfsNoswapOptionSupported(mounter mount.Interface) bool { return tmpfsNoswapOptionSupported } + +// gets /proc/swaps's content as an input, returns true if swap is enabled. +func isSwapOnAccordingToProcSwaps(procSwapsContent []byte) bool { + procSwapsContent = bytes.TrimSpace(procSwapsContent) // extra trailing \n + procSwapsStr := string(procSwapsContent) + procSwapsLines := strings.Split(procSwapsStr, "\n") + + // If there is more than one line (table headers) in /proc/swaps then swap is enabled + klog.InfoS("Swap is on", "/proc/swaps contents", procSwapsStr) + return len(procSwapsLines) > 1 +} diff --git a/pkg/kubelet/util/swap/swap_util_test.go b/pkg/kubelet/util/swap/swap_util_test.go new file mode 100644 index 0000000000000..611c464b70fdd --- /dev/null +++ b/pkg/kubelet/util/swap/swap_util_test.go @@ -0,0 +1,66 @@ +/* +Copyright 2024 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 swap + +import "testing" + +func TestIsSwapEnabled(t *testing.T) { + testCases := []struct { + name string + procSwapsContent string + expectedEnabled bool + }{ + { + name: "empty", + procSwapsContent: "", + expectedEnabled: false, + }, + { + name: "with swap enabled, one partition", + procSwapsContent: ` +Filename Type Size Used Priority +/dev/dm-1 partition 33554428 0 -2 +`, + expectedEnabled: true, + }, + { + name: "with swap enabled, 2 partitions", + procSwapsContent: ` +Filename Type Size Used Priority +/dev/dm-1 partition 33554428 0 -2 +/dev/zram0 partition 8388604 0 100 +`, + expectedEnabled: true, + }, + { + name: "empty lines", + procSwapsContent: ` + +`, + expectedEnabled: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + isEnabled := isSwapOnAccordingToProcSwaps([]byte(tc.procSwapsContent)) + if isEnabled != tc.expectedEnabled { + t.Errorf("expected %v, got %v", tc.expectedEnabled, isEnabled) + } + }) + } +} From 29535c0463d7bc44900b479df5e08c5465604584 Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Wed, 8 May 2024 17:33:47 +0300 Subject: [PATCH 5/7] Warn of swap is enabled on the OS and tmpfs noswap is not supported When --fail-swap-on=false kubelet CLI argument is provided, but tmpfs noswap is not supported by the kernel, warn about the risks of memory-backed volumes being swapped into disk Signed-off-by: Itamar Holder --- pkg/kubelet/cm/container_manager_linux.go | 32 +++++++++------------- pkg/kubelet/util/swap/swap_util.go | 33 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/pkg/kubelet/cm/container_manager_linux.go b/pkg/kubelet/cm/container_manager_linux.go index fb666a8333fb7..b8c541207762c 100644 --- a/pkg/kubelet/cm/container_manager_linux.go +++ b/pkg/kubelet/cm/container_manager_linux.go @@ -20,12 +20,10 @@ limitations under the License. package cm import ( - "bytes" "context" "fmt" "os" "path" - "strings" "sync" "time" @@ -64,6 +62,7 @@ import ( "k8s.io/kubernetes/pkg/kubelet/stats/pidlimit" "k8s.io/kubernetes/pkg/kubelet/status" "k8s.io/kubernetes/pkg/kubelet/userns/inuserns" + "k8s.io/kubernetes/pkg/kubelet/util/swap" schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework" "k8s.io/kubernetes/pkg/util/oom" ) @@ -204,25 +203,18 @@ func NewContainerManager(mountUtil mount.Interface, cadvisorInterface cadvisor.I return nil, fmt.Errorf("failed to get mounted cgroup subsystems: %v", err) } - if failSwapOn { - // Check whether swap is enabled. The Kubelet does not support running with swap enabled. - swapFile := "/proc/swaps" - swapData, err := os.ReadFile(swapFile) - if err != nil { - if os.IsNotExist(err) { - klog.InfoS("File does not exist, assuming that swap is disabled", "path", swapFile) - } else { - return nil, err - } - } else { - swapData = bytes.TrimSpace(swapData) // extra trailing \n - swapLines := strings.Split(string(swapData), "\n") + isSwapOn, err := swap.IsSwapOn() + if err != nil { + return nil, fmt.Errorf("failed to determine if swap is on: %w", err) + } - // If there is more than one line (table headers) in /proc/swaps, swap is enabled and we should - // error out unless --fail-swap-on is set to false. - if len(swapLines) > 1 { - return nil, fmt.Errorf("running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false. /proc/swaps contained: %v", swapLines) - } + if isSwapOn { + if failSwapOn { + return nil, fmt.Errorf("running with swap on is not supported, please disable swap or set --fail-swap-on flag to false") + } + + if !swap.IsTmpfsNoswapOptionSupported(mountUtil) { + klog.InfoS("tmpfs noswap option is not supported, hence memory-backed volumes (e.g. secrets, emptyDirs) might be swapped to disk") } } diff --git a/pkg/kubelet/util/swap/swap_util.go b/pkg/kubelet/util/swap/swap_util.go index db7fdc9fcc909..626e30ebd01f7 100644 --- a/pkg/kubelet/util/swap/swap_util.go +++ b/pkg/kubelet/util/swap/swap_util.go @@ -32,6 +32,9 @@ import ( var ( tmpfsNoswapOptionSupported bool tmpfsNoswapOptionAvailabilityOnce sync.Once + swapOn bool + swapOnErr error + swapOnOnce sync.Once ) const TmpfsNoswapOption = "noswap" @@ -96,3 +99,33 @@ func isSwapOnAccordingToProcSwaps(procSwapsContent []byte) bool { klog.InfoS("Swap is on", "/proc/swaps contents", procSwapsStr) return len(procSwapsLines) > 1 } + +// IsSwapOn detects whether swap in enabled on the system by inspecting +// /proc/swaps. If the file does not exist, an os.NotFound error will be returned. +// If running on windows, swap is assumed to always be false. +func IsSwapOn() (bool, error) { + isSwapOnHelper := func() (bool, error) { + if sysruntime.GOOS == "windows" { + return false, nil + } + + const swapFilePath = "/proc/swaps" + procSwapsContent, err := os.ReadFile(swapFilePath) + if err != nil { + if os.IsNotExist(err) { + klog.InfoS("File does not exist, assuming that swap is disabled", "path", swapFilePath) + return false, nil + } + + return false, err + } + + return isSwapOnAccordingToProcSwaps(procSwapsContent), nil + } + + swapOnOnce.Do(func() { + swapOn, swapOnErr = isSwapOnHelper() + }) + + return swapOn, swapOnErr +} From 74f29880bdd2f2f13a541d14479fd8d306ce87af Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Wed, 15 May 2024 10:24:15 +0300 Subject: [PATCH 6/7] Replace log entry by a warning event Signed-off-by: Itamar Holder --- pkg/kubelet/cm/container_manager_linux.go | 7 ++++++- pkg/kubelet/cm/node_container_manager_linux.go | 17 +++++++++++------ pkg/kubelet/events/event.go | 1 + 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/pkg/kubelet/cm/container_manager_linux.go b/pkg/kubelet/cm/container_manager_linux.go index b8c541207762c..dd94b99daae9d 100644 --- a/pkg/kubelet/cm/container_manager_linux.go +++ b/pkg/kubelet/cm/container_manager_linux.go @@ -57,6 +57,7 @@ import ( cmutil "k8s.io/kubernetes/pkg/kubelet/cm/util" "k8s.io/kubernetes/pkg/kubelet/config" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" + "k8s.io/kubernetes/pkg/kubelet/events" "k8s.io/kubernetes/pkg/kubelet/lifecycle" "k8s.io/kubernetes/pkg/kubelet/pluginmanager/cache" "k8s.io/kubernetes/pkg/kubelet/stats/pidlimit" @@ -214,7 +215,11 @@ func NewContainerManager(mountUtil mount.Interface, cadvisorInterface cadvisor.I } if !swap.IsTmpfsNoswapOptionSupported(mountUtil) { - klog.InfoS("tmpfs noswap option is not supported, hence memory-backed volumes (e.g. secrets, emptyDirs) might be swapped to disk") + nodeRef := nodeRefFromNode(string(nodeConfig.NodeName)) + recorder.Event(nodeRef, v1.EventTypeWarning, events.PossibleMemoryBackedVolumesOnDisk, + "The tmpfs noswap option is not supported. Memory-backed volumes (e.g. secrets, emptyDirs, etc.) "+ + "might be swapped to disk and should no longer be considered secure.", + ) } } diff --git a/pkg/kubelet/cm/node_container_manager_linux.go b/pkg/kubelet/cm/node_container_manager_linux.go index c8baf64186087..c9f013ad663d3 100644 --- a/pkg/kubelet/cm/node_container_manager_linux.go +++ b/pkg/kubelet/cm/node_container_manager_linux.go @@ -84,12 +84,7 @@ func (cm *containerManagerImpl) enforceNodeAllocatableCgroups() error { } // Using ObjectReference for events as the node maybe not cached; refer to #42701 for detail. - nodeRef := &v1.ObjectReference{ - Kind: "Node", - Name: cm.nodeInfo.Name, - UID: types.UID(cm.nodeInfo.Name), - Namespace: "", - } + nodeRef := nodeRefFromNode(cm.nodeInfo.Name) // If Node Allocatable is enforced on a node that has not been drained or is updated on an existing node to a lower value, // existing memory usage across pods might be higher than current Node Allocatable Memory Limits. @@ -265,3 +260,13 @@ func (cm *containerManagerImpl) validateNodeAllocatable() error { } return nil } + +// Using ObjectReference for events as the node maybe not cached; refer to #42701 for detail. +func nodeRefFromNode(nodeName string) *v1.ObjectReference { + return &v1.ObjectReference{ + Kind: "Node", + Name: nodeName, + UID: types.UID(nodeName), + Namespace: "", + } +} diff --git a/pkg/kubelet/events/event.go b/pkg/kubelet/events/event.go index d08253989ae81..6c56a0234d78d 100644 --- a/pkg/kubelet/events/event.go +++ b/pkg/kubelet/events/event.go @@ -75,6 +75,7 @@ const ( FailedStatusPodSandBox = "FailedPodSandBoxStatus" FailedMountOnFilesystemMismatch = "FailedMountOnFilesystemMismatch" FailedPrepareDynamicResources = "FailedPrepareDynamicResources" + PossibleMemoryBackedVolumesOnDisk = "PossibleMemoryBackedVolumesOnDisk" ) // Image manager event reason list From a6b971f14b8233f63b1a4e3270dd8f0c5e600d16 Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Tue, 21 May 2024 12:54:23 +0300 Subject: [PATCH 7/7] Use kubelet owned directories for mounting rather than /tmp Signed-off-by: Itamar Holder --- pkg/kubelet/cm/container_manager_linux.go | 2 +- pkg/kubelet/util/swap/swap_util.go | 21 +++++++++++++-------- pkg/volume/emptydir/empty_dir.go | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/pkg/kubelet/cm/container_manager_linux.go b/pkg/kubelet/cm/container_manager_linux.go index dd94b99daae9d..83c07d68f8c47 100644 --- a/pkg/kubelet/cm/container_manager_linux.go +++ b/pkg/kubelet/cm/container_manager_linux.go @@ -214,7 +214,7 @@ func NewContainerManager(mountUtil mount.Interface, cadvisorInterface cadvisor.I return nil, fmt.Errorf("running with swap on is not supported, please disable swap or set --fail-swap-on flag to false") } - if !swap.IsTmpfsNoswapOptionSupported(mountUtil) { + if !swap.IsTmpfsNoswapOptionSupported(mountUtil, nodeConfig.KubeletRootDir) { nodeRef := nodeRefFromNode(string(nodeConfig.NodeName)) recorder.Event(nodeRef, v1.EventTypeWarning, events.PossibleMemoryBackedVolumesOnDisk, "The tmpfs noswap option is not supported. Memory-backed volumes (e.g. secrets, emptyDirs, etc.) "+ diff --git a/pkg/kubelet/util/swap/swap_util.go b/pkg/kubelet/util/swap/swap_util.go index 626e30ebd01f7..2160820b6f19a 100644 --- a/pkg/kubelet/util/swap/swap_util.go +++ b/pkg/kubelet/util/swap/swap_util.go @@ -18,6 +18,7 @@ package swap import ( "bytes" + "errors" "os" sysruntime "runtime" "strings" @@ -39,7 +40,7 @@ var ( const TmpfsNoswapOption = "noswap" -func IsTmpfsNoswapOptionSupported(mounter mount.Interface) bool { +func IsTmpfsNoswapOptionSupported(mounter mount.Interface, mountPath string) bool { isTmpfsNoswapOptionSupportedHelper := func() bool { if sysruntime.GOOS == "windows" { return false @@ -55,28 +56,32 @@ func IsTmpfsNoswapOptionSupported(mounter mount.Interface) bool { return true } - mountDir, err := os.MkdirTemp("", "tmpfs-noswap-test-") + if mountPath == "" { + klog.ErrorS(errors.New("mount path is empty, falling back to /tmp"), "") + } + + mountPath, err = os.MkdirTemp(mountPath, "tmpfs-noswap-test-") if err != nil { - klog.InfoS("error creating dir to test if tmpfs noswap is enabled. Assuming not supported", "mount path", mountDir, "error", err) + klog.InfoS("error creating dir to test if tmpfs noswap is enabled. Assuming not supported", "mount path", mountPath, "error", err) return false } defer func() { - err = os.RemoveAll(mountDir) + err = os.RemoveAll(mountPath) if err != nil { - klog.ErrorS(err, "error removing test tmpfs dir", "mount path", mountDir) + klog.ErrorS(err, "error removing test tmpfs dir", "mount path", mountPath) } }() - err = mounter.MountSensitiveWithoutSystemd("tmpfs", mountDir, "tmpfs", []string{TmpfsNoswapOption}, nil) + err = mounter.MountSensitiveWithoutSystemd("tmpfs", mountPath, "tmpfs", []string{TmpfsNoswapOption}, nil) if err != nil { klog.InfoS("error mounting tmpfs with the noswap option. Assuming not supported", "error", err) return false } - err = mounter.Unmount(mountDir) + err = mounter.Unmount(mountPath) if err != nil { - klog.ErrorS(err, "error unmounting test tmpfs dir", "mount path", mountDir) + klog.ErrorS(err, "error unmounting test tmpfs dir", "mount path", mountPath) } return true diff --git a/pkg/volume/emptydir/empty_dir.go b/pkg/volume/emptydir/empty_dir.go index d4f281a9cab1a..d4f942139540e 100644 --- a/pkg/volume/emptydir/empty_dir.go +++ b/pkg/volume/emptydir/empty_dir.go @@ -328,7 +328,7 @@ func (ed *emptyDir) setupTmpfs(dir string) error { return nil } - options := ed.generateTmpfsMountOptions(swap.IsTmpfsNoswapOptionSupported(ed.mounter)) + options := ed.generateTmpfsMountOptions(swap.IsTmpfsNoswapOptionSupported(ed.mounter, ed.plugin.host.GetPluginDir(emptyDirPluginName))) klog.V(3).Infof("pod %v: mounting tmpfs for volume %v", ed.pod.UID, ed.volName) return ed.mounter.MountSensitiveWithoutSystemd("tmpfs", dir, "tmpfs", options, nil)