mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Add SELinux context tracking to volume manager
Both ActualStateOfWorld and DesiredStateOfWorld must track SELinux context of volume mounts.
This commit is contained in:
parent
4cfb277e8b
commit
48b0751269
@ -27,7 +27,9 @@ import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/util"
|
||||
"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
|
||||
@ -73,7 +75,7 @@ type ActualStateOfWorld interface {
|
||||
// global mount point prior to detach.
|
||||
// If a volume with the name volumeName does not exist in the list of
|
||||
// attached volumes, an error is returned.
|
||||
SetDeviceMountState(volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath string) error
|
||||
SetDeviceMountState(volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath, seLinuxMountContext string) error
|
||||
|
||||
// DeletePodFromVolume removes the given pod from the given volume in the
|
||||
// cache indicating the volume has been successfully unmounted from the pod.
|
||||
@ -107,7 +109,7 @@ type ActualStateOfWorld interface {
|
||||
// volumes, depend on this to update the contents of the volume.
|
||||
// All volume mounting calls should be idempotent so a second mount call for
|
||||
// volumes that do not need to update contents should not fail.
|
||||
PodExistsInVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName, desiredVolumeSize resource.Quantity) (bool, string, error)
|
||||
PodExistsInVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName, desiredVolumeSize resource.Quantity, seLinuxLabel string) (bool, string, error)
|
||||
|
||||
// PodRemovedFromVolume returns true if the given pod does not exist in the list of
|
||||
// mountedPods for the given volume in the cache, indicating that the pod has
|
||||
@ -182,6 +184,11 @@ type AttachedVolume struct {
|
||||
|
||||
// DeviceMountState indicates if device has been globally mounted or is not.
|
||||
DeviceMountState operationexecutor.DeviceMountState
|
||||
|
||||
// SELinuxMountContext is the context with that the volume is globally mounted
|
||||
// (via -o context=XYZ mount option). If empty, the volume is not mounted with
|
||||
// "-o context=".
|
||||
SELinuxMountContext string
|
||||
}
|
||||
|
||||
// DeviceMayBeMounted returns true if device is mounted in global path or is in
|
||||
@ -288,6 +295,11 @@ type attachedVolume struct {
|
||||
// persistentVolumeSize records size of the volume when pod was started or
|
||||
// size after successful completion of volume expansion operation.
|
||||
persistentVolumeSize *resource.Quantity
|
||||
|
||||
// seLinuxMountContext is the context with that the volume is mounted to global directory
|
||||
// (via -o context=XYZ mount option). If nil, the volume is not mounted. If "", the volume is
|
||||
// mounted without "-o context=".
|
||||
seLinuxMountContext *string
|
||||
}
|
||||
|
||||
// The mountedPod object represents a pod for which the kubelet volume manager
|
||||
@ -333,6 +345,11 @@ type mountedPod struct {
|
||||
// - VolumeMounted: means volume for pod has been successfully mounted
|
||||
// - VolumeMountUncertain: means volume for pod may not be mounted, but it must be unmounted
|
||||
volumeMountStateForPod operationexecutor.VolumeMountState
|
||||
|
||||
// seLinuxMountContext is the context with that the volume is mounted to Pod directory
|
||||
// (via -o context=XYZ mount option). If nil, the volume is not mounted. If "", the volume is
|
||||
// mounted without "-o context=".
|
||||
seLinuxMountContext string
|
||||
}
|
||||
|
||||
func (asw *actualStateOfWorld) MarkVolumeAsAttached(
|
||||
@ -465,13 +482,13 @@ func (asw *actualStateOfWorld) MarkVolumeAsUnmounted(
|
||||
}
|
||||
|
||||
func (asw *actualStateOfWorld) MarkDeviceAsMounted(
|
||||
volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error {
|
||||
return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceGloballyMounted, devicePath, deviceMountPath)
|
||||
volumeName v1.UniqueVolumeName, devicePath, deviceMountPath, seLinuxMountContext string) error {
|
||||
return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceGloballyMounted, devicePath, deviceMountPath, seLinuxMountContext)
|
||||
}
|
||||
|
||||
func (asw *actualStateOfWorld) MarkDeviceAsUncertain(
|
||||
volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error {
|
||||
return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceMountUncertain, devicePath, deviceMountPath)
|
||||
volumeName v1.UniqueVolumeName, devicePath, deviceMountPath, seLinuxMountContext string) error {
|
||||
return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceMountUncertain, devicePath, deviceMountPath, seLinuxMountContext)
|
||||
}
|
||||
|
||||
func (asw *actualStateOfWorld) MarkVolumeMountAsUncertain(markVolumeOpts operationexecutor.MarkVolumeOpts) error {
|
||||
@ -481,7 +498,7 @@ func (asw *actualStateOfWorld) MarkVolumeMountAsUncertain(markVolumeOpts operati
|
||||
|
||||
func (asw *actualStateOfWorld) MarkDeviceAsUnmounted(
|
||||
volumeName v1.UniqueVolumeName) error {
|
||||
return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceNotMounted, "", "")
|
||||
return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceNotMounted, "", "", "")
|
||||
}
|
||||
|
||||
func (asw *actualStateOfWorld) GetDeviceMountState(volumeName v1.UniqueVolumeName) operationexecutor.DeviceMountState {
|
||||
@ -629,6 +646,7 @@ func (asw *actualStateOfWorld) AddPodToVolume(markVolumeOpts operationexecutor.M
|
||||
volumeGidValue: volumeGidValue,
|
||||
volumeSpec: volumeSpec,
|
||||
volumeMountStateForPod: markVolumeOpts.VolumeMountState,
|
||||
seLinuxMountContext: markVolumeOpts.SELinuxMountContext,
|
||||
}
|
||||
}
|
||||
|
||||
@ -646,6 +664,15 @@ func (asw *actualStateOfWorld) AddPodToVolume(markVolumeOpts operationexecutor.M
|
||||
podObj.mounter = mounter
|
||||
}
|
||||
asw.attachedVolumes[volumeName].mountedPods[podName] = podObj
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
// Store the mount context also in the AttachedVolume to have a global volume context
|
||||
// for a quick comparison in PodExistsInVolume.
|
||||
if volumeObj.seLinuxMountContext == nil {
|
||||
volumeObj.seLinuxMountContext = &markVolumeOpts.SELinuxMountContext
|
||||
asw.attachedVolumes[volumeName] = volumeObj
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -685,7 +712,7 @@ func (asw *actualStateOfWorld) MarkRemountRequired(
|
||||
}
|
||||
|
||||
func (asw *actualStateOfWorld) SetDeviceMountState(
|
||||
volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath string) error {
|
||||
volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath, seLinuxMountContext string) error {
|
||||
asw.Lock()
|
||||
defer asw.Unlock()
|
||||
|
||||
@ -701,6 +728,11 @@ func (asw *actualStateOfWorld) SetDeviceMountState(
|
||||
if devicePath != "" {
|
||||
volumeObj.devicePath = devicePath
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
if seLinuxMountContext != "" {
|
||||
volumeObj.seLinuxMountContext = &seLinuxMountContext
|
||||
}
|
||||
}
|
||||
asw.attachedVolumes[volumeName] = volumeObj
|
||||
return nil
|
||||
}
|
||||
@ -776,7 +808,7 @@ func (asw *actualStateOfWorld) DeleteVolume(volumeName v1.UniqueVolumeName) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (asw *actualStateOfWorld) PodExistsInVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName, desiredVolumeSize resource.Quantity) (bool, string, error) {
|
||||
func (asw *actualStateOfWorld) PodExistsInVolume(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName, desiredVolumeSize resource.Quantity, seLinuxLabel string) (bool, string, error) {
|
||||
asw.RLock()
|
||||
defer asw.RUnlock()
|
||||
|
||||
@ -785,6 +817,22 @@ func (asw *actualStateOfWorld) PodExistsInVolume(podName volumetypes.UniquePodNa
|
||||
return false, "", newVolumeNotAttachedError(volumeName)
|
||||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
if volumeObj.seLinuxMountContext != nil {
|
||||
// The volume is mounted, check its SELinux context mount option
|
||||
if *volumeObj.seLinuxMountContext != seLinuxLabel {
|
||||
fullErr := newSELinuxMountMismatchError(volumeName)
|
||||
if util.IsRWOP(volumeObj.spec) {
|
||||
return false, volumeObj.devicePath, fullErr
|
||||
} else {
|
||||
// This is not an error yet, but it will be when support for RWO and RWX volumes is added
|
||||
// TODO: bump some metric here
|
||||
klog.V(4).ErrorS(fullErr, "Please report this error in https://github.com/kubernetes/enhancements/issues/1710, together with full Pod yaml file")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
podObj, podExists := volumeObj.mountedPods[podName]
|
||||
if podExists {
|
||||
// if volume mount was uncertain we should keep trying to mount the volume
|
||||
@ -905,7 +953,6 @@ func (asw *actualStateOfWorld) GetAllMountedVolumes() []MountedVolume {
|
||||
mountedVolume,
|
||||
getMountedVolume(&podObj, &volumeObj))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1010,15 +1057,22 @@ func (asw *actualStateOfWorld) SyncReconstructedVolume(volumeName v1.UniqueVolum
|
||||
|
||||
func (asw *actualStateOfWorld) newAttachedVolume(
|
||||
attachedVolume *attachedVolume) AttachedVolume {
|
||||
seLinuxMountContext := ""
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
if attachedVolume.seLinuxMountContext != nil {
|
||||
seLinuxMountContext = *attachedVolume.seLinuxMountContext
|
||||
}
|
||||
}
|
||||
return AttachedVolume{
|
||||
AttachedVolume: operationexecutor.AttachedVolume{
|
||||
VolumeName: attachedVolume.volumeName,
|
||||
VolumeSpec: attachedVolume.spec,
|
||||
NodeName: asw.nodeName,
|
||||
PluginIsAttachable: attachedVolume.pluginIsAttachable,
|
||||
DevicePath: attachedVolume.devicePath,
|
||||
DeviceMountPath: attachedVolume.deviceMountPath,
|
||||
PluginName: attachedVolume.pluginName},
|
||||
VolumeName: attachedVolume.volumeName,
|
||||
VolumeSpec: attachedVolume.spec,
|
||||
NodeName: asw.nodeName,
|
||||
PluginIsAttachable: attachedVolume.pluginIsAttachable,
|
||||
DevicePath: attachedVolume.devicePath,
|
||||
DeviceMountPath: attachedVolume.deviceMountPath,
|
||||
PluginName: attachedVolume.pluginName,
|
||||
SELinuxMountContext: seLinuxMountContext},
|
||||
DeviceMountState: attachedVolume.deviceMountState,
|
||||
}
|
||||
}
|
||||
@ -1105,6 +1159,10 @@ func IsFSResizeRequiredError(err error) bool {
|
||||
// mountedPod and attachedVolume objects.
|
||||
func getMountedVolume(
|
||||
mountedPod *mountedPod, attachedVolume *attachedVolume) MountedVolume {
|
||||
seLinuxMountContext := ""
|
||||
if attachedVolume.seLinuxMountContext != nil {
|
||||
seLinuxMountContext = *attachedVolume.seLinuxMountContext
|
||||
}
|
||||
return MountedVolume{
|
||||
MountedVolume: operationexecutor.MountedVolume{
|
||||
PodName: mountedPod.podName,
|
||||
@ -1117,5 +1175,32 @@ func getMountedVolume(
|
||||
BlockVolumeMapper: mountedPod.blockVolumeMapper,
|
||||
VolumeGidValue: mountedPod.volumeGidValue,
|
||||
VolumeSpec: mountedPod.volumeSpec,
|
||||
DeviceMountPath: attachedVolume.deviceMountPath}}
|
||||
DeviceMountPath: attachedVolume.deviceMountPath,
|
||||
SELinuxMountContext: seLinuxMountContext}}
|
||||
|
||||
}
|
||||
|
||||
// seLinuxMountMismatchError is an error returned when PodExistsInVolume() found
|
||||
// a volume mounted with a different SELinux label than expected.
|
||||
type seLinuxMountMismatchError struct {
|
||||
volumeName v1.UniqueVolumeName
|
||||
}
|
||||
|
||||
func (err seLinuxMountMismatchError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"volumeName %q is already mounted to a different pod with a different SELinux label",
|
||||
err.volumeName)
|
||||
}
|
||||
|
||||
func newSELinuxMountMismatchError(volumeName v1.UniqueVolumeName) error {
|
||||
return seLinuxMountMismatchError{
|
||||
volumeName: volumeName,
|
||||
}
|
||||
}
|
||||
|
||||
// IsSELinuxMountMismatchError returns true if the specified error is a
|
||||
// seLinuxMountMismatchError.
|
||||
func IsSELinuxMountMismatchError(err error) bool {
|
||||
_, ok := err.(seLinuxMountMismatchError)
|
||||
return ok
|
||||
}
|
||||
|
@ -737,7 +737,7 @@ func Test_MarkDeviceAsMounted_Positive_NewVolume(t *testing.T) {
|
||||
}
|
||||
|
||||
// Act
|
||||
err = asw.MarkDeviceAsMounted(generatedVolumeName, devicePath, deviceMountPath)
|
||||
err = asw.MarkDeviceAsMounted(generatedVolumeName, devicePath, deviceMountPath, "")
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -824,7 +824,7 @@ func TestUncertainVolumeMounts(t *testing.T) {
|
||||
t.Fatalf("expected volume %s to be found in aws.GetPossiblyMountedVolumesForPod", volumeSpec1.Name())
|
||||
}
|
||||
|
||||
volExists, _, _ := asw.PodExistsInVolume(podName1, generatedVolumeName1, resource.Quantity{})
|
||||
volExists, _, _ := asw.PodExistsInVolume(podName1, generatedVolumeName1, resource.Quantity{}, "")
|
||||
if volExists {
|
||||
t.Fatalf("expected volume %s to not exist in asw", generatedVolumeName1)
|
||||
}
|
||||
@ -910,7 +910,7 @@ func verifyPodExistsInVolumeAsw(
|
||||
expectedDevicePath string,
|
||||
asw ActualStateOfWorld) {
|
||||
podExistsInVolume, devicePath, err :=
|
||||
asw.PodExistsInVolume(expectedPodName, expectedVolumeName, resource.Quantity{})
|
||||
asw.PodExistsInVolume(expectedPodName, expectedVolumeName, resource.Quantity{}, "")
|
||||
if err != nil {
|
||||
t.Fatalf(
|
||||
"ASW PodExistsInVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
@ -952,7 +952,7 @@ func verifyPodDoesntExistInVolumeAsw(
|
||||
expectVolumeToExist bool,
|
||||
asw ActualStateOfWorld) {
|
||||
podExistsInVolume, devicePath, err :=
|
||||
asw.PodExistsInVolume(podToCheck, volumeToCheck, resource.Quantity{})
|
||||
asw.PodExistsInVolume(podToCheck, volumeToCheck, resource.Quantity{}, "")
|
||||
if !expectVolumeToExist && err == nil {
|
||||
t.Fatalf(
|
||||
"ASW PodExistsInVolume did not return error. Expected: <error indicating volume does not exist> Actual: <%v>", err)
|
||||
|
@ -28,7 +28,10 @@ import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/klog/v2"
|
||||
apiv1resource "k8s.io/kubernetes/pkg/api/v1/resource"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/util"
|
||||
"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
|
||||
@ -55,7 +58,7 @@ type DesiredStateOfWorld interface {
|
||||
// added.
|
||||
// If a pod with the same unique name already exists under the specified
|
||||
// volume, this is a no-op.
|
||||
AddPodToVolume(podName types.UniquePodName, pod *v1.Pod, volumeSpec *volume.Spec, outerVolumeSpecName string, volumeGidValue string) (v1.UniqueVolumeName, error)
|
||||
AddPodToVolume(podName types.UniquePodName, pod *v1.Pod, volumeSpec *volume.Spec, outerVolumeSpecName string, volumeGidValue string, seLinuxContainerContexts []*v1.SELinuxOptions) (v1.UniqueVolumeName, error)
|
||||
|
||||
// MarkVolumesReportedInUse sets the ReportedInUse value to true for the
|
||||
// reportedVolumes. For volumes not in the reportedVolumes list, the
|
||||
@ -83,7 +86,7 @@ type DesiredStateOfWorld interface {
|
||||
// volumes that should be attached to this node.
|
||||
// If a pod with the same unique name does not exist under the specified
|
||||
// volume, false is returned.
|
||||
VolumeExists(volumeName v1.UniqueVolumeName) bool
|
||||
VolumeExists(volumeName v1.UniqueVolumeName, seLinuxMountContext string) bool
|
||||
|
||||
// PodExistsInVolume returns true if the given pod exists in the list of
|
||||
// podsToMount for the given volume in the cache.
|
||||
@ -91,7 +94,7 @@ type DesiredStateOfWorld interface {
|
||||
// volume, false is returned.
|
||||
// If a volume with the name volumeName does not exist in the list of
|
||||
// attached volumes, false is returned.
|
||||
PodExistsInVolume(podName types.UniquePodName, volumeName v1.UniqueVolumeName) bool
|
||||
PodExistsInVolume(podName types.UniquePodName, volumeName v1.UniqueVolumeName, seLinuxMountContext string) bool
|
||||
|
||||
// GetVolumesToMount generates and returns a list of volumes that should be
|
||||
// attached to this node and the pods they should be mounted to based on the
|
||||
@ -195,6 +198,13 @@ type volumeToMount struct {
|
||||
// persistentVolumeSize records desired size of a persistent volume.
|
||||
// Usually this value reflects size recorded in pv.Spec.Capacity
|
||||
persistentVolumeSize *resource.Quantity
|
||||
|
||||
// seLinuxFileLabel is desired SELinux label on files on the volume. If empty, then
|
||||
// - either the context+label is unknown (assigned randomly by the container runtime)
|
||||
// - or the volume plugin responsible for this volume does not support mounting with -o context
|
||||
// - or the OS does not support SELinux
|
||||
// In all cases, the SELinux context does not matter when mounting the volume.
|
||||
seLinuxFileLabel string
|
||||
}
|
||||
|
||||
// The pod object represents a pod that references the underlying volume and
|
||||
@ -232,7 +242,8 @@ func (dsw *desiredStateOfWorld) AddPodToVolume(
|
||||
pod *v1.Pod,
|
||||
volumeSpec *volume.Spec,
|
||||
outerVolumeSpecName string,
|
||||
volumeGidValue string) (v1.UniqueVolumeName, error) {
|
||||
volumeGidValue string,
|
||||
seLinuxContainerContexts []*v1.SELinuxOptions) (v1.UniqueVolumeName, error) {
|
||||
dsw.Lock()
|
||||
defer dsw.Unlock()
|
||||
|
||||
@ -268,7 +279,63 @@ func (dsw *desiredStateOfWorld) AddPodToVolume(
|
||||
volumeName = util.GetUniqueVolumeNameFromSpecWithPod(podName, volumePlugin, volumeSpec)
|
||||
}
|
||||
|
||||
if _, volumeExists := dsw.volumesToMount[volumeName]; !volumeExists {
|
||||
var seLinuxFileLabel string
|
||||
// Volume plugin supports SELinux context mount for all its volumes.
|
||||
var pluginSupportsSELinuxContextMount bool
|
||||
// The volume is ReadWriteOncePod. We don't support other volume types in SELinuxMountReadWriteOncePod feature.
|
||||
// Don't use mount option to apply the SELinux context, still, track the context and report metrics of things
|
||||
// that would break if the feature was for all volume access modes.
|
||||
var isRWOP bool
|
||||
|
||||
if feature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
pluginSupportsSELinuxContextMount, err = dsw.getSELinuxMountSupport(volumeSpec)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
isRWOP = util.IsRWOP(volumeSpec)
|
||||
if pluginSupportsSELinuxContextMount {
|
||||
// Ensure that a volume that can be mounted with "-o context=XYZ" is
|
||||
// used only by containers with the same SELinux contexts.
|
||||
for _, containerContext := range seLinuxContainerContexts {
|
||||
newLabel, err := util.SELinuxOptionsToFileLabel(containerContext)
|
||||
if err != nil {
|
||||
fullErr := fmt.Errorf("failed to construct SELinux label from context %q: %s", containerContext, err)
|
||||
if isRWOP {
|
||||
// Cannot mount with -o context if the context can't be composed.
|
||||
return "", fullErr
|
||||
} else {
|
||||
// This is not an error yet, but it will be when support for RWO and RWX volumes is added
|
||||
// TODO: bump some metric here
|
||||
klog.V(4).ErrorS(err, "Please report this error in https://github.com/kubernetes/enhancements/issues/1710, together with full Pod yaml file")
|
||||
break
|
||||
}
|
||||
}
|
||||
if seLinuxFileLabel == "" {
|
||||
seLinuxFileLabel = newLabel
|
||||
continue
|
||||
}
|
||||
if seLinuxFileLabel != newLabel {
|
||||
fullErr := fmt.Errorf("volume %s is used with two different SELinux contexts in the same pod: %q, %q", volumeSpec.Name(), seLinuxFileLabel, newLabel)
|
||||
if isRWOP {
|
||||
return "", fullErr
|
||||
} else {
|
||||
// This is not an error yet, but it will be when support for RWO and RWX volumes is added
|
||||
// TODO: bump some metric here
|
||||
klog.V(4).ErrorS(err, "Please report this error in https://github.com/kubernetes/enhancements/issues/1710, together with full Pod yaml file")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Volume plugin does not support SELinux context mount.
|
||||
// DSW will track this volume with SELinux label "", i.e. no mount with
|
||||
// -o context.
|
||||
seLinuxFileLabel = ""
|
||||
}
|
||||
}
|
||||
klog.V(4).InfoS("volume final SELinux label decided", "volume", volumeSpec.Name(), "label", seLinuxFileLabel)
|
||||
|
||||
if vol, volumeExists := dsw.volumesToMount[volumeName]; !volumeExists {
|
||||
var sizeLimit *resource.Quantity
|
||||
if volumeSpec.Volume != nil {
|
||||
if util.IsLocalEphemeralVolume(*volumeSpec.Volume) {
|
||||
@ -291,6 +358,7 @@ func (dsw *desiredStateOfWorld) AddPodToVolume(
|
||||
volumeGidValue: volumeGidValue,
|
||||
reportedInUse: false,
|
||||
desiredSizeLimit: sizeLimit,
|
||||
seLinuxFileLabel: seLinuxFileLabel,
|
||||
}
|
||||
// record desired size of the volume
|
||||
if volumeSpec.PersistentVolume != nil {
|
||||
@ -300,9 +368,24 @@ func (dsw *desiredStateOfWorld) AddPodToVolume(
|
||||
vmt.persistentVolumeSize = &pvCapCopy
|
||||
}
|
||||
}
|
||||
|
||||
dsw.volumesToMount[volumeName] = vmt
|
||||
} else {
|
||||
// volume exists
|
||||
if pluginSupportsSELinuxContextMount {
|
||||
if seLinuxFileLabel != vol.seLinuxFileLabel {
|
||||
// TODO: update the error message after tests, e.g. add at least the conflicting pod names.
|
||||
fullErr := fmt.Errorf("conflicting SELinux labels of volume %s: %q and %q", volumeSpec.Name(), vol.seLinuxFileLabel, seLinuxFileLabel)
|
||||
if isRWOP {
|
||||
return "", fullErr
|
||||
} else {
|
||||
// This is not an error yet, but it will be when support for RWO and RWX volumes is added
|
||||
// TODO: bump some metric here
|
||||
klog.V(4).ErrorS(err, "Please report this error in https://github.com/kubernetes/enhancements/issues/1710, together with full Pod yaml file")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oldPodMount, ok := dsw.volumesToMount[volumeName].podsToMount[podName]
|
||||
mountRequestTime := time.Now()
|
||||
if ok && !volumePlugin.RequiresRemount(volumeSpec) {
|
||||
@ -380,16 +463,22 @@ func (dsw *desiredStateOfWorld) UpdatePersistentVolumeSize(volumeName v1.UniqueV
|
||||
}
|
||||
|
||||
func (dsw *desiredStateOfWorld) VolumeExists(
|
||||
volumeName v1.UniqueVolumeName) bool {
|
||||
volumeName v1.UniqueVolumeName, seLinuxMountContext string) bool {
|
||||
dsw.RLock()
|
||||
defer dsw.RUnlock()
|
||||
|
||||
_, volumeExists := dsw.volumesToMount[volumeName]
|
||||
return volumeExists
|
||||
vol, volumeExists := dsw.volumesToMount[volumeName]
|
||||
if !volumeExists {
|
||||
return false
|
||||
}
|
||||
if feature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
return vol.seLinuxFileLabel == seLinuxMountContext
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dsw *desiredStateOfWorld) PodExistsInVolume(
|
||||
podName types.UniquePodName, volumeName v1.UniqueVolumeName) bool {
|
||||
podName types.UniquePodName, volumeName v1.UniqueVolumeName, seLinuxMountOption string) bool {
|
||||
dsw.RLock()
|
||||
defer dsw.RUnlock()
|
||||
|
||||
@ -398,6 +487,15 @@ func (dsw *desiredStateOfWorld) PodExistsInVolume(
|
||||
return false
|
||||
}
|
||||
|
||||
if feature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
if volumeObj.seLinuxFileLabel != seLinuxMountOption {
|
||||
// The volume is in DSW, but with a different SELinux mount option.
|
||||
// Report it as unused, so the volume is unmounted and mounted back
|
||||
// with the right SELinux option.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
_, podExists := volumeObj.podsToMount[podName]
|
||||
return podExists
|
||||
}
|
||||
@ -448,6 +546,7 @@ func (dsw *desiredStateOfWorld) GetVolumesToMount() []VolumeToMount {
|
||||
ReportedInUse: volumeObj.reportedInUse,
|
||||
MountRequestTime: podObj.mountRequestTime,
|
||||
DesiredSizeLimit: volumeObj.desiredSizeLimit,
|
||||
SELinuxLabel: volumeObj.seLinuxFileLabel,
|
||||
},
|
||||
}
|
||||
if volumeObj.persistentVolumeSize != nil {
|
||||
@ -504,3 +603,7 @@ func (dsw *desiredStateOfWorld) MarkVolumeAttachability(volumeName v1.UniqueVolu
|
||||
volumeObj.pluginIsAttachable = attachable
|
||||
dsw.volumesToMount[volumeName] = volumeObj
|
||||
}
|
||||
|
||||
func (dsw *desiredStateOfWorld) getSELinuxMountSupport(volumeSpec *volume.Spec) (bool, error) {
|
||||
return util.SupportsSELinuxContextMount(volumeSpec, dsw.volumePluginMgr)
|
||||
}
|
||||
|
@ -17,10 +17,11 @@ limitations under the License.
|
||||
package cache
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
volumetesting "k8s.io/kubernetes/pkg/volume/testing"
|
||||
@ -59,7 +60,7 @@ func Test_AddPodToVolume_Positive_NewPodNewVolume(t *testing.T) {
|
||||
|
||||
// Act
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -104,7 +105,7 @@ func Test_AddPodToVolume_Positive_ExistingPodExistingVolume(t *testing.T) {
|
||||
|
||||
// Act
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -259,8 +260,8 @@ func Test_AddPodToVolume_Positive_NamesForDifferentPodsAndDifferentVolumes(t *te
|
||||
for name, v := range testcases {
|
||||
volumeSpec1 := &volume.Spec{Volume: &v.pod1.Spec.Volumes[0]}
|
||||
volumeSpec2 := &volume.Spec{Volume: &v.pod2.Spec.Volumes[0]}
|
||||
generatedVolumeName1, err1 := dsw.AddPodToVolume(util.GetUniquePodName(v.pod1), v.pod1, volumeSpec1, volumeSpec1.Name(), "")
|
||||
generatedVolumeName2, err2 := dsw.AddPodToVolume(util.GetUniquePodName(v.pod2), v.pod2, volumeSpec2, volumeSpec2.Name(), "")
|
||||
generatedVolumeName1, err1 := dsw.AddPodToVolume(util.GetUniquePodName(v.pod1), v.pod1, volumeSpec1, volumeSpec1.Name(), "", nil)
|
||||
generatedVolumeName2, err2 := dsw.AddPodToVolume(util.GetUniquePodName(v.pod2), v.pod2, volumeSpec2, volumeSpec2.Name(), "", nil)
|
||||
if err1 != nil {
|
||||
t.Fatalf("test %q: AddPodToVolume failed. Expected: <no error> Actual: <%v>", name, err1)
|
||||
}
|
||||
@ -309,7 +310,7 @@ func Test_DeletePodFromVolume_Positive_PodExistsVolumeExists(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */)
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
@ -407,19 +408,19 @@ func Test_MarkVolumesReportedInUse_Positive_NewPodNewVolume(t *testing.T) {
|
||||
pod3Name := util.GetUniquePodName(pod3)
|
||||
|
||||
generatedVolume1Name, err := dsw.AddPodToVolume(
|
||||
pod1Name, pod1, volume1Spec, volume1Spec.Name(), "" /* volumeGidValue */)
|
||||
pod1Name, pod1, volume1Spec, volume1Spec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */)
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
|
||||
generatedVolume2Name, err := dsw.AddPodToVolume(
|
||||
pod2Name, pod2, volume2Spec, volume2Spec.Name(), "" /* volumeGidValue */)
|
||||
pod2Name, pod2, volume2Spec, volume2Spec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */)
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
|
||||
generatedVolume3Name, err := dsw.AddPodToVolume(
|
||||
pod3Name, pod3, volume3Spec, volume3Spec.Name(), "" /* volumeGidValue */)
|
||||
pod3Name, pod3, volume3Spec, volume3Spec.Name(), "" /* volumeGidValue */, nil /* seLinuxContainerContexts */)
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
@ -580,14 +581,14 @@ func Test_AddPodToVolume_WithEmptyDirSizeLimit(t *testing.T) {
|
||||
}
|
||||
for i := range pod1.Spec.Volumes {
|
||||
volumeSpec := &volume.Spec{Volume: &pod1.Spec.Volumes[i]}
|
||||
_, err := dsw.AddPodToVolume(pod1Name, pod1, volumeSpec, volumeSpec.Name(), "")
|
||||
_, err := dsw.AddPodToVolume(pod1Name, pod1, volumeSpec, volumeSpec.Name(), "", nil /* seLinuxContainerContexts */)
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
}
|
||||
for i := range pod2.Spec.Volumes {
|
||||
volumeSpec := &volume.Spec{Volume: &pod2.Spec.Volumes[i]}
|
||||
_, err := dsw.AddPodToVolume(pod2Name, pod2, volumeSpec, volumeSpec.Name(), "")
|
||||
_, err := dsw.AddPodToVolume(pod2Name, pod2, volumeSpec, volumeSpec.Name(), "", nil /* seLinuxContainerContexts */)
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ package metrics
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/kubelet/volumemanager/cache"
|
||||
@ -56,7 +56,7 @@ func TestMetricCollection(t *testing.T) {
|
||||
podName := util.GetUniquePodName(pod)
|
||||
|
||||
// Add one volume to DesiredStateOfWorld
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(podName, pod, volumeSpec, volumeSpec.Name(), "")
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(podName, pod, volumeSpec, volumeSpec.Name(), "", "" /* seLinuxLabel */)
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ func (dswp *desiredStateOfWorldPopulator) processPodVolumes(
|
||||
}
|
||||
|
||||
allVolumesAdded := true
|
||||
mounts, devices := util.GetPodVolumeNames(pod)
|
||||
mounts, devices, seLinuxContainerContexts := util.GetPodVolumeNames(pod)
|
||||
|
||||
// Process volume spec for each volume defined in pod
|
||||
for _, podVolume := range pod.Spec.Volumes {
|
||||
@ -304,7 +304,7 @@ func (dswp *desiredStateOfWorldPopulator) processPodVolumes(
|
||||
|
||||
// Add volume to desired state of world
|
||||
uniqueVolumeName, err := dswp.desiredStateOfWorld.AddPodToVolume(
|
||||
uniquePodName, pod, volumeSpec, podVolume.Name, volumeGidValue)
|
||||
uniquePodName, pod, volumeSpec, podVolume.Name, volumeGidValue, seLinuxContainerContexts[podVolume.Name])
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "Failed to add volume to desiredStateOfWorld", "pod", klog.KObj(pod), "volumeName", podVolume.Name, "volumeSpecName", volumeSpec.Name())
|
||||
dswp.desiredStateOfWorld.AddErrorToPod(uniquePodName, err.Error())
|
||||
|
@ -199,7 +199,7 @@ func (rc *reconciler) reconcile() {
|
||||
func (rc *reconciler) unmountVolumes() {
|
||||
// Ensure volumes that should be unmounted are unmounted.
|
||||
for _, mountedVolume := range rc.actualStateOfWorld.GetAllMountedVolumes() {
|
||||
if !rc.desiredStateOfWorld.PodExistsInVolume(mountedVolume.PodName, mountedVolume.VolumeName) {
|
||||
if !rc.desiredStateOfWorld.PodExistsInVolume(mountedVolume.PodName, mountedVolume.VolumeName, mountedVolume.SELinuxMountContext) {
|
||||
// Volume is mounted, unmount it
|
||||
klog.V(5).InfoS(mountedVolume.GenerateMsgDetailed("Starting operationExecutor.UnmountVolume", ""))
|
||||
err := rc.operationExecutor.UnmountVolume(
|
||||
@ -217,9 +217,14 @@ func (rc *reconciler) unmountVolumes() {
|
||||
func (rc *reconciler) mountOrAttachVolumes() {
|
||||
// Ensure volumes that should be attached/mounted are attached/mounted.
|
||||
for _, volumeToMount := range rc.desiredStateOfWorld.GetVolumesToMount() {
|
||||
volMounted, devicePath, err := rc.actualStateOfWorld.PodExistsInVolume(volumeToMount.PodName, volumeToMount.VolumeName, volumeToMount.PersistentVolumeSize)
|
||||
volMounted, devicePath, err := rc.actualStateOfWorld.PodExistsInVolume(volumeToMount.PodName, volumeToMount.VolumeName, volumeToMount.PersistentVolumeSize, volumeToMount.SELinuxLabel)
|
||||
volumeToMount.DevicePath = devicePath
|
||||
if cache.IsVolumeNotAttachedError(err) {
|
||||
if cache.IsSELinuxMountMismatchError(err) {
|
||||
// TODO: check error message + lower frequency, this can be noisy
|
||||
klog.ErrorS(err, volumeToMount.GenerateErrorDetailed("mount precondition failed", err).Error(), "pod", klog.KObj(volumeToMount.Pod))
|
||||
// TODO: report error better, this may be too noisy
|
||||
rc.desiredStateOfWorld.AddErrorToPod(volumeToMount.PodName, err.Error())
|
||||
} else if cache.IsVolumeNotAttachedError(err) {
|
||||
rc.waitForVolumeAttach(volumeToMount)
|
||||
} else if !volMounted || cache.IsRemountRequiredError(err) {
|
||||
rc.mountAttachedVolumes(volumeToMount, err)
|
||||
@ -373,7 +378,7 @@ func (rc *reconciler) waitForVolumeAttach(volumeToMount cache.VolumeToMount) {
|
||||
func (rc *reconciler) unmountDetachDevices() {
|
||||
for _, attachedVolume := range rc.actualStateOfWorld.GetUnmountedVolumes() {
|
||||
// Check IsOperationPending to avoid marking a volume as detached if it's in the process of mounting.
|
||||
if !rc.desiredStateOfWorld.VolumeExists(attachedVolume.VolumeName) &&
|
||||
if !rc.desiredStateOfWorld.VolumeExists(attachedVolume.VolumeName, attachedVolume.SELinuxMountContext) &&
|
||||
!rc.operationExecutor.IsOperationPending(attachedVolume.VolumeName, nestedpendingoperations.EmptyUniquePodName, nestedpendingoperations.EmptyNodeName) {
|
||||
if attachedVolume.DeviceMayBeMounted() {
|
||||
// Volume is globally mounted to device, unmount it
|
||||
@ -765,7 +770,8 @@ func (rc *reconciler) updateStates(volumesNeedUpdate map[v1.UniqueVolumeName]*gl
|
||||
klog.ErrorS(err, "Could not find device mount path for volume", "volumeName", gvl.volumeName)
|
||||
continue
|
||||
}
|
||||
err = rc.actualStateOfWorld.MarkDeviceAsMounted(gvl.volumeName, gvl.devicePath, deviceMountPath)
|
||||
// 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)
|
||||
continue
|
||||
|
@ -160,7 +160,7 @@ func Test_Run_Positive_VolumeAttachAndMount(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -349,7 +349,7 @@ func Test_Run_Positive_VolumeMountControllerAttachEnabled(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{generatedVolumeName})
|
||||
|
||||
// Assert
|
||||
@ -428,7 +428,7 @@ func Test_Run_Negative_VolumeMountControllerAttachEnabled(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -506,7 +506,7 @@ func Test_Run_Positive_VolumeAttachMountUnmountDetach(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -608,7 +608,7 @@ func Test_Run_Positive_VolumeUnmountControllerAttachEnabled(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -715,7 +715,7 @@ func Test_Run_Positive_VolumeAttachAndMap(t *testing.T) {
|
||||
}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -827,7 +827,7 @@ func Test_Run_Positive_BlockVolumeMapControllerAttachEnabled(t *testing.T) {
|
||||
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{generatedVolumeName})
|
||||
|
||||
// Assert
|
||||
@ -924,7 +924,7 @@ func Test_Run_Positive_BlockVolumeAttachMapUnmapDetach(t *testing.T) {
|
||||
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -1048,7 +1048,7 @@ func Test_Run_Positive_VolumeUnmapControllerAttachEnabled(t *testing.T) {
|
||||
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
@ -1319,7 +1319,7 @@ func Test_Run_Positive_VolumeFSResizeControllerAttachEnabled(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{PersistentVolume: pv}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
volumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
// Assert
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
@ -1340,7 +1340,7 @@ func Test_Run_Positive_VolumeFSResizeControllerAttachEnabled(t *testing.T) {
|
||||
// Simulate what DSOWP does
|
||||
pvWithSize.Spec.Capacity[v1.ResourceStorage] = tc.newPVSize
|
||||
volumeSpec = &volume.Spec{PersistentVolume: pvWithSize}
|
||||
dsw.AddPodToVolume(podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
dsw.AddPodToVolume(podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
|
||||
t.Logf("Changing size of the volume to %s", tc.newPVSize.String())
|
||||
newSize := tc.newPVSize.DeepCopy()
|
||||
@ -1573,7 +1573,7 @@ func Test_UncertainDeviceGlobalMounts(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{PersistentVolume: pv}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
volumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
// Assert
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
@ -1795,7 +1795,7 @@ func Test_UncertainVolumeMountState(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{PersistentVolume: pv}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
volumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
// Assert
|
||||
if err != nil {
|
||||
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
|
||||
@ -2133,7 +2133,7 @@ func Test_Run_Positive_VolumeMountControllerAttachEnabledRace(t *testing.T) {
|
||||
volumeSpecCopy := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
generatedVolumeName, err := dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{generatedVolumeName})
|
||||
|
||||
if err != nil {
|
||||
@ -2158,7 +2158,7 @@ func Test_Run_Positive_VolumeMountControllerAttachEnabledRace(t *testing.T) {
|
||||
klog.InfoS("UnmountDevice called")
|
||||
var generatedVolumeNameCopy v1.UniqueVolumeName
|
||||
generatedVolumeNameCopy, err = dsw.AddPodToVolume(
|
||||
podName, pod, volumeSpecCopy, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpecCopy, volumeSpec.Name(), "" /* volumeGidValue */, nil /* seLinuxLabel */)
|
||||
dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{generatedVolumeNameCopy})
|
||||
return nil
|
||||
}
|
||||
@ -2410,7 +2410,7 @@ func TestSyncStates(t *testing.T) {
|
||||
volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
|
||||
podName := util.GetUniquePodName(pod)
|
||||
volumeName, err := rcInstance.desiredStateOfWorld.AddPodToVolume(
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
|
||||
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */, nil /* SELinuxContext */)
|
||||
if err != nil {
|
||||
t.Fatalf("error adding volume %s to dsow: %v", volumeSpec.Name(), err)
|
||||
}
|
||||
|
@ -536,7 +536,7 @@ func filterUnmountedVolumes(mountedVolumes sets.String, expectedVolumes []string
|
||||
// getExpectedVolumes returns a list of volumes that must be mounted in order to
|
||||
// consider the volume setup step for this pod satisfied.
|
||||
func getExpectedVolumes(pod *v1.Pod) []string {
|
||||
mounts, devices := util.GetPodVolumeNames(pod)
|
||||
mounts, devices, _ := util.GetPodVolumeNames(pod)
|
||||
return mounts.Union(devices).UnsortedList()
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,7 @@ func NewOperationExecutor(
|
||||
}
|
||||
}
|
||||
|
||||
// MarkVolumeOpts is an struct to pass arguments to MountVolume functions
|
||||
// MarkVolumeOpts is a struct to pass arguments to MountVolume functions
|
||||
type MarkVolumeOpts struct {
|
||||
PodName volumetypes.UniquePodName
|
||||
PodUID types.UID
|
||||
@ -177,6 +177,7 @@ type MarkVolumeOpts struct {
|
||||
VolumeGidVolume string
|
||||
VolumeSpec *volume.Spec
|
||||
VolumeMountState VolumeMountState
|
||||
SELinuxMountContext string
|
||||
}
|
||||
|
||||
// ActualStateOfWorldMounterUpdater defines a set of operations updating the actual
|
||||
@ -192,10 +193,10 @@ type ActualStateOfWorldMounterUpdater interface {
|
||||
MarkVolumeMountAsUncertain(markVolumeOpts MarkVolumeOpts) error
|
||||
|
||||
// Marks the specified volume as having been globally mounted.
|
||||
MarkDeviceAsMounted(volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error
|
||||
MarkDeviceAsMounted(volumeName v1.UniqueVolumeName, devicePath, deviceMountPath, seLinuxMountContext string) error
|
||||
|
||||
// MarkDeviceAsUncertain marks device state in global mount path as uncertain
|
||||
MarkDeviceAsUncertain(volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error
|
||||
MarkDeviceAsUncertain(volumeName v1.UniqueVolumeName, devicePath, deviceMountPath, seLinuxMountContext string) error
|
||||
|
||||
// Marks the specified volume as having its global mount unmounted.
|
||||
MarkDeviceAsUnmounted(volumeName v1.UniqueVolumeName) error
|
||||
@ -446,6 +447,9 @@ type VolumeToMount struct {
|
||||
// PersistentVolumeSize stores desired size of the volume.
|
||||
// usually this is the size if pv.Spec.Capacity
|
||||
PersistentVolumeSize resource.Quantity
|
||||
|
||||
// SELinux label that should be used to mount.
|
||||
SELinuxLabel string
|
||||
}
|
||||
|
||||
// DeviceMountState represents device mount state in a global path.
|
||||
@ -552,6 +556,8 @@ type AttachedVolume struct {
|
||||
// PluginName is the Unescaped Qualified name of the volume plugin used to
|
||||
// attach and mount this volume.
|
||||
PluginName string
|
||||
|
||||
SELinuxMountContext string
|
||||
}
|
||||
|
||||
// GenerateMsgDetailed returns detailed msgs for attached volumes
|
||||
@ -728,6 +734,10 @@ type MountedVolume struct {
|
||||
// DeviceMountPath contains the path on the node where the device should
|
||||
// be mounted after it is attached.
|
||||
DeviceMountPath string
|
||||
|
||||
// SELinuxMountContext is value of mount option 'mount -o context=XYZ'.
|
||||
// If empty, no such mount option was used.
|
||||
SELinuxMountContext string
|
||||
}
|
||||
|
||||
// GenerateMsgDetailed returns detailed msgs for mounted volumes
|
||||
|
@ -645,7 +645,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
||||
volumeToMount.VolumeSpec,
|
||||
devicePath,
|
||||
deviceMountPath,
|
||||
volume.DeviceMounterArgs{FsGroup: fsGroup},
|
||||
volume.DeviceMounterArgs{FsGroup: fsGroup, SELinuxLabel: volumeToMount.SELinuxLabel},
|
||||
)
|
||||
if err != nil {
|
||||
og.checkForFailedMount(volumeToMount, err)
|
||||
@ -659,7 +659,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
||||
|
||||
// Update actual state of world to reflect volume is globally mounted
|
||||
markDeviceMountedErr := actualStateOfWorld.MarkDeviceAsMounted(
|
||||
volumeToMount.VolumeName, devicePath, deviceMountPath)
|
||||
volumeToMount.VolumeName, devicePath, deviceMountPath, volumeToMount.SELinuxLabel)
|
||||
if markDeviceMountedErr != nil {
|
||||
// On failure, return error. Caller will log and retry.
|
||||
eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.MarkDeviceAsMounted failed", markDeviceMountedErr)
|
||||
@ -688,6 +688,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
||||
FsGroup: hostGID,
|
||||
DesiredSize: volumeToMount.DesiredSizeLimit,
|
||||
FSGroupChangePolicy: fsGroupChangePolicy,
|
||||
SELinuxLabel: volumeToMount.SELinuxLabel,
|
||||
})
|
||||
// Update actual state of world
|
||||
markOpts := MarkVolumeOpts{
|
||||
@ -699,6 +700,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
||||
VolumeGidVolume: volumeToMount.VolumeGidValue,
|
||||
VolumeSpec: volumeToMount.VolumeSpec,
|
||||
VolumeMountState: VolumeMounted,
|
||||
SELinuxMountContext: volumeToMount.SELinuxLabel,
|
||||
}
|
||||
if mountErr != nil {
|
||||
og.checkForFailedMount(volumeToMount, mountErr)
|
||||
@ -787,7 +789,7 @@ func (og *operationGenerator) markDeviceErrorState(volumeToMount VolumeToMount,
|
||||
actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceNotMounted {
|
||||
// only devices which are not mounted can be marked as uncertain. We do not want to mark a device
|
||||
// which was previously marked as mounted here as uncertain.
|
||||
markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath)
|
||||
markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath, volumeToMount.SELinuxLabel)
|
||||
if markDeviceUncertainError != nil {
|
||||
klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainError).Error())
|
||||
}
|
||||
@ -955,7 +957,7 @@ func (og *operationGenerator) GenerateUnmountDeviceFunc(
|
||||
unmountDeviceErr := volumeDeviceUnmounter.UnmountDevice(deviceMountPath)
|
||||
if unmountDeviceErr != nil {
|
||||
// Mark the device as uncertain, so MountDevice is called for new pods. UnmountDevice may be already in progress.
|
||||
markDeviceUncertainErr := actualStateOfWorld.MarkDeviceAsUncertain(deviceToDetach.VolumeName, deviceToDetach.DevicePath, deviceMountPath)
|
||||
markDeviceUncertainErr := actualStateOfWorld.MarkDeviceAsUncertain(deviceToDetach.VolumeName, deviceToDetach.DevicePath, deviceMountPath, deviceToDetach.SELinuxMountContext)
|
||||
if markDeviceUncertainErr != nil {
|
||||
// There is nothing else we can do. Hope that UnmountDevice will be re-tried shortly.
|
||||
klog.Errorf(deviceToDetach.GenerateErrorDetailed("UnmountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainErr).Error())
|
||||
@ -976,7 +978,7 @@ func (og *operationGenerator) GenerateUnmountDeviceFunc(
|
||||
// The device is still in use elsewhere. Caller will log and retry.
|
||||
if deviceOpened {
|
||||
// Mark the device as uncertain, so MountDevice is called for new pods.
|
||||
markDeviceUncertainErr := actualStateOfWorld.MarkDeviceAsUncertain(deviceToDetach.VolumeName, deviceToDetach.DevicePath, deviceMountPath)
|
||||
markDeviceUncertainErr := actualStateOfWorld.MarkDeviceAsUncertain(deviceToDetach.VolumeName, deviceToDetach.DevicePath, deviceMountPath, deviceToDetach.SELinuxMountContext)
|
||||
if markDeviceUncertainErr != nil {
|
||||
// There is nothing else we can do. Hope that UnmountDevice will be re-tried shortly.
|
||||
klog.Errorf(deviceToDetach.GenerateErrorDetailed("UnmountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainErr).Error())
|
||||
@ -1114,7 +1116,7 @@ func (og *operationGenerator) GenerateMapVolumeFunc(
|
||||
// Update actual state of world to reflect volume is globally mounted
|
||||
markedDevicePath := devicePath
|
||||
markDeviceMappedErr := actualStateOfWorld.MarkDeviceAsMounted(
|
||||
volumeToMount.VolumeName, markedDevicePath, globalMapPath)
|
||||
volumeToMount.VolumeName, markedDevicePath, globalMapPath, "")
|
||||
if markDeviceMappedErr != nil {
|
||||
// On failure, return error. Caller will log and retry.
|
||||
eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.MarkDeviceAsMounted failed", markDeviceMappedErr)
|
||||
@ -1183,7 +1185,7 @@ func (og *operationGenerator) GenerateMapVolumeFunc(
|
||||
// TODO: This can be improved after #82492 is merged and ASW has state.
|
||||
if markedDevicePath != devicePath {
|
||||
markDeviceMappedErr := actualStateOfWorld.MarkDeviceAsMounted(
|
||||
volumeToMount.VolumeName, devicePath, globalMapPath)
|
||||
volumeToMount.VolumeName, devicePath, globalMapPath, "")
|
||||
if markDeviceMappedErr != nil {
|
||||
// On failure, return error. Caller will log and retry.
|
||||
eventErr, detailedErr := volumeToMount.GenerateError("MapVolume.MarkDeviceAsMounted failed", markDeviceMappedErr)
|
||||
@ -1411,7 +1413,7 @@ func (og *operationGenerator) GenerateUnmapDeviceFunc(
|
||||
// cases below. The volume is marked as fully un-mapped at the end of this function, when everything
|
||||
// succeeds.
|
||||
markDeviceUncertainErr := actualStateOfWorld.MarkDeviceAsUncertain(
|
||||
deviceToDetach.VolumeName, deviceToDetach.DevicePath, globalMapPath)
|
||||
deviceToDetach.VolumeName, deviceToDetach.DevicePath, globalMapPath, "" /* seLinuxMountContext */)
|
||||
if markDeviceUncertainErr != nil {
|
||||
// On failure, return error. Caller will log and retry.
|
||||
eventErr, detailedErr := deviceToDetach.GenerateError("UnmapDevice.MarkDeviceAsUncertain failed", markDeviceUncertainErr)
|
||||
|
117
pkg/volume/util/selinux.go
Normal file
117
pkg/volume/util/selinux.go
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright 2022 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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
)
|
||||
|
||||
// SELinuxOptionsToFileLabel returns SELinux file label for given options.
|
||||
func SELinuxOptionsToFileLabel(opts *v1.SELinuxOptions) (string, error) {
|
||||
if opts == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
args := contextOptions(opts)
|
||||
if len(args) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// TODO: use interface for InitLabels for unit tests.
|
||||
processLabel, fileLabel, err := label.InitLabels(args)
|
||||
if err != nil {
|
||||
// In theory, this should be unreachable. InitLabels can fail only when args contain an unknown option,
|
||||
// and all options returned by contextOptions are known.
|
||||
return "", err
|
||||
}
|
||||
// InitLabels() may allocate a new unique SELinux label in kubelet memory. The label is *not* allocated
|
||||
// in the container runtime. Clear it to avoid memory problems.
|
||||
// ReleaseLabel on non-allocated label is NOOP.
|
||||
selinux.ReleaseLabel(processLabel)
|
||||
|
||||
return fileLabel, nil
|
||||
}
|
||||
|
||||
// Convert SELinuxOptions to []string accepted by label.InitLabels
|
||||
func contextOptions(opts *v1.SELinuxOptions) []string {
|
||||
if opts == nil {
|
||||
return nil
|
||||
}
|
||||
args := make([]string, 0, 3)
|
||||
if opts.User != "" {
|
||||
args = append(args, "user:"+opts.User)
|
||||
}
|
||||
if opts.Role != "" {
|
||||
args = append(args, "role:"+opts.Role)
|
||||
}
|
||||
if opts.Type != "" {
|
||||
args = append(args, "type:"+opts.Type)
|
||||
}
|
||||
if opts.Level != "" {
|
||||
args = append(args, "level:"+opts.Level)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// SupportsSELinuxContextMount checks if the given volumeSpec supports with mount -o context
|
||||
func SupportsSELinuxContextMount(volumeSpec *volume.Spec, volumePluginMgr *volume.VolumePluginMgr) (bool, error) {
|
||||
// This is cheap
|
||||
if !selinux.GetEnabled() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
plugin, _ := volumePluginMgr.FindPluginBySpec(volumeSpec)
|
||||
if plugin != nil {
|
||||
return plugin.SupportsSELinuxContextMount(volumeSpec)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func IsRWOP(volumeSpec *volume.Spec) bool {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod) {
|
||||
return false
|
||||
}
|
||||
if volumeSpec.PersistentVolume == nil {
|
||||
return false
|
||||
}
|
||||
if len(volumeSpec.PersistentVolume.Spec.AccessModes) != 1 {
|
||||
return false
|
||||
}
|
||||
if !v1helper.ContainsAccessMode(volumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AddSELinuxMountOption adds -o context="XYZ" mount option to a given list
|
||||
func AddSELinuxMountOption(options []string, seLinuxContext string) []string {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
return options
|
||||
}
|
||||
// Use double quotes to support a comma "," in the SELinux context string.
|
||||
// For example: dirsync,context="system_u:object_r:container_file_t:s0:c15,c25",noatime
|
||||
return append(options, fmt.Sprintf("context=%q", seLinuxContext))
|
||||
}
|
@ -275,16 +275,6 @@ func JoinMountOptions(userOptions []string, systemOptions []string) []string {
|
||||
return allMountOptions.List()
|
||||
}
|
||||
|
||||
// AddSELinuxMountOption adds -o context="XYZ mount option to a given list
|
||||
func AddSELinuxMountOption(options []string, seLinuxContext string) []string {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
return options
|
||||
}
|
||||
// Use double quotes to support a comma "," in the SELinux context string.
|
||||
// For example: dirsync,context="system_u:object_r:container_file_t:s0:c15,c25",noatime
|
||||
return append(options, "context=%q", seLinuxContext)
|
||||
}
|
||||
|
||||
// ContainsAccessMode returns whether the requested mode is contained by modes
|
||||
func ContainsAccessMode(modes []v1.PersistentVolumeAccessMode, mode v1.PersistentVolumeAccessMode) bool {
|
||||
for _, m := range modes {
|
||||
@ -584,15 +574,29 @@ func IsLocalEphemeralVolume(volume v1.Volume) bool {
|
||||
}
|
||||
|
||||
// GetPodVolumeNames returns names of volumes that are used in a pod,
|
||||
// either as filesystem mount or raw block device.
|
||||
func GetPodVolumeNames(pod *v1.Pod) (mounts sets.String, devices sets.String) {
|
||||
// either as filesystem mount or raw block device, together with list
|
||||
// of all SELinux contexts of all containers that use the volumes.
|
||||
func GetPodVolumeNames(pod *v1.Pod) (mounts sets.String, devices sets.String, seLinuxContainerContexts map[string][]*v1.SELinuxOptions) {
|
||||
mounts = sets.NewString()
|
||||
devices = sets.NewString()
|
||||
seLinuxContainerContexts = make(map[string][]*v1.SELinuxOptions)
|
||||
|
||||
podutil.VisitContainers(&pod.Spec, podutil.AllFeatureEnabledContainers(), func(container *v1.Container, containerType podutil.ContainerType) bool {
|
||||
var seLinuxOptions *v1.SELinuxOptions
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
|
||||
effectiveContainerSecurity := securitycontext.DetermineEffectiveSecurityContext(pod, container)
|
||||
if effectiveContainerSecurity != nil {
|
||||
// No DeepCopy, SELinuxOptions is already a copy of Pod's or container's SELinuxOptions
|
||||
seLinuxOptions = effectiveContainerSecurity.SELinuxOptions
|
||||
}
|
||||
}
|
||||
|
||||
if container.VolumeMounts != nil {
|
||||
for _, mount := range container.VolumeMounts {
|
||||
mounts.Insert(mount.Name)
|
||||
if seLinuxOptions != nil {
|
||||
seLinuxContainerContexts[mount.Name] = append(seLinuxContainerContexts[mount.Name], seLinuxOptions.DeepCopy())
|
||||
}
|
||||
}
|
||||
}
|
||||
if container.VolumeDevices != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user