From e575e60ea42ad58bfe124f44e719e4b7cc1ab2e6 Mon Sep 17 00:00:00 2001 From: Jan Safranek Date: Thu, 3 Nov 2022 17:40:16 +0100 Subject: [PATCH] Reconstruct SELinux mount option When reconstructing volumes from disk after kubelet restart, reconstruct also context=XYZ mount option and add it to the ActualStateOfWorld. --- .../volumemanager/reconciler/reconstruct.go | 1 - .../reconciler/reconstruct_common.go | 11 +++- .../reconciler/reconstruct_new.go | 7 ++- pkg/volume/csi/csi_mounter_test.go | 3 +- pkg/volume/csi/csi_plugin.go | 17 +++--- pkg/volume/csi/csi_plugin_test.go | 54 ++++++++++++++---- pkg/volume/fc/fc.go | 17 +++++- pkg/volume/iscsi/iscsi.go | 17 +++++- pkg/volume/plugins.go | 4 ++ pkg/volume/rbd/rbd.go | 12 +++- pkg/volume/util/hostutil/fake_hostutil.go | 6 ++ pkg/volume/util/hostutil/hostutil.go | 3 + pkg/volume/util/hostutil/hostutil_linux.go | 32 +++++++++++ .../util/hostutil/hostutil_linux_test.go | 57 +++++++++++++++++++ .../util/hostutil/hostutil_unsupported.go | 6 ++ pkg/volume/util/hostutil/hostutil_windows.go | 6 ++ 16 files changed, 225 insertions(+), 28 deletions(-) diff --git a/pkg/kubelet/volumemanager/reconciler/reconstruct.go b/pkg/kubelet/volumemanager/reconciler/reconstruct.go index 87af24a964f..f245f6c2088 100644 --- a/pkg/kubelet/volumemanager/reconciler/reconstruct.go +++ b/pkg/kubelet/volumemanager/reconciler/reconstruct.go @@ -160,7 +160,6 @@ func (rc *reconciler) updateStates(volumesNeedUpdate map[v1.UniqueVolumeName]*gl klog.ErrorS(err, "Could not find device mount path for volume", "volumeName", gvl.volumeName) continue } - // TODO(jsafrane): add reconstructed SELinux context err = rc.actualStateOfWorld.MarkDeviceAsMounted(gvl.volumeName, gvl.devicePath, deviceMountPath, "") if err != nil { klog.ErrorS(err, "Could not mark device is mounted to actual state of world", "volume", gvl.volumeName) diff --git a/pkg/kubelet/volumemanager/reconciler/reconstruct_common.go b/pkg/kubelet/volumemanager/reconciler/reconstruct_common.go index e5a33aa735a..30088cec284 100644 --- a/pkg/kubelet/volumemanager/reconciler/reconstruct_common.go +++ b/pkg/kubelet/volumemanager/reconciler/reconstruct_common.go @@ -56,6 +56,7 @@ type reconstructedVolume struct { mounter volumepkg.Mounter deviceMounter volumepkg.DeviceMounter blockVolumeMapper volumepkg.BlockVolumeMapper + seLinuxMountContext string } // globalVolumeInfo stores reconstructed volume information @@ -211,6 +212,9 @@ func (rc *reconciler) reconstructVolume(volume podVolume) (*reconstructedVolume, return nil, err } volumeSpec := reconstructed.Spec + if volumeSpec == nil { + return nil, fmt.Errorf("failed to reconstruct volume for plugin %q (spec.Name: %q) pod %q (UID: %q): got nil", volume.pluginName, volume.volumeSpecName, volume.podName, pod.UID) + } // We have to find the plugins by volume spec (NOT by plugin name) here // in order to correctly reconstruct ephemeral volume types. @@ -312,9 +316,10 @@ func (rc *reconciler) reconstructVolume(volume podVolume) (*reconstructedVolume, volumeGidValue: "", // devicePath is updated during updateStates() by checking node status's VolumesAttached data. // TODO: get device path directly from the volume mount path. - devicePath: "", - mounter: volumeMounter, - blockVolumeMapper: volumeMapper, + devicePath: "", + mounter: volumeMounter, + blockVolumeMapper: volumeMapper, + seLinuxMountContext: reconstructed.SELinuxMountContext, } return reconstructedVolume, nil } diff --git a/pkg/kubelet/volumemanager/reconciler/reconstruct_new.go b/pkg/kubelet/volumemanager/reconciler/reconstruct_new.go index e0e20a65d1b..80acf7eaa09 100644 --- a/pkg/kubelet/volumemanager/reconciler/reconstruct_new.go +++ b/pkg/kubelet/volumemanager/reconciler/reconstruct_new.go @@ -112,6 +112,7 @@ func (rc *reconciler) updateStatesNew(reconstructedVolumes map[v1.UniqueVolumeNa klog.ErrorS(err, "Could not add volume information to actual state of world", "volumeName", gvl.volumeName) continue } + var seLinuxMountContext string for _, volume := range gvl.podVolumes { markVolumeOpts := operationexecutor.MarkVolumeOpts{ PodName: volume.podName, @@ -123,6 +124,7 @@ func (rc *reconciler) updateStatesNew(reconstructedVolumes map[v1.UniqueVolumeNa VolumeGidVolume: volume.volumeGidValue, VolumeSpec: volume.volumeSpec, VolumeMountState: operationexecutor.VolumeMountUncertain, + SELinuxMountContext: volume.seLinuxMountContext, } _, err = rc.actualStateOfWorld.CheckAndMarkVolumeAsUncertainViaReconstruction(markVolumeOpts) @@ -130,7 +132,8 @@ func (rc *reconciler) updateStatesNew(reconstructedVolumes map[v1.UniqueVolumeNa klog.ErrorS(err, "Could not add pod to volume information to actual state of world", "pod", klog.KObj(volume.pod)) continue } - klog.V(2).InfoS("Volume is marked as uncertain and added into the actual state", "pod", klog.KObj(volume.pod), "podName", volume.podName, "volumeName", volume.volumeName) + seLinuxMountContext = volume.seLinuxMountContext + klog.V(2).InfoS("Volume is marked as uncertain and added into the actual state", "pod", klog.KObj(volume.pod), "podName", volume.podName, "volumeName", volume.volumeName, "seLinuxMountContext", volume.seLinuxMountContext) } // If the volume has device to mount, we mark its device as uncertain. if gvl.deviceMounter != nil || gvl.blockVolumeMapper != nil { @@ -139,7 +142,7 @@ func (rc *reconciler) updateStatesNew(reconstructedVolumes map[v1.UniqueVolumeNa klog.ErrorS(err, "Could not find device mount path for volume", "volumeName", gvl.volumeName) continue } - err = rc.actualStateOfWorld.MarkDeviceAsUncertain(gvl.volumeName, gvl.devicePath, deviceMountPath, "") + err = rc.actualStateOfWorld.MarkDeviceAsUncertain(gvl.volumeName, gvl.devicePath, deviceMountPath, seLinuxMountContext) if err != nil { klog.ErrorS(err, "Could not mark device is uncertain to actual state of world", "volumeName", gvl.volumeName, "deviceMountPath", deviceMountPath) continue diff --git a/pkg/volume/csi/csi_mounter_test.go b/pkg/volume/csi/csi_mounter_test.go index f0e06511d77..c1c487f2d95 100644 --- a/pkg/volume/csi/csi_mounter_test.go +++ b/pkg/volume/csi/csi_mounter_test.go @@ -60,7 +60,7 @@ var ( testAccount = "test-service-account" ) -func prepareVolumeInfoFile(mountPath string, plug *csiPlugin, specVolumeName, volumeID, driverName, lifecycleMode string) error { +func prepareVolumeInfoFile(mountPath string, plug *csiPlugin, specVolumeName, volumeID, driverName, lifecycleMode, seLinuxMountContext string) error { nodeName := string(plug.host.GetNodeName()) volData := map[string]string{ volDataKey.specVolID: specVolumeName, @@ -69,6 +69,7 @@ func prepareVolumeInfoFile(mountPath string, plug *csiPlugin, specVolumeName, vo volDataKey.nodeName: nodeName, volDataKey.attachmentID: getAttachmentName(volumeID, driverName, nodeName), volDataKey.volumeLifecycleMode: lifecycleMode, + volDataKey.seLinuxMountContext: seLinuxMountContext, } if err := os.MkdirAll(mountPath, 0755); err != nil { return fmt.Errorf("failed to create dir for volume info file: %s", err) diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go index c4bb214e6cf..e3c1076ec3a 100644 --- a/pkg/volume/csi/csi_plugin.go +++ b/pkg/volume/csi/csi_plugin.go @@ -455,22 +455,23 @@ func (p *csiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.Re if err != nil { return volume.ReconstructedVolume{}, errors.New(log("plugin.ConstructVolumeSpec failed loading volume data using [%s]: %v", mountPath, err)) } - klog.V(4).Info(log("plugin.ConstructVolumeSpec extracted [%#v]", volData)) - var spec *volume.Spec + var ret volume.ReconstructedVolume + if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { + ret.SELinuxMountContext = volData[volDataKey.seLinuxMountContext] + } + // If mode is VolumeLifecycleEphemeral, use constructVolSourceSpec // to construct volume source spec. If mode is VolumeLifecyclePersistent, // use constructPVSourceSpec to construct volume construct pv source spec. if storage.VolumeLifecycleMode(volData[volDataKey.volumeLifecycleMode]) == storage.VolumeLifecycleEphemeral { - spec = p.constructVolSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName]) - return volume.ReconstructedVolume{Spec: spec}, nil + ret.Spec = p.constructVolSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName]) + return ret, nil } - spec = p.constructPVSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName], volData[volDataKey.volHandle]) - return volume.ReconstructedVolume{ - Spec: spec, - }, nil + ret.Spec = p.constructPVSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName], volData[volDataKey.volHandle]) + return ret, nil } // constructVolSourceSpec constructs volume.Spec with CSIVolumeSource diff --git a/pkg/volume/csi/csi_plugin_test.go b/pkg/volume/csi/csi_plugin_test.go index e874eaba7b8..4a76d734195 100644 --- a/pkg/volume/csi/csi_plugin_test.go +++ b/pkg/volume/csi/csi_plugin_test.go @@ -29,9 +29,12 @@ import ( meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" + utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/informers" fakeclient "k8s.io/client-go/kubernetes/fake" utiltesting "k8s.io/client-go/util/testing" + featuregatetesting "k8s.io/component-base/featuregate/testing" + "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" volumetest "k8s.io/kubernetes/pkg/volume/testing" ) @@ -316,16 +319,20 @@ func TestPluginConstructVolumeSpec(t *testing.T) { defer os.RemoveAll(tmpDir) testCases := []struct { - name string - originSpec *volume.Spec - specVolID string - volHandle string - podUID types.UID + name string + seLinuxMountEnabled bool + originSpec *volume.Spec + originSELinuxMountContext string + specVolID string + volHandle string + expectedSELinuxContext string + podUID types.UID }{ { - name: "construct spec1 from original persistent spec", - specVolID: "test.vol.id", - volHandle: "testvol-handle1", + name: "construct spec1 from original persistent spec", + specVolID: "test.vol.id", + volHandle: "testvol-handle1", + originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("test.vol.id", 20, testDriver, "testvol-handle1"), true), podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), }, @@ -336,12 +343,35 @@ func TestPluginConstructVolumeSpec(t *testing.T) { originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("spec2", 20, testDriver, "handle2"), true), podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), }, + { + name: "construct SELinux context from original persistent spec when the feature is enabled", + seLinuxMountEnabled: true, + specVolID: "spec3", + volHandle: "handle3", + originSELinuxMountContext: "system_u:object_r:container_file_t:s0:c314,c894", + originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("spec3", 20, testDriver, "handle3"), true), + expectedSELinuxContext: "system_u:object_r:container_file_t:s0:c314,c894", + podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), + }, + { + name: "construct empty SELinux from original persistent spec when the feature is disabled", + seLinuxMountEnabled: false, + specVolID: "spec4", + volHandle: "handle4", + originSELinuxMountContext: "system_u:object_r:container_file_t:s0:c314,c894", + originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("spec4", 20, testDriver, "handle4"), true), + expectedSELinuxContext: "", // The context is cleared when the feature gate is off + podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), + }, } registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t) for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tc.seLinuxMountEnabled)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, tc.seLinuxMountEnabled)() + mounter, err := plug.NewMounter( tc.originSpec, &api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}}, @@ -356,7 +386,7 @@ func TestPluginConstructVolumeSpec(t *testing.T) { csiMounter := mounter.(*csiMountMgr) mountPath := filepath.Dir(csiMounter.GetPath()) - err = prepareVolumeInfoFile(mountPath, plug, tc.originSpec.Name(), csiMounter.volumeID, testDriver, string(csiMounter.volumeLifecycleMode)) + err = prepareVolumeInfoFile(mountPath, plug, tc.originSpec.Name(), csiMounter.volumeID, testDriver, string(csiMounter.volumeLifecycleMode), tc.originSELinuxMountContext) if err != nil { t.Fatalf("failed to save fake volume info file: %s", err) } @@ -395,6 +425,10 @@ func TestPluginConstructVolumeSpec(t *testing.T) { if rec.Spec.Name() != tc.specVolID { t.Errorf("Unexpected spec name constructed %s", rec.Spec.Name()) } + + if rec.SELinuxMountContext != tc.expectedSELinuxContext { + t.Errorf("Expected SELinux context %q, got %q", tc.expectedSELinuxContext, rec.SELinuxMountContext) + } }) } } @@ -490,7 +524,7 @@ func TestPluginConstructVolumeSpecWithInline(t *testing.T) { csiMounter := mounter.(*csiMountMgr) mountPath := filepath.Dir(csiMounter.GetPath()) - err = prepareVolumeInfoFile(mountPath, plug, tc.originSpec.Name(), csiMounter.volumeID, testDriver, string(csiMounter.volumeLifecycleMode)) + err = prepareVolumeInfoFile(mountPath, plug, tc.originSpec.Name(), csiMounter.volumeID, testDriver, string(csiMounter.volumeLifecycleMode), "") if err != nil { t.Fatalf("failed to save fake volume info file: %s", err) } diff --git a/pkg/volume/fc/fc.go b/pkg/volume/fc/fc.go index a29e85a1d9d..f38d590f756 100644 --- a/pkg/volume/fc/fc.go +++ b/pkg/volume/fc/fc.go @@ -283,10 +283,25 @@ func (plugin *fcPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volum FC: &v1.FCVolumeSource{WWIDs: wwids, Lun: &lun, TargetWWNs: wwns}, }, } + + var mountContext string + if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { + kvh, ok := plugin.host.(volume.KubeletVolumeHost) + if !ok { + return volume.ReconstructedVolume{}, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface") + } + hu := kvh.GetHostUtil() + mountContext, err = hu.GetSELinuxMountContext(mountPath) + if err != nil { + return volume.ReconstructedVolume{}, err + } + } + klog.V(5).Infof("ConstructVolumeSpec: TargetWWNs: %v, Lun: %v, WWIDs: %v", fcVolume.VolumeSource.FC.TargetWWNs, *fcVolume.VolumeSource.FC.Lun, fcVolume.VolumeSource.FC.WWIDs) return volume.ReconstructedVolume{ - Spec: volume.NewSpecFromVolume(fcVolume), + Spec: volume.NewSpecFromVolume(fcVolume), + SELinuxMountContext: mountContext, }, nil } diff --git a/pkg/volume/iscsi/iscsi.go b/pkg/volume/iscsi/iscsi.go index 791527a3c98..fadce442a2c 100644 --- a/pkg/volume/iscsi/iscsi.go +++ b/pkg/volume/iscsi/iscsi.go @@ -279,8 +279,23 @@ func (plugin *iscsiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (vo }, }, } + + var mountContext string + if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { + kvh, ok := plugin.host.(volume.KubeletVolumeHost) + if !ok { + return volume.ReconstructedVolume{}, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface") + } + hu := kvh.GetHostUtil() + mountContext, err = hu.GetSELinuxMountContext(mountPath) + if err != nil { + return volume.ReconstructedVolume{}, err + } + } + return volume.ReconstructedVolume{ - Spec: volume.NewSpecFromVolume(iscsiVolume), + Spec: volume.NewSpecFromVolume(iscsiVolume), + SELinuxMountContext: mountContext, }, nil } diff --git a/pkg/volume/plugins.go b/pkg/volume/plugins.go index d469a89b617..c0ec12f0c0f 100644 --- a/pkg/volume/plugins.go +++ b/pkg/volume/plugins.go @@ -573,7 +573,11 @@ type VolumeConfig struct { // ReconstructedVolume contains information about a volume reconstructed by // ConstructVolumeSpec(). type ReconstructedVolume struct { + // Spec is the volume spec of a mounted volume Spec *Spec + // SELinuxMountContext is value of -o context=XYZ mount option. + // If empty, no such mount option is used. + SELinuxMountContext string } // NewSpecFromVolume creates an Spec from an v1.Volume diff --git a/pkg/volume/rbd/rbd.go b/pkg/volume/rbd/rbd.go index 93747df81a5..5a9fe52a795 100644 --- a/pkg/volume/rbd/rbd.go +++ b/pkg/volume/rbd/rbd.go @@ -430,8 +430,18 @@ func (plugin *rbdPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volu }, }, } + + var mountContext string + if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { + mountContext, err = hu.GetSELinuxMountContext(mountPath) + if err != nil { + return volume.ReconstructedVolume{}, err + } + } + return volume.ReconstructedVolume{ - Spec: volume.NewSpecFromVolume(rbdVolume), + Spec: volume.NewSpecFromVolume(rbdVolume), + SELinuxMountContext: mountContext, }, nil } diff --git a/pkg/volume/util/hostutil/fake_hostutil.go b/pkg/volume/util/hostutil/fake_hostutil.go index 36b72e5e8ec..0efccb3e365 100644 --- a/pkg/volume/util/hostutil/fake_hostutil.go +++ b/pkg/volume/util/hostutil/fake_hostutil.go @@ -116,3 +116,9 @@ func (hu *FakeHostUtil) GetSELinuxSupport(pathname string) (bool, error) { func (hu *FakeHostUtil) GetMode(pathname string) (os.FileMode, error) { return 0, errors.New("not implemented") } + +// GetSELinuxMountContext returns value of -o context=XYZ mount option on +// given mount point. +func (hu *FakeHostUtil) GetSELinuxMountContext(pathname string) (string, error) { + return "", errors.New("not implemented") +} diff --git a/pkg/volume/util/hostutil/hostutil.go b/pkg/volume/util/hostutil/hostutil.go index 561278b7d8b..dfe165aae36 100644 --- a/pkg/volume/util/hostutil/hostutil.go +++ b/pkg/volume/util/hostutil/hostutil.go @@ -68,6 +68,9 @@ type HostUtils interface { GetSELinuxSupport(pathname string) (bool, error) // GetMode returns permissions of the path. GetMode(pathname string) (os.FileMode, error) + // GetSELinuxMountContext returns value of -o context=XYZ mount option on + // given mount point. + GetSELinuxMountContext(pathname string) (string, error) } // Compile-time check to ensure all HostUtil implementations satisfy diff --git a/pkg/volume/util/hostutil/hostutil_linux.go b/pkg/volume/util/hostutil/hostutil_linux.go index 60e76e0e7d5..5c687d9f447 100644 --- a/pkg/volume/util/hostutil/hostutil_linux.go +++ b/pkg/volume/util/hostutil/hostutil_linux.go @@ -299,3 +299,35 @@ func GetModeLinux(pathname string) (os.FileMode, error) { } return info.Mode(), nil } + +// GetSELinuxMountContext returns value of -o context=XYZ mount option on +// given mount point. +func (hu *HostUtil) GetSELinuxMountContext(pathname string) (string, error) { + return getSELinuxMountContext(pathname, procMountInfoPath, selinux.GetEnabled) +} + +// getSELinux is common implementation of GetSELinuxSupport on Linux. +// Using an extra function for unit tests. +func getSELinuxMountContext(path string, mountInfoFilename string, selinuxEnabled seLinuxEnabledFunc) (string, error) { + // Skip /proc/mounts parsing if SELinux is disabled. + if !selinuxEnabled() { + return "", nil + } + + info, err := findMountInfo(path, mountInfoFilename) + if err != nil { + return "", err + } + + for _, opt := range info.SuperOptions { + if !strings.HasPrefix(opt, "context=") { + continue + } + // Remove context= + context := strings.TrimPrefix(opt, "context=") + // Remove double quotes + context = strings.Trim(context, "\"") + return context, nil + } + return "", nil +} diff --git a/pkg/volume/util/hostutil/hostutil_linux_test.go b/pkg/volume/util/hostutil/hostutil_linux_test.go index 4ae76e28f6a..cc2007e3caf 100644 --- a/pkg/volume/util/hostutil/hostutil_linux_test.go +++ b/pkg/volume/util/hostutil/hostutil_linux_test.go @@ -331,3 +331,60 @@ func writeFile(content string) (string, string, error) { } return tempDir, filename, nil } + +func TestGetSELinuxMountContext(t *testing.T) { + info := + `840 60 8:0 / /var/lib/kubelet/pods/d4f3b306-ad4c-4f7a-8983-b5b228039a8c/volumes/kubernetes.io~iscsi/mypv rw,relatime shared:421 - ext4 /dev/sda rw,context="system_u:object_r:container_file_t:s0:c314,c894" +224 62 253:0 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered +82 62 0:43 / /var/lib/foo rw,relatime shared:32 - tmpfs tmpfs rw +83 63 0:44 / /var/lib/bar rw,relatime - tmpfs tmpfs rw +` + tempDir, filename, err := writeFile(info) + if err != nil { + t.Fatalf("cannot create temporary file: %v", err) + } + defer os.RemoveAll(tempDir) + + tests := []struct { + name string + mountPoint string + seLinuxEnabled bool + expectedContext string + }{ + { + "no context", + "/var/lib/foo", + true, + "", + }, + { + "with context with SELinux", + "/var/lib/kubelet/pods/d4f3b306-ad4c-4f7a-8983-b5b228039a8c/volumes/kubernetes.io~iscsi/mypv", + true, + "system_u:object_r:container_file_t:s0:c314,c894", + }, + { + "with context with no SELinux", + "/var/lib/kubelet/pods/d4f3b306-ad4c-4f7a-8983-b5b228039a8c/volumes/kubernetes.io~iscsi/mypv", + false, + "", + }, + { + "no context with seclabel", + "/var/lib/docker/devicemapper/test/shared", + true, + "", + }, + } + + for _, test := range tests { + out, err := getSELinuxMountContext(test.mountPoint, filename, func() bool { return test.seLinuxEnabled }) + if err != nil { + t.Errorf("Test %s failed with error: %s", test.name, err) + } + if test.expectedContext != out { + t.Errorf("Test %s failed: expected %v, got %v", test.name, test.expectedContext, out) + } + } + +} diff --git a/pkg/volume/util/hostutil/hostutil_unsupported.go b/pkg/volume/util/hostutil/hostutil_unsupported.go index 0c25c352426..c5ff9c0b5e1 100644 --- a/pkg/volume/util/hostutil/hostutil_unsupported.go +++ b/pkg/volume/util/hostutil/hostutil_unsupported.go @@ -101,3 +101,9 @@ func (hu *HostUtil) GetMode(pathname string) (os.FileMode, error) { func getDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) { return "", errUnsupported } + +// GetSELinuxMountContext returns value of -o context=XYZ mount option on +// given mount point. +func (hu *HostUtil) GetSELinuxMountContext(pathname string) (string, error) { + return "", errUnsupported +} diff --git a/pkg/volume/util/hostutil/hostutil_windows.go b/pkg/volume/util/hostutil/hostutil_windows.go index bd59624b870..c039ada4066 100644 --- a/pkg/volume/util/hostutil/hostutil_windows.go +++ b/pkg/volume/util/hostutil/hostutil_windows.go @@ -123,3 +123,9 @@ func (hu *HostUtil) GetMode(pathname string) (os.FileMode, error) { } return info.Mode(), nil } + +// GetSELinuxMountContext returns value of -o context=XYZ mount option on +// given mount point. +func (hu *HostUtil) GetSELinuxMountContext(pathname string) (string, error) { + return "", nil +}