Reconstruct SELinux mount option

When reconstructing volumes from disk after kubelet restart, reconstruct
also context=XYZ mount option and add it to the ActualStateOfWorld.
This commit is contained in:
Jan Safranek 2022-11-03 17:40:16 +01:00
parent 95bd687a28
commit e575e60ea4
16 changed files with 225 additions and 28 deletions

View File

@ -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) klog.ErrorS(err, "Could not find device mount path for volume", "volumeName", gvl.volumeName)
continue continue
} }
// TODO(jsafrane): add reconstructed SELinux context
err = rc.actualStateOfWorld.MarkDeviceAsMounted(gvl.volumeName, gvl.devicePath, deviceMountPath, "") err = rc.actualStateOfWorld.MarkDeviceAsMounted(gvl.volumeName, gvl.devicePath, deviceMountPath, "")
if err != nil { if err != nil {
klog.ErrorS(err, "Could not mark device is mounted to actual state of world", "volume", gvl.volumeName) klog.ErrorS(err, "Could not mark device is mounted to actual state of world", "volume", gvl.volumeName)

View File

@ -56,6 +56,7 @@ type reconstructedVolume struct {
mounter volumepkg.Mounter mounter volumepkg.Mounter
deviceMounter volumepkg.DeviceMounter deviceMounter volumepkg.DeviceMounter
blockVolumeMapper volumepkg.BlockVolumeMapper blockVolumeMapper volumepkg.BlockVolumeMapper
seLinuxMountContext string
} }
// globalVolumeInfo stores reconstructed volume information // globalVolumeInfo stores reconstructed volume information
@ -211,6 +212,9 @@ func (rc *reconciler) reconstructVolume(volume podVolume) (*reconstructedVolume,
return nil, err return nil, err
} }
volumeSpec := reconstructed.Spec 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 // We have to find the plugins by volume spec (NOT by plugin name) here
// in order to correctly reconstruct ephemeral volume types. // in order to correctly reconstruct ephemeral volume types.
@ -312,9 +316,10 @@ func (rc *reconciler) reconstructVolume(volume podVolume) (*reconstructedVolume,
volumeGidValue: "", volumeGidValue: "",
// devicePath is updated during updateStates() by checking node status's VolumesAttached data. // devicePath is updated during updateStates() by checking node status's VolumesAttached data.
// TODO: get device path directly from the volume mount path. // TODO: get device path directly from the volume mount path.
devicePath: "", devicePath: "",
mounter: volumeMounter, mounter: volumeMounter,
blockVolumeMapper: volumeMapper, blockVolumeMapper: volumeMapper,
seLinuxMountContext: reconstructed.SELinuxMountContext,
} }
return reconstructedVolume, nil return reconstructedVolume, nil
} }

View File

@ -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) klog.ErrorS(err, "Could not add volume information to actual state of world", "volumeName", gvl.volumeName)
continue continue
} }
var seLinuxMountContext string
for _, volume := range gvl.podVolumes { for _, volume := range gvl.podVolumes {
markVolumeOpts := operationexecutor.MarkVolumeOpts{ markVolumeOpts := operationexecutor.MarkVolumeOpts{
PodName: volume.podName, PodName: volume.podName,
@ -123,6 +124,7 @@ func (rc *reconciler) updateStatesNew(reconstructedVolumes map[v1.UniqueVolumeNa
VolumeGidVolume: volume.volumeGidValue, VolumeGidVolume: volume.volumeGidValue,
VolumeSpec: volume.volumeSpec, VolumeSpec: volume.volumeSpec,
VolumeMountState: operationexecutor.VolumeMountUncertain, VolumeMountState: operationexecutor.VolumeMountUncertain,
SELinuxMountContext: volume.seLinuxMountContext,
} }
_, err = rc.actualStateOfWorld.CheckAndMarkVolumeAsUncertainViaReconstruction(markVolumeOpts) _, 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)) klog.ErrorS(err, "Could not add pod to volume information to actual state of world", "pod", klog.KObj(volume.pod))
continue 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 the volume has device to mount, we mark its device as uncertain.
if gvl.deviceMounter != nil || gvl.blockVolumeMapper != nil { 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) klog.ErrorS(err, "Could not find device mount path for volume", "volumeName", gvl.volumeName)
continue continue
} }
err = rc.actualStateOfWorld.MarkDeviceAsUncertain(gvl.volumeName, gvl.devicePath, deviceMountPath, "") err = rc.actualStateOfWorld.MarkDeviceAsUncertain(gvl.volumeName, gvl.devicePath, deviceMountPath, seLinuxMountContext)
if err != nil { if err != nil {
klog.ErrorS(err, "Could not mark device is uncertain to actual state of world", "volumeName", gvl.volumeName, "deviceMountPath", deviceMountPath) klog.ErrorS(err, "Could not mark device is uncertain to actual state of world", "volumeName", gvl.volumeName, "deviceMountPath", deviceMountPath)
continue continue

View File

@ -60,7 +60,7 @@ var (
testAccount = "test-service-account" 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()) nodeName := string(plug.host.GetNodeName())
volData := map[string]string{ volData := map[string]string{
volDataKey.specVolID: specVolumeName, volDataKey.specVolID: specVolumeName,
@ -69,6 +69,7 @@ func prepareVolumeInfoFile(mountPath string, plug *csiPlugin, specVolumeName, vo
volDataKey.nodeName: nodeName, volDataKey.nodeName: nodeName,
volDataKey.attachmentID: getAttachmentName(volumeID, driverName, nodeName), volDataKey.attachmentID: getAttachmentName(volumeID, driverName, nodeName),
volDataKey.volumeLifecycleMode: lifecycleMode, volDataKey.volumeLifecycleMode: lifecycleMode,
volDataKey.seLinuxMountContext: seLinuxMountContext,
} }
if err := os.MkdirAll(mountPath, 0755); err != nil { if err := os.MkdirAll(mountPath, 0755); err != nil {
return fmt.Errorf("failed to create dir for volume info file: %s", err) return fmt.Errorf("failed to create dir for volume info file: %s", err)

View File

@ -455,22 +455,23 @@ func (p *csiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.Re
if err != nil { if err != nil {
return volume.ReconstructedVolume{}, errors.New(log("plugin.ConstructVolumeSpec failed loading volume data using [%s]: %v", mountPath, err)) 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)) 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 // If mode is VolumeLifecycleEphemeral, use constructVolSourceSpec
// to construct volume source spec. If mode is VolumeLifecyclePersistent, // to construct volume source spec. If mode is VolumeLifecyclePersistent,
// use constructPVSourceSpec to construct volume construct pv source spec. // use constructPVSourceSpec to construct volume construct pv source spec.
if storage.VolumeLifecycleMode(volData[volDataKey.volumeLifecycleMode]) == storage.VolumeLifecycleEphemeral { if storage.VolumeLifecycleMode(volData[volDataKey.volumeLifecycleMode]) == storage.VolumeLifecycleEphemeral {
spec = p.constructVolSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName]) ret.Spec = p.constructVolSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName])
return volume.ReconstructedVolume{Spec: spec}, nil return ret, nil
} }
spec = p.constructPVSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName], volData[volDataKey.volHandle]) ret.Spec = p.constructPVSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName], volData[volDataKey.volHandle])
return volume.ReconstructedVolume{ return ret, nil
Spec: spec,
}, nil
} }
// constructVolSourceSpec constructs volume.Spec with CSIVolumeSource // constructVolSourceSpec constructs volume.Spec with CSIVolumeSource

View File

@ -29,9 +29,12 @@ import (
meta "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers" "k8s.io/client-go/informers"
fakeclient "k8s.io/client-go/kubernetes/fake" fakeclient "k8s.io/client-go/kubernetes/fake"
utiltesting "k8s.io/client-go/util/testing" utiltesting "k8s.io/client-go/util/testing"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing" volumetest "k8s.io/kubernetes/pkg/volume/testing"
) )
@ -316,16 +319,20 @@ func TestPluginConstructVolumeSpec(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
testCases := []struct { testCases := []struct {
name string name string
originSpec *volume.Spec seLinuxMountEnabled bool
specVolID string originSpec *volume.Spec
volHandle string originSELinuxMountContext string
podUID types.UID specVolID string
volHandle string
expectedSELinuxContext string
podUID types.UID
}{ }{
{ {
name: "construct spec1 from original persistent spec", name: "construct spec1 from original persistent spec",
specVolID: "test.vol.id", specVolID: "test.vol.id",
volHandle: "testvol-handle1", volHandle: "testvol-handle1",
originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("test.vol.id", 20, testDriver, "testvol-handle1"), true), originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("test.vol.id", 20, testDriver, "testvol-handle1"), true),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), 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), originSpec: volume.NewSpecFromPersistentVolume(makeTestPV("spec2", 20, testDriver, "handle2"), true),
podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), 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) registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { 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( mounter, err := plug.NewMounter(
tc.originSpec, tc.originSpec,
&api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}}, &api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}},
@ -356,7 +386,7 @@ func TestPluginConstructVolumeSpec(t *testing.T) {
csiMounter := mounter.(*csiMountMgr) csiMounter := mounter.(*csiMountMgr)
mountPath := filepath.Dir(csiMounter.GetPath()) 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 { if err != nil {
t.Fatalf("failed to save fake volume info file: %s", err) 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 { if rec.Spec.Name() != tc.specVolID {
t.Errorf("Unexpected spec name constructed %s", rec.Spec.Name()) 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) csiMounter := mounter.(*csiMountMgr)
mountPath := filepath.Dir(csiMounter.GetPath()) 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 { if err != nil {
t.Fatalf("failed to save fake volume info file: %s", err) t.Fatalf("failed to save fake volume info file: %s", err)
} }

View File

@ -283,10 +283,25 @@ func (plugin *fcPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volum
FC: &v1.FCVolumeSource{WWIDs: wwids, Lun: &lun, TargetWWNs: wwns}, 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", klog.V(5).Infof("ConstructVolumeSpec: TargetWWNs: %v, Lun: %v, WWIDs: %v",
fcVolume.VolumeSource.FC.TargetWWNs, *fcVolume.VolumeSource.FC.Lun, fcVolume.VolumeSource.FC.WWIDs) fcVolume.VolumeSource.FC.TargetWWNs, *fcVolume.VolumeSource.FC.Lun, fcVolume.VolumeSource.FC.WWIDs)
return volume.ReconstructedVolume{ return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(fcVolume), Spec: volume.NewSpecFromVolume(fcVolume),
SELinuxMountContext: mountContext,
}, nil }, nil
} }

View File

@ -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{ return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(iscsiVolume), Spec: volume.NewSpecFromVolume(iscsiVolume),
SELinuxMountContext: mountContext,
}, nil }, nil
} }

View File

@ -573,7 +573,11 @@ type VolumeConfig struct {
// ReconstructedVolume contains information about a volume reconstructed by // ReconstructedVolume contains information about a volume reconstructed by
// ConstructVolumeSpec(). // ConstructVolumeSpec().
type ReconstructedVolume struct { type ReconstructedVolume struct {
// Spec is the volume spec of a mounted volume
Spec *Spec 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 // NewSpecFromVolume creates an Spec from an v1.Volume

View File

@ -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{ return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(rbdVolume), Spec: volume.NewSpecFromVolume(rbdVolume),
SELinuxMountContext: mountContext,
}, nil }, nil
} }

View File

@ -116,3 +116,9 @@ func (hu *FakeHostUtil) GetSELinuxSupport(pathname string) (bool, error) {
func (hu *FakeHostUtil) GetMode(pathname string) (os.FileMode, error) { func (hu *FakeHostUtil) GetMode(pathname string) (os.FileMode, error) {
return 0, errors.New("not implemented") 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")
}

View File

@ -68,6 +68,9 @@ type HostUtils interface {
GetSELinuxSupport(pathname string) (bool, error) GetSELinuxSupport(pathname string) (bool, error)
// GetMode returns permissions of the path. // GetMode returns permissions of the path.
GetMode(pathname string) (os.FileMode, error) 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 // Compile-time check to ensure all HostUtil implementations satisfy

View File

@ -299,3 +299,35 @@ func GetModeLinux(pathname string) (os.FileMode, error) {
} }
return info.Mode(), nil 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
}

View File

@ -331,3 +331,60 @@ func writeFile(content string) (string, string, error) {
} }
return tempDir, filename, nil 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)
}
}
}

View File

@ -101,3 +101,9 @@ func (hu *HostUtil) GetMode(pathname string) (os.FileMode, error) {
func getDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) { func getDeviceNameFromMount(mounter mount.Interface, mountPath, pluginMountDir string) (string, error) {
return "", errUnsupported 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
}

View File

@ -123,3 +123,9 @@ func (hu *HostUtil) GetMode(pathname string) (os.FileMode, error) {
} }
return info.Mode(), nil 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
}