Add CSIDriverSpec.SELinuxMount

The new field tells Kubernetes if the CSI driver supports mounting of
volumes with -o context=XYZ or not.
This commit is contained in:
Jan Safranek 2022-03-16 16:20:44 +01:00
parent 34dc6b2587
commit 3efeeef346
9 changed files with 206 additions and 12 deletions

View File

@ -390,6 +390,27 @@ type CSIDriverSpec struct {
// //
// +optional // +optional
RequiresRepublish *bool RequiresRepublish *bool
// SELinuxMount specifies if the CSI driver supports "-o context"
// mount option.
//
// When "true", the CSI driver must ensure that all volumes provided by this CSI
// driver can be mounted separately with different `-o context` options. This is
// typical for storage backends that provide volumes as filesystems on block
// devices or as independent shared volumes.
// Kubernetes will call NodeStage / NodePublish with "-o context=xyz" mount
// option when mounting a ReadWriteOncePod volume used in Pod that has
// explicitly set SELinux context. In the future, it may be expanded to other
// volume AccessModes. In any case, Kubernetes will ensure that the volume is
// mounted only with a single SELinux context.
//
// When "false", Kubernetes won't pass any special SELinux mount options to the driver.
// This is typical for volumes that represent subdirectories of a bigger shared filesystem.
//
// Default is "false".
//
// +optional
SELinuxMount *bool
} }
// FSGroupPolicy specifies if a CSI Driver supports modifying // FSGroupPolicy specifies if a CSI Driver supports modifying

View File

@ -64,4 +64,8 @@ func SetDefaults_CSIDriver(obj *storagev1.CSIDriver) {
obj.Spec.RequiresRepublish = new(bool) obj.Spec.RequiresRepublish = new(bool)
*(obj.Spec.RequiresRepublish) = false *(obj.Spec.RequiresRepublish) = false
} }
if obj.Spec.SELinuxMount == nil && utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
obj.Spec.SELinuxMount = new(bool)
*(obj.Spec.SELinuxMount) = false
}
} }

View File

@ -122,3 +122,30 @@ func TestSetDefaultCSIDriver(t *testing.T) {
}) })
} }
} }
func TestSetDefaultSELinuxMountReadWriteOncePodEnabled(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
driver := &storagev1.CSIDriver{}
// field should be defaulted
defaultSELinuxMount := false
output := roundTrip(t, runtime.Object(driver)).(*storagev1.CSIDriver)
outSELinuxMount := output.Spec.SELinuxMount
if outSELinuxMount == nil {
t.Errorf("Expected SELinuxMount to be defaulted to: %+v, got: nil", defaultSELinuxMount)
} else if *outSELinuxMount != defaultSELinuxMount {
t.Errorf("Expected SELinuxMount to be defaulted to: %+v, got: %+v", defaultSELinuxMount, outSELinuxMount)
}
}
func TestSetDefaultSELinuxMountReadWriteOncePodDisabled(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, false)()
driver := &storagev1.CSIDriver{}
// field should not be defaulted
output := roundTrip(t, runtime.Object(driver)).(*storagev1.CSIDriver)
outSELinuxMount := output.Spec.SELinuxMount
if outSELinuxMount != nil {
t.Errorf("Expected SELinuxMount to remain nil, got: %+v", outSELinuxMount)
}
}

View File

@ -64,4 +64,8 @@ func SetDefaults_CSIDriver(obj *storagev1beta1.CSIDriver) {
obj.Spec.RequiresRepublish = new(bool) obj.Spec.RequiresRepublish = new(bool)
*(obj.Spec.RequiresRepublish) = false *(obj.Spec.RequiresRepublish) = false
} }
if obj.Spec.SELinuxMount == nil && utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
obj.Spec.SELinuxMount = new(bool)
*(obj.Spec.SELinuxMount) = false
}
} }

View File

@ -165,3 +165,30 @@ func TestSetDefaultCSIDriver(t *testing.T) {
}) })
} }
} }
func TestSetDefaultSELinuxMountReadWriteOncePodEnabled(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
driver := &storagev1beta1.CSIDriver{}
// field should be defaulted
defaultSELinuxMount := false
output := roundTrip(t, runtime.Object(driver)).(*storagev1beta1.CSIDriver)
outSELinuxMount := output.Spec.SELinuxMount
if outSELinuxMount == nil {
t.Errorf("Expected SELinuxMount to be defaulted to: %+v, got: nil", defaultSELinuxMount)
} else if *outSELinuxMount != defaultSELinuxMount {
t.Errorf("Expected SELinuxMount to be defaulted to: %+v, got: %+v", defaultSELinuxMount, outSELinuxMount)
}
}
func TestSetDefaultSELinuxMountReadWriteOncePodDisabled(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, false)()
driver := &storagev1beta1.CSIDriver{}
// field should not be defaulted
output := roundTrip(t, runtime.Object(driver)).(*storagev1beta1.CSIDriver)
outSELinuxMount := output.Spec.SELinuxMount
if outSELinuxMount != nil {
t.Errorf("Expected SELinuxMount remain nil, got: %+v", outSELinuxMount)
}
}

View File

@ -50,6 +50,9 @@ func (csiDriverStrategy) PrepareForCreate(ctx context.Context, obj runtime.Objec
if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) { if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
csiDriver.Spec.VolumeLifecycleModes = nil csiDriver.Spec.VolumeLifecycleModes = nil
} }
if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
csiDriver.Spec.SELinuxMount = nil
}
} }
func (csiDriverStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { func (csiDriverStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
@ -87,6 +90,11 @@ func (csiDriverStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.
if !apiequality.Semantic.DeepEqual(oldCSIDriver.Spec.TokenRequests, newCSIDriver.Spec.TokenRequests) || !apiequality.Semantic.DeepEqual(oldCSIDriver.Spec.RequiresRepublish, newCSIDriver.Spec.RequiresRepublish) { if !apiequality.Semantic.DeepEqual(oldCSIDriver.Spec.TokenRequests, newCSIDriver.Spec.TokenRequests) || !apiequality.Semantic.DeepEqual(oldCSIDriver.Spec.RequiresRepublish, newCSIDriver.Spec.RequiresRepublish) {
newCSIDriver.Generation = oldCSIDriver.Generation + 1 newCSIDriver.Generation = oldCSIDriver.Generation + 1
} }
if oldCSIDriver.Spec.SELinuxMount == nil &&
!utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
newCSIDriver.Spec.SELinuxMount = nil
}
} }
func (csiDriverStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { func (csiDriverStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {

View File

@ -211,18 +211,36 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
RequiresRepublish: &enabled, RequiresRepublish: &enabled,
}, },
} }
driverWithSELinuxMountEnabled := &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
SELinuxMount: &enabled,
},
}
driverWithSELinuxMountDisabled := &storage.CSIDriver{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: storage.CSIDriverSpec{
SELinuxMount: &disabled,
},
}
resultPersistent := []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent} resultPersistent := []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent}
tests := []struct { tests := []struct {
name string name string
old, update *storage.CSIDriver old, update *storage.CSIDriver
csiInlineVolumeEnabled bool csiInlineVolumeEnabled bool
wantCapacity *bool seLinuxMountReadWriteOncePodEnabled bool
wantModes []storage.VolumeLifecycleMode wantCapacity *bool
wantTokenRequests []storage.TokenRequest wantModes []storage.VolumeLifecycleMode
wantRequiresRepublish *bool wantTokenRequests []storage.TokenRequest
wantGeneration int64 wantRequiresRepublish *bool
wantGeneration int64
wantSELinuxMount *bool
}{ }{
{ {
name: "capacity feature enabled, before: none, update: enabled", name: "capacity feature enabled, before: none, update: enabled",
@ -237,20 +255,20 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
wantCapacity: &disabled, wantCapacity: &disabled,
}, },
{ {
name: "inline feature enabled, before: none, update: persitent", name: "inline feature enabled, before: none, update: persistent",
csiInlineVolumeEnabled: true, csiInlineVolumeEnabled: true,
old: driverWithNothing, old: driverWithNothing,
update: driverWithPersistent, update: driverWithPersistent,
wantModes: resultPersistent, wantModes: resultPersistent,
}, },
{ {
name: "inline feature disabled, before: none, update: persitent", name: "inline feature disabled, before: none, update: persistent",
old: driverWithNothing, old: driverWithNothing,
update: driverWithPersistent, update: driverWithPersistent,
wantModes: nil, wantModes: nil,
}, },
{ {
name: "inline feature disabled, before: ephemeral, update: persitent", name: "inline feature disabled, before: ephemeral, update: persistent",
old: driverWithEphemeral, old: driverWithEphemeral,
update: driverWithPersistent, update: driverWithPersistent,
wantModes: resultPersistent, wantModes: resultPersistent,
@ -263,11 +281,54 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
wantRequiresRepublish: &enabled, wantRequiresRepublish: &enabled,
wantGeneration: 1, wantGeneration: 1,
}, },
{
name: "SELinux mount support feature enabled, before: nil, update: on",
seLinuxMountReadWriteOncePodEnabled: true,
old: driverWithNothing,
update: driverWithSELinuxMountEnabled,
wantSELinuxMount: &enabled,
},
{
name: "SELinux mount support feature enabled, before: off, update: on",
seLinuxMountReadWriteOncePodEnabled: true,
old: driverWithSELinuxMountDisabled,
update: driverWithSELinuxMountEnabled,
wantSELinuxMount: &enabled,
},
{
name: "SELinux mount support feature enabled, before: on, update: off",
seLinuxMountReadWriteOncePodEnabled: true,
old: driverWithSELinuxMountEnabled,
update: driverWithSELinuxMountDisabled,
wantSELinuxMount: &disabled,
},
{
name: "SELinux mount support feature disabled, before: nil, update: on",
seLinuxMountReadWriteOncePodEnabled: false,
old: driverWithNothing,
update: driverWithSELinuxMountEnabled,
wantSELinuxMount: nil,
},
{
name: "SELinux mount support feature disabled, before: off, update: on",
seLinuxMountReadWriteOncePodEnabled: false,
old: driverWithSELinuxMountDisabled,
update: driverWithSELinuxMountEnabled,
wantSELinuxMount: &enabled,
},
{
name: "SELinux mount support feature enabled, before: on, update: off",
seLinuxMountReadWriteOncePodEnabled: false,
old: driverWithSELinuxMountEnabled,
update: driverWithSELinuxMountDisabled,
wantSELinuxMount: &disabled,
},
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, test.csiInlineVolumeEnabled)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, test.csiInlineVolumeEnabled)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, test.seLinuxMountReadWriteOncePodEnabled)()
csiDriver := test.update.DeepCopy() csiDriver := test.update.DeepCopy()
Strategy.PrepareForUpdate(ctx, csiDriver, test.old) Strategy.PrepareForUpdate(ctx, csiDriver, test.old)
@ -276,9 +337,9 @@ func TestCSIDriverPrepareForUpdate(t *testing.T) {
require.Equal(t, test.wantModes, csiDriver.Spec.VolumeLifecycleModes) require.Equal(t, test.wantModes, csiDriver.Spec.VolumeLifecycleModes)
require.Equal(t, test.wantTokenRequests, csiDriver.Spec.TokenRequests) require.Equal(t, test.wantTokenRequests, csiDriver.Spec.TokenRequests)
require.Equal(t, test.wantRequiresRepublish, csiDriver.Spec.RequiresRepublish) require.Equal(t, test.wantRequiresRepublish, csiDriver.Spec.RequiresRepublish)
require.Equal(t, test.wantSELinuxMount, csiDriver.Spec.SELinuxMounted)
}) })
} }
} }
func TestCSIDriverValidation(t *testing.T) { func TestCSIDriverValidation(t *testing.T) {

View File

@ -392,6 +392,27 @@ type CSIDriverSpec struct {
// //
// +optional // +optional
RequiresRepublish *bool `json:"requiresRepublish,omitempty" protobuf:"varint,7,opt,name=requiresRepublish"` RequiresRepublish *bool `json:"requiresRepublish,omitempty" protobuf:"varint,7,opt,name=requiresRepublish"`
// SELinuxMount specifies if the CSI driver supports "-o context"
// mount option.
//
// When "true", the CSI driver must ensure that all volumes provided by this CSI
// driver can be mounted separately with different `-o context` options. This is
// typical for storage backends that provide volumes as filesystems on block
// devices or as independent shared volumes.
// Kubernetes will call NodeStage / NodePublish with "-o context=xyz" mount
// option when mounting a ReadWriteOncePod volume used in Pod that has
// explicitly set SELinux context. In the future, it may be expanded to other
// volume AccessModes. In any case, Kubernetes will ensure that the volume is
// mounted only with a single SELinux context.
//
// When "false", Kubernetes won't pass any special SELinux mount options to the driver.
// This is typical for volumes that represent subdirectories of a bigger shared filesystem.
//
// Default is "false".
//
// +optional
SELinuxMount *bool `json:"seLinuxMount,omitempty" protobuf:"varint,8,opt,name=seLinuxMount"`
} }
// FSGroupPolicy specifies if a CSI Driver supports modifying // FSGroupPolicy specifies if a CSI Driver supports modifying

View File

@ -410,6 +410,27 @@ type CSIDriverSpec struct {
// //
// +optional // +optional
RequiresRepublish *bool `json:"requiresRepublish,omitempty" protobuf:"varint,7,opt,name=requiresRepublish"` RequiresRepublish *bool `json:"requiresRepublish,omitempty" protobuf:"varint,7,opt,name=requiresRepublish"`
// SELinuxMount specifies if the CSI driver supports "-o context"
// mount option.
//
// When "true", the CSI driver must ensure that all volumes provided by this CSI
// driver can be mounted separately with different `-o context` options. This is
// typical for storage backends that provide volumes as filesystems on block
// devices or as independent shared volumes.
// Kubernetes will call NodeStage / NodePublish with "-o context=xyz" mount
// option when mounting a ReadWriteOncePod volume used in Pod that has
// explicitly set SELinux context. In the future, it may be expanded to other
// volume AccessModes. In any case, Kubernetes will ensure that the volume is
// mounted only with a single SELinux context.
//
// When "false", Kubernetes won't pass any special SELinux mount options to the driver.
// This is typical for volumes that represent subdirectories of a bigger shared filesystem.
//
// Default is "false".
//
// +optional
SELinuxMount *bool `json:"seLinuxMount,omitempty" protobuf:"varint,8,opt,name=seLinuxMount"`
} }
// FSGroupPolicy specifies if a CSI Driver supports modifying // FSGroupPolicy specifies if a CSI Driver supports modifying