Graduate ReadWriteOncePod to GA

This commit is contained in:
Chris Henzie 2023-10-11 10:56:00 -07:00
parent f7cb8a5e8a
commit 2dbd405583
16 changed files with 93 additions and 359 deletions

View File

@ -1653,33 +1653,20 @@ var allowedTemplateObjectMetaFields = map[string]bool{
// PersistentVolumeSpecValidationOptions contains the different settings for PeristentVolume validation // PersistentVolumeSpecValidationOptions contains the different settings for PeristentVolume validation
type PersistentVolumeSpecValidationOptions struct { type PersistentVolumeSpecValidationOptions struct {
// Allow spec to contain the "ReadWiteOncePod" access mode
AllowReadWriteOncePod bool
} }
// ValidatePersistentVolumeName checks that a name is appropriate for a // ValidatePersistentVolumeName checks that a name is appropriate for a
// PersistentVolumeName object. // PersistentVolumeName object.
var ValidatePersistentVolumeName = apimachineryvalidation.NameIsDNSSubdomain var ValidatePersistentVolumeName = apimachineryvalidation.NameIsDNSSubdomain
var supportedAccessModes = sets.NewString(string(core.ReadWriteOnce), string(core.ReadOnlyMany), string(core.ReadWriteMany)) var supportedAccessModes = sets.NewString(string(core.ReadWriteOnce), string(core.ReadOnlyMany), string(core.ReadWriteMany), string(core.ReadWriteOncePod))
var supportedReclaimPolicy = sets.NewString(string(core.PersistentVolumeReclaimDelete), string(core.PersistentVolumeReclaimRecycle), string(core.PersistentVolumeReclaimRetain)) var supportedReclaimPolicy = sets.NewString(string(core.PersistentVolumeReclaimDelete), string(core.PersistentVolumeReclaimRecycle), string(core.PersistentVolumeReclaimRetain))
var supportedVolumeModes = sets.NewString(string(core.PersistentVolumeBlock), string(core.PersistentVolumeFilesystem)) var supportedVolumeModes = sets.NewString(string(core.PersistentVolumeBlock), string(core.PersistentVolumeFilesystem))
func ValidationOptionsForPersistentVolume(pv, oldPv *core.PersistentVolume) PersistentVolumeSpecValidationOptions { func ValidationOptionsForPersistentVolume(pv, oldPv *core.PersistentVolume) PersistentVolumeSpecValidationOptions {
opts := PersistentVolumeSpecValidationOptions{ return PersistentVolumeSpecValidationOptions{}
AllowReadWriteOncePod: utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod),
}
if oldPv == nil {
// If there's no old PV, use the options based solely on feature enablement
return opts
}
if helper.ContainsAccessMode(oldPv.Spec.AccessModes, core.ReadWriteOncePod) {
// If the old object allowed "ReadWriteOncePod", continue to allow it in the new object
opts.AllowReadWriteOncePod = true
}
return opts
} }
func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName string, validateInlinePersistentVolumeSpec bool, fldPath *field.Path, opts PersistentVolumeSpecValidationOptions) field.ErrorList { func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName string, validateInlinePersistentVolumeSpec bool, fldPath *field.Path, opts PersistentVolumeSpecValidationOptions) field.ErrorList {
@ -1701,15 +1688,10 @@ func ValidatePersistentVolumeSpec(pvSpec *core.PersistentVolumeSpec, pvName stri
allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), "")) allErrs = append(allErrs, field.Required(fldPath.Child("accessModes"), ""))
} }
expandedSupportedAccessModes := sets.StringKeySet(supportedAccessModes)
if opts.AllowReadWriteOncePod {
expandedSupportedAccessModes.Insert(string(core.ReadWriteOncePod))
}
foundReadWriteOncePod, foundNonReadWriteOncePod := false, false foundReadWriteOncePod, foundNonReadWriteOncePod := false, false
for _, mode := range pvSpec.AccessModes { for _, mode := range pvSpec.AccessModes {
if !expandedSupportedAccessModes.Has(string(mode)) { if !supportedAccessModes.Has(string(mode)) {
allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, expandedSupportedAccessModes.List())) allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, supportedAccessModes.List()))
} }
if mode == core.ReadWriteOncePod { if mode == core.ReadWriteOncePod {
@ -2016,8 +1998,6 @@ func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *core.PersistentVolume) f
} }
type PersistentVolumeClaimSpecValidationOptions struct { type PersistentVolumeClaimSpecValidationOptions struct {
// Allow spec to contain the "ReadWiteOncePod" access mode
AllowReadWriteOncePod bool
// Allow users to recover from previously failing expansion operation // Allow users to recover from previously failing expansion operation
EnableRecoverFromExpansionFailure bool EnableRecoverFromExpansionFailure bool
// Allow to validate the label value of the label selector // Allow to validate the label value of the label selector
@ -2028,7 +2008,6 @@ type PersistentVolumeClaimSpecValidationOptions struct {
func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolumeClaim) PersistentVolumeClaimSpecValidationOptions { func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolumeClaim) PersistentVolumeClaimSpecValidationOptions {
opts := PersistentVolumeClaimSpecValidationOptions{ opts := PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod),
EnableRecoverFromExpansionFailure: utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure), EnableRecoverFromExpansionFailure: utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure),
AllowInvalidLabelValueInSelector: false, AllowInvalidLabelValueInSelector: false,
} }
@ -2048,11 +2027,6 @@ func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolum
opts.AllowInvalidLabelValueInSelector = true opts.AllowInvalidLabelValueInSelector = true
} }
if helper.ContainsAccessMode(oldPvc.Spec.AccessModes, core.ReadWriteOncePod) {
// If the old object allowed "ReadWriteOncePod", continue to allow it in the new object
opts.AllowReadWriteOncePod = true
}
if helper.ClaimContainsAllocatedResources(oldPvc) || if helper.ClaimContainsAllocatedResources(oldPvc) ||
helper.ClaimContainsAllocatedResourceStatus(oldPvc) { helper.ClaimContainsAllocatedResourceStatus(oldPvc) {
opts.EnableRecoverFromExpansionFailure = true opts.EnableRecoverFromExpansionFailure = true
@ -2062,7 +2036,6 @@ func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolum
func ValidationOptionsForPersistentVolumeClaimTemplate(claimTemplate, oldClaimTemplate *core.PersistentVolumeClaimTemplate) PersistentVolumeClaimSpecValidationOptions { func ValidationOptionsForPersistentVolumeClaimTemplate(claimTemplate, oldClaimTemplate *core.PersistentVolumeClaimTemplate) PersistentVolumeClaimSpecValidationOptions {
opts := PersistentVolumeClaimSpecValidationOptions{ opts := PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod),
AllowInvalidLabelValueInSelector: false, AllowInvalidLabelValueInSelector: false,
} }
if oldClaimTemplate == nil { if oldClaimTemplate == nil {
@ -2076,10 +2049,6 @@ func ValidationOptionsForPersistentVolumeClaimTemplate(claimTemplate, oldClaimTe
// If the old object had an invalid label selector, continue to allow it in the new object // If the old object had an invalid label selector, continue to allow it in the new object
opts.AllowInvalidLabelValueInSelector = true opts.AllowInvalidLabelValueInSelector = true
} }
if helper.ContainsAccessMode(oldClaimTemplate.Spec.AccessModes, core.ReadWriteOncePod) {
// If the old object allowed "ReadWriteOncePod", continue to allow it in the new object
opts.AllowReadWriteOncePod = true
}
return opts return opts
} }
@ -2172,15 +2141,10 @@ func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fld
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, labelSelectorValidationOpts, fldPath.Child("selector"))...) allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, labelSelectorValidationOpts, fldPath.Child("selector"))...)
} }
expandedSupportedAccessModes := sets.StringKeySet(supportedAccessModes)
if opts.AllowReadWriteOncePod {
expandedSupportedAccessModes.Insert(string(core.ReadWriteOncePod))
}
foundReadWriteOncePod, foundNonReadWriteOncePod := false, false foundReadWriteOncePod, foundNonReadWriteOncePod := false, false
for _, mode := range spec.AccessModes { for _, mode := range spec.AccessModes {
if !expandedSupportedAccessModes.Has(string(mode)) { if !supportedAccessModes.Has(string(mode)) {
allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, expandedSupportedAccessModes.List())) allErrs = append(allErrs, field.NotSupported(fldPath.Child("accessModes"), mode, supportedAccessModes.List()))
} }
if mode == core.ReadWriteOncePod { if mode == core.ReadWriteOncePod {

View File

@ -109,9 +109,8 @@ func TestValidatePersistentVolumes(t *testing.T) {
validMode := core.PersistentVolumeFilesystem validMode := core.PersistentVolumeFilesystem
invalidMode := core.PersistentVolumeMode("fakeVolumeMode") invalidMode := core.PersistentVolumeMode("fakeVolumeMode")
scenarios := map[string]struct { scenarios := map[string]struct {
isExpectedFailure bool isExpectedFailure bool
enableReadWriteOncePod bool volume *core.PersistentVolume
volume *core.PersistentVolume
}{ }{
"good-volume": { "good-volume": {
isExpectedFailure: false, isExpectedFailure: false,
@ -253,9 +252,8 @@ func TestValidatePersistentVolumes(t *testing.T) {
VolumeMode: &invalidMode, VolumeMode: &invalidMode,
}), }),
}, },
"with-read-write-once-pod-feature-gate-enabled": { "with-read-write-once-pod": {
isExpectedFailure: false, isExpectedFailure: false,
enableReadWriteOncePod: true,
volume: testVolume("foo", "", core.PersistentVolumeSpec{ volume: testVolume("foo", "", core.PersistentVolumeSpec{
Capacity: core.ResourceList{ Capacity: core.ResourceList{
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"), core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
@ -269,25 +267,8 @@ func TestValidatePersistentVolumes(t *testing.T) {
}, },
}), }),
}, },
"with-read-write-once-pod-feature-gate-disabled": { "with-read-write-once-pod-and-others": {
isExpectedFailure: true, isExpectedFailure: true,
enableReadWriteOncePod: false,
volume: testVolume("foo", "", core.PersistentVolumeSpec{
Capacity: core.ResourceList{
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
},
AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod"},
PersistentVolumeSource: core.PersistentVolumeSource{
HostPath: &core.HostPathVolumeSource{
Path: "/foo",
Type: newHostPathType(string(core.HostPathDirectory)),
},
},
}),
},
"with-read-write-once-pod-and-others-feature-gate-enabled": {
isExpectedFailure: true,
enableReadWriteOncePod: true,
volume: testVolume("foo", "", core.PersistentVolumeSpec{ volume: testVolume("foo", "", core.PersistentVolumeSpec{
Capacity: core.ResourceList{ Capacity: core.ResourceList{
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"), core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
@ -501,8 +482,6 @@ func TestValidatePersistentVolumes(t *testing.T) {
for name, scenario := range scenarios { for name, scenario := range scenarios {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, scenario.enableReadWriteOncePod)()
opts := ValidationOptionsForPersistentVolume(scenario.volume, nil) opts := ValidationOptionsForPersistentVolume(scenario.volume, nil)
errs := ValidatePersistentVolume(scenario.volume, opts) errs := ValidatePersistentVolume(scenario.volume, opts)
if len(errs) == 0 && scenario.isExpectedFailure { if len(errs) == 0 && scenario.isExpectedFailure {
@ -903,51 +882,17 @@ func TestValidatePersistentVolumeSourceUpdate(t *testing.T) {
func TestValidationOptionsForPersistentVolume(t *testing.T) { func TestValidationOptionsForPersistentVolume(t *testing.T) {
tests := map[string]struct { tests := map[string]struct {
oldPv *core.PersistentVolume oldPv *core.PersistentVolume
enableReadWriteOncePod bool expectValidationOpts PersistentVolumeSpecValidationOptions
expectValidationOpts PersistentVolumeSpecValidationOptions
}{ }{
"nil old pv": { "nil old pv": {
oldPv: nil, oldPv: nil,
enableReadWriteOncePod: true, expectValidationOpts: PersistentVolumeSpecValidationOptions{},
expectValidationOpts: PersistentVolumeSpecValidationOptions{
AllowReadWriteOncePod: true,
},
},
"rwop allowed because feature enabled": {
oldPv: pvWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}),
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeSpecValidationOptions{
AllowReadWriteOncePod: true,
},
},
"rwop not allowed because not used and feature disabled": {
oldPv: pvWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}),
enableReadWriteOncePod: false,
expectValidationOpts: PersistentVolumeSpecValidationOptions{
AllowReadWriteOncePod: false,
},
},
"rwop allowed because used and feature enabled": {
oldPv: pvWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}),
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeSpecValidationOptions{
AllowReadWriteOncePod: true,
},
},
"rwop allowed because used and feature disabled": {
oldPv: pvWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}),
enableReadWriteOncePod: false,
expectValidationOpts: PersistentVolumeSpecValidationOptions{
AllowReadWriteOncePod: true,
},
}, },
} }
for name, tc := range tests { for name, tc := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tc.enableReadWriteOncePod)()
opts := ValidationOptionsForPersistentVolume(nil, tc.oldPv) opts := ValidationOptionsForPersistentVolume(nil, tc.oldPv)
if opts != tc.expectValidationOpts { if opts != tc.expectValidationOpts {
t.Errorf("Expected opts: %+v, received: %+v", opts, tc.expectValidationOpts) t.Errorf("Expected opts: %+v, received: %+v", opts, tc.expectValidationOpts)
@ -973,29 +918,6 @@ func getCSIVolumeWithSecret(pv *core.PersistentVolume, secret *core.SecretRefere
return pvCopy return pvCopy
} }
func pvWithAccessModes(accessModes []core.PersistentVolumeAccessMode) *core.PersistentVolume {
return &core.PersistentVolume{
Spec: core.PersistentVolumeSpec{
AccessModes: accessModes,
},
}
}
func pvcWithAccessModes(accessModes []core.PersistentVolumeAccessMode) *core.PersistentVolumeClaim {
return &core.PersistentVolumeClaim{
Spec: core.PersistentVolumeClaimSpec{
AccessModes: accessModes,
},
}
}
func pvcTemplateWithAccessModes(accessModes []core.PersistentVolumeAccessMode) *core.PersistentVolumeClaimTemplate {
return &core.PersistentVolumeClaimTemplate{
Spec: core.PersistentVolumeClaimSpec{
AccessModes: accessModes,
},
}
}
func pvcWithDataSource(dataSource *core.TypedLocalObjectReference) *core.PersistentVolumeClaim { func pvcWithDataSource(dataSource *core.TypedLocalObjectReference) *core.PersistentVolumeClaim {
return &core.PersistentVolumeClaim{ return &core.PersistentVolumeClaim{
@ -1594,9 +1516,8 @@ func testValidatePVC(t *testing.T, ephemeral bool) {
ten := int64(10) ten := int64(10)
scenarios := map[string]struct { scenarios := map[string]struct {
isExpectedFailure bool isExpectedFailure bool
enableReadWriteOncePod bool claim *core.PersistentVolumeClaim
claim *core.PersistentVolumeClaim
}{ }{
"good-claim": { "good-claim": {
isExpectedFailure: false, isExpectedFailure: false,
@ -1734,9 +1655,8 @@ func testValidatePVC(t *testing.T, ephemeral bool) {
return claim return claim
}(), }(),
}, },
"with-read-write-once-pod-feature-gate-enabled": { "with-read-write-once-pod": {
isExpectedFailure: false, isExpectedFailure: false,
enableReadWriteOncePod: true,
claim: testVolumeClaim(goodName, goodNS, core.PersistentVolumeClaimSpec{ claim: testVolumeClaim(goodName, goodNS, core.PersistentVolumeClaimSpec{
AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod"}, AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod"},
Resources: core.VolumeResourceRequirements{ Resources: core.VolumeResourceRequirements{
@ -1746,21 +1666,8 @@ func testValidatePVC(t *testing.T, ephemeral bool) {
}, },
}), }),
}, },
"with-read-write-once-pod-feature-gate-disabled": { "with-read-write-once-pod-and-others": {
isExpectedFailure: true, isExpectedFailure: true,
enableReadWriteOncePod: false,
claim: testVolumeClaim(goodName, goodNS, core.PersistentVolumeClaimSpec{
AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod"},
Resources: core.VolumeResourceRequirements{
Requests: core.ResourceList{
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
},
},
}),
},
"with-read-write-once-pod-and-others-feature-gate-enabled": {
isExpectedFailure: true,
enableReadWriteOncePod: true,
claim: testVolumeClaim(goodName, goodNS, core.PersistentVolumeClaimSpec{ claim: testVolumeClaim(goodName, goodNS, core.PersistentVolumeClaimSpec{
AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod", "ReadWriteMany"}, AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteOncePod", "ReadWriteMany"},
Resources: core.VolumeResourceRequirements{ Resources: core.VolumeResourceRequirements{
@ -1991,8 +1898,6 @@ func testValidatePVC(t *testing.T, ephemeral bool) {
for name, scenario := range scenarios { for name, scenario := range scenarios {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, scenario.enableReadWriteOncePod)()
var errs field.ErrorList var errs field.ErrorList
if ephemeral { if ephemeral {
volumes := []core.Volume{{ volumes := []core.Volume{{
@ -2754,47 +2659,12 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) {
invaildAPIGroup := "^invalid" invaildAPIGroup := "^invalid"
tests := map[string]struct { tests := map[string]struct {
oldPvc *core.PersistentVolumeClaim oldPvc *core.PersistentVolumeClaim
enableReadWriteOncePod bool expectValidationOpts PersistentVolumeClaimSpecValidationOptions
expectValidationOpts PersistentVolumeClaimSpecValidationOptions
}{ }{
"nil pv": { "nil pv": {
oldPvc: nil, oldPvc: nil,
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{ expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
EnableRecoverFromExpansionFailure: false,
},
},
"rwop allowed because feature enabled": {
oldPvc: pvcWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}),
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
EnableRecoverFromExpansionFailure: false,
},
},
"rwop not allowed because not used and feature disabled": {
oldPvc: pvcWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}),
enableReadWriteOncePod: false,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: false,
EnableRecoverFromExpansionFailure: false,
},
},
"rwop allowed because used and feature enabled": {
oldPvc: pvcWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}),
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
EnableRecoverFromExpansionFailure: false,
},
},
"rwop allowed because used and feature disabled": {
oldPvc: pvcWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}),
enableReadWriteOncePod: false,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
EnableRecoverFromExpansionFailure: false, EnableRecoverFromExpansionFailure: false,
}, },
}, },
@ -2814,8 +2684,6 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) {
for name, tc := range tests { for name, tc := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tc.enableReadWriteOncePod)()
opts := ValidationOptionsForPersistentVolumeClaim(nil, tc.oldPvc) opts := ValidationOptionsForPersistentVolumeClaim(nil, tc.oldPvc)
if opts != tc.expectValidationOpts { if opts != tc.expectValidationOpts {
t.Errorf("Expected opts: %+v, received: %+v", tc.expectValidationOpts, opts) t.Errorf("Expected opts: %+v, received: %+v", tc.expectValidationOpts, opts)
@ -2826,51 +2694,17 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) {
func TestValidationOptionsForPersistentVolumeClaimTemplate(t *testing.T) { func TestValidationOptionsForPersistentVolumeClaimTemplate(t *testing.T) {
tests := map[string]struct { tests := map[string]struct {
oldPvcTemplate *core.PersistentVolumeClaimTemplate oldPvcTemplate *core.PersistentVolumeClaimTemplate
enableReadWriteOncePod bool expectValidationOpts PersistentVolumeClaimSpecValidationOptions
expectValidationOpts PersistentVolumeClaimSpecValidationOptions
}{ }{
"nil pv": { "nil pv": {
oldPvcTemplate: nil, oldPvcTemplate: nil,
enableReadWriteOncePod: true, expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{},
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
},
},
"rwop allowed because feature enabled": {
oldPvcTemplate: pvcTemplateWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}),
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
},
},
"rwop not allowed because not used and feature disabled": {
oldPvcTemplate: pvcTemplateWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOnce}),
enableReadWriteOncePod: false,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: false,
},
},
"rwop allowed because used and feature enabled": {
oldPvcTemplate: pvcTemplateWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}),
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
},
},
"rwop allowed because used and feature disabled": {
oldPvcTemplate: pvcTemplateWithAccessModes([]core.PersistentVolumeAccessMode{core.ReadWriteOncePod}),
enableReadWriteOncePod: false,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
},
}, },
} }
for name, tc := range tests { for name, tc := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tc.enableReadWriteOncePod)()
opts := ValidationOptionsForPersistentVolumeClaimTemplate(nil, tc.oldPvcTemplate) opts := ValidationOptionsForPersistentVolumeClaimTemplate(nil, tc.oldPvcTemplate)
if opts != tc.expectValidationOpts { if opts != tc.expectValidationOpts {
t.Errorf("Expected opts: %+v, received: %+v", opts, tc.expectValidationOpts) t.Errorf("Expected opts: %+v, received: %+v", opts, tc.expectValidationOpts)

View File

@ -670,6 +670,7 @@ const (
// kep: https://kep.k8s.io/2485 // kep: https://kep.k8s.io/2485
// alpha: v1.22 // alpha: v1.22
// beta: v1.27 // beta: v1.27
// GA: v1.29
// //
// Enables usage of the ReadWriteOncePod PersistentVolume access mode. // Enables usage of the ReadWriteOncePod PersistentVolume access mode.
ReadWriteOncePod featuregate.Feature = "ReadWriteOncePod" ReadWriteOncePod featuregate.Feature = "ReadWriteOncePod"
@ -1046,7 +1047,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
QOSReserved: {Default: false, PreRelease: featuregate.Alpha}, QOSReserved: {Default: false, PreRelease: featuregate.Alpha},
ReadWriteOncePod: {Default: true, PreRelease: featuregate.Beta}, ReadWriteOncePod: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
RecoverVolumeExpansionFailure: {Default: false, PreRelease: featuregate.Alpha}, RecoverVolumeExpansionFailure: {Default: false, PreRelease: featuregate.Alpha},

View File

@ -877,7 +877,6 @@ func Test_MarkDeviceAsMounted_Positive_NewVolume(t *testing.T) {
// Verifies volume/pod combo exist using PodExistsInVolume() // Verifies volume/pod combo exist using PodExistsInVolume()
func Test_AddPodToVolume_Positive_SELinux(t *testing.T) { func Test_AddPodToVolume_Positive_SELinux(t *testing.T) {
// Arrange // Arrange
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
@ -956,7 +955,6 @@ func Test_AddPodToVolume_Positive_SELinux(t *testing.T) {
// Verifies newly added volume exists in GetGloballyMountedVolumes() // Verifies newly added volume exists in GetGloballyMountedVolumes()
func Test_MarkDeviceAsMounted_Positive_SELinux(t *testing.T) { func Test_MarkDeviceAsMounted_Positive_SELinux(t *testing.T) {
// Arrange // Arrange
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t) volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)

View File

@ -609,7 +609,6 @@ func Test_AddPodToVolume_WithEmptyDirSizeLimit(t *testing.T) {
// Verifies newly added pod/volume exists via PodExistsInVolume() without SELinux context // Verifies newly added pod/volume exists via PodExistsInVolume() without SELinux context
// VolumeExists() and GetVolumesToMount() and no errors. // VolumeExists() and GetVolumesToMount() and no errors.
func Test_AddPodToVolume_Positive_SELinuxNoRWOP(t *testing.T) { func Test_AddPodToVolume_Positive_SELinuxNoRWOP(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
// Arrange // Arrange
plugins := []volume.VolumePlugin{ plugins := []volume.VolumePlugin{
@ -690,7 +689,6 @@ func Test_AddPodToVolume_Positive_SELinuxNoRWOP(t *testing.T) {
// Verifies newly added pod/volume exists via PodExistsInVolume() without SELinux context // Verifies newly added pod/volume exists via PodExistsInVolume() without SELinux context
// VolumeExists() and GetVolumesToMount() and no errors. // VolumeExists() and GetVolumesToMount() and no errors.
func Test_AddPodToVolume_Positive_NoSELinuxPlugin(t *testing.T) { func Test_AddPodToVolume_Positive_NoSELinuxPlugin(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
// Arrange // Arrange
plugins := []volume.VolumePlugin{ plugins := []volume.VolumePlugin{
@ -772,7 +770,6 @@ func Test_AddPodToVolume_Positive_NoSELinuxPlugin(t *testing.T) {
// Verifies newly added pod/volume exists via PodExistsInVolume() // Verifies newly added pod/volume exists via PodExistsInVolume()
// VolumeExists() and GetVolumesToMount() and no errors. // VolumeExists() and GetVolumesToMount() and no errors.
func Test_AddPodToVolume_Positive_ExistingPodSameSELinuxRWOP(t *testing.T) { func Test_AddPodToVolume_Positive_ExistingPodSameSELinuxRWOP(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
// Arrange // Arrange
plugins := []volume.VolumePlugin{ plugins := []volume.VolumePlugin{
@ -873,7 +870,6 @@ func Test_AddPodToVolume_Positive_ExistingPodSameSELinuxRWOP(t *testing.T) {
// Verifies newly added pod/volume exists via PodExistsInVolume() // Verifies newly added pod/volume exists via PodExistsInVolume()
// VolumeExists() and GetVolumesToMount() and no errors. // VolumeExists() and GetVolumesToMount() and no errors.
func Test_AddPodToVolume_Negative_ExistingPodDifferentSELinuxRWOP(t *testing.T) { func Test_AddPodToVolume_Negative_ExistingPodDifferentSELinuxRWOP(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
// Arrange // Arrange
plugins := []volume.VolumePlugin{ plugins := []volume.VolumePlugin{

View File

@ -1189,7 +1189,6 @@ func TestCheckVolumeFSResize(t *testing.T) {
} }
func TestCheckVolumeSELinux(t *testing.T) { func TestCheckVolumeSELinux(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
fullOpts := &v1.SELinuxOptions{ fullOpts := &v1.SELinuxOptions{
User: "system_u", User: "system_u",

View File

@ -21,7 +21,6 @@ package feature
// the internal k8s features pkg. // the internal k8s features pkg.
type Features struct { type Features struct {
EnableDynamicResourceAllocation bool EnableDynamicResourceAllocation bool
EnableReadWriteOncePod bool
EnableVolumeCapacityPriority bool EnableVolumeCapacityPriority bool
EnableMinDomainsInPodTopologySpread bool EnableMinDomainsInPodTopologySpread bool
EnableNodeInclusionPolicyInPodTopologySpread bool EnableNodeInclusionPolicyInPodTopologySpread bool

View File

@ -47,7 +47,6 @@ import (
func NewInTreeRegistry() runtime.Registry { func NewInTreeRegistry() runtime.Registry {
fts := plfeature.Features{ fts := plfeature.Features{
EnableDynamicResourceAllocation: feature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation), EnableDynamicResourceAllocation: feature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation),
EnableReadWriteOncePod: feature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod),
EnableVolumeCapacityPriority: feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority), EnableVolumeCapacityPriority: feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority),
EnableMinDomainsInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MinDomainsInPodTopologySpread), EnableMinDomainsInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MinDomainsInPodTopologySpread),
EnableNodeInclusionPolicyInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread), EnableNodeInclusionPolicyInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread),

View File

@ -33,9 +33,8 @@ import (
// VolumeRestrictions is a plugin that checks volume restrictions. // VolumeRestrictions is a plugin that checks volume restrictions.
type VolumeRestrictions struct { type VolumeRestrictions struct {
pvcLister corelisters.PersistentVolumeClaimLister pvcLister corelisters.PersistentVolumeClaimLister
sharedLister framework.SharedLister sharedLister framework.SharedLister
enableReadWriteOncePod bool
} }
var _ framework.PreFilterPlugin = &VolumeRestrictions{} var _ framework.PreFilterPlugin = &VolumeRestrictions{}
@ -169,13 +168,6 @@ func (pl *VolumeRestrictions) PreFilter(ctx context.Context, cycleState *framewo
} }
} }
if !pl.enableReadWriteOncePod {
if needsCheck {
return nil, nil
}
return nil, framework.NewStatus(framework.Skip)
}
pvcs, err := pl.readWriteOncePodPVCsForPod(ctx, pod) pvcs, err := pl.readWriteOncePodPVCsForPod(ctx, pod)
if err != nil { if err != nil {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
@ -198,9 +190,6 @@ func (pl *VolumeRestrictions) PreFilter(ctx context.Context, cycleState *framewo
// AddPod from pre-computed data in cycleState. // AddPod from pre-computed data in cycleState.
func (pl *VolumeRestrictions) AddPod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToAdd *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { func (pl *VolumeRestrictions) AddPod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToAdd *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status {
if !pl.enableReadWriteOncePod {
return nil
}
state, err := getPreFilterState(cycleState) state, err := getPreFilterState(cycleState)
if err != nil { if err != nil {
return framework.AsStatus(err) return framework.AsStatus(err)
@ -211,9 +200,6 @@ func (pl *VolumeRestrictions) AddPod(ctx context.Context, cycleState *framework.
// RemovePod from pre-computed data in cycleState. // RemovePod from pre-computed data in cycleState.
func (pl *VolumeRestrictions) RemovePod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToRemove *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status { func (pl *VolumeRestrictions) RemovePod(ctx context.Context, cycleState *framework.CycleState, podToSchedule *v1.Pod, podInfoToRemove *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status {
if !pl.enableReadWriteOncePod {
return nil
}
state, err := getPreFilterState(cycleState) state, err := getPreFilterState(cycleState)
if err != nil { if err != nil {
return framework.AsStatus(err) return framework.AsStatus(err)
@ -321,9 +307,6 @@ func (pl *VolumeRestrictions) Filter(ctx context.Context, cycleState *framework.
if !satisfyVolumeConflicts(pod, nodeInfo) { if !satisfyVolumeConflicts(pod, nodeInfo) {
return framework.NewStatus(framework.Unschedulable, ErrReasonDiskConflict) return framework.NewStatus(framework.Unschedulable, ErrReasonDiskConflict)
} }
if !pl.enableReadWriteOncePod {
return nil
}
state, err := getPreFilterState(cycleState) state, err := getPreFilterState(cycleState)
if err != nil { if err != nil {
return framework.AsStatus(err) return framework.AsStatus(err)
@ -354,8 +337,7 @@ func New(_ context.Context, _ runtime.Object, handle framework.Handle, fts featu
sharedLister := handle.SnapshotSharedLister() sharedLister := handle.SnapshotSharedLister()
return &VolumeRestrictions{ return &VolumeRestrictions{
pvcLister: pvcLister, pvcLister: pvcLister,
sharedLister: sharedLister, sharedLister: sharedLister,
enableReadWriteOncePod: fts.EnableReadWriteOncePod,
}, nil }, nil
} }

View File

@ -24,9 +24,6 @@ import (
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/scheduler/apis/config" "k8s.io/kubernetes/pkg/scheduler/apis/config"
"k8s.io/kubernetes/pkg/scheduler/framework" "k8s.io/kubernetes/pkg/scheduler/framework"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature"
@ -355,8 +352,6 @@ func TestISCSIDiskConflicts(t *testing.T) {
} }
func TestAccessModeConflicts(t *testing.T) { func TestAccessModeConflicts(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
// Required for querying lister for PVCs in the same namespace. // Required for querying lister for PVCs in the same namespace.
podWithOnePVC := st.MakePod().Name("pod-with-one-pvc").Namespace(metav1.NamespaceDefault).PVC("claim-with-rwop-1").Node("node-1").Obj() podWithOnePVC := st.MakePod().Name("pod-with-one-pvc").Namespace(metav1.NamespaceDefault).PVC("claim-with-rwop-1").Node("node-1").Obj()
podWithTwoPVCs := st.MakePod().Name("pod-with-two-pvcs").Namespace(metav1.NamespaceDefault).PVC("claim-with-rwop-1").PVC("claim-with-rwop-2").Node("node-1").Obj() podWithTwoPVCs := st.MakePod().Name("pod-with-two-pvcs").Namespace(metav1.NamespaceDefault).PVC("claim-with-rwop-1").PVC("claim-with-rwop-2").Node("node-1").Obj()
@ -401,81 +396,64 @@ func TestAccessModeConflicts(t *testing.T) {
} }
tests := []struct { tests := []struct {
name string name string
pod *v1.Pod pod *v1.Pod
nodeInfo *framework.NodeInfo nodeInfo *framework.NodeInfo
existingPods []*v1.Pod existingPods []*v1.Pod
existingNodes []*v1.Node existingNodes []*v1.Node
existingPVCs []*v1.PersistentVolumeClaim existingPVCs []*v1.PersistentVolumeClaim
enableReadWriteOncePod bool preFilterWantStatus *framework.Status
preFilterWantStatus *framework.Status wantStatus *framework.Status
wantStatus *framework.Status
}{ }{
{ {
name: "nothing", name: "nothing",
pod: &v1.Pod{}, pod: &v1.Pod{},
nodeInfo: framework.NewNodeInfo(), nodeInfo: framework.NewNodeInfo(),
existingPods: []*v1.Pod{}, existingPods: []*v1.Pod{},
existingNodes: []*v1.Node{}, existingNodes: []*v1.Node{},
existingPVCs: []*v1.PersistentVolumeClaim{}, existingPVCs: []*v1.PersistentVolumeClaim{},
enableReadWriteOncePod: true, preFilterWantStatus: framework.NewStatus(framework.Skip),
preFilterWantStatus: framework.NewStatus(framework.Skip), wantStatus: nil,
wantStatus: nil,
}, },
{ {
name: "nothing, ReadWriteOncePod disabled", name: "failed to get PVC",
pod: &v1.Pod{}, pod: podWithOnePVC,
nodeInfo: framework.NewNodeInfo(), nodeInfo: framework.NewNodeInfo(),
existingPods: []*v1.Pod{}, existingPods: []*v1.Pod{},
existingNodes: []*v1.Node{}, existingNodes: []*v1.Node{},
existingPVCs: []*v1.PersistentVolumeClaim{}, existingPVCs: []*v1.PersistentVolumeClaim{},
enableReadWriteOncePod: false, preFilterWantStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, "persistentvolumeclaim \"claim-with-rwop-1\" not found"),
preFilterWantStatus: framework.NewStatus(framework.Skip), wantStatus: nil,
wantStatus: nil,
}, },
{ {
name: "failed to get PVC", name: "no access mode conflict",
pod: podWithOnePVC, pod: podWithOnePVC,
nodeInfo: framework.NewNodeInfo(), nodeInfo: framework.NewNodeInfo(podWithReadWriteManyPVC),
existingPods: []*v1.Pod{}, existingPods: []*v1.Pod{podWithReadWriteManyPVC},
existingNodes: []*v1.Node{}, existingNodes: []*v1.Node{node},
existingPVCs: []*v1.PersistentVolumeClaim{}, existingPVCs: []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteManyPVC},
enableReadWriteOncePod: true, preFilterWantStatus: framework.NewStatus(framework.Skip),
preFilterWantStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, "persistentvolumeclaim \"claim-with-rwop-1\" not found"), wantStatus: nil,
wantStatus: nil,
}, },
{ {
name: "no access mode conflict", name: "access mode conflict, unschedulable",
pod: podWithOnePVC, pod: podWithOneConflict,
nodeInfo: framework.NewNodeInfo(podWithReadWriteManyPVC), nodeInfo: framework.NewNodeInfo(podWithOnePVC, podWithReadWriteManyPVC),
existingPods: []*v1.Pod{podWithReadWriteManyPVC}, existingPods: []*v1.Pod{podWithOnePVC, podWithReadWriteManyPVC},
existingNodes: []*v1.Node{node}, existingNodes: []*v1.Node{node},
existingPVCs: []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteManyPVC}, existingPVCs: []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteManyPVC},
enableReadWriteOncePod: true, preFilterWantStatus: nil,
preFilterWantStatus: framework.NewStatus(framework.Skip), wantStatus: framework.NewStatus(framework.Unschedulable, ErrReasonReadWriteOncePodConflict),
wantStatus: nil,
}, },
{ {
name: "access mode conflict, unschedulable", name: "two conflicts, unschedulable",
pod: podWithOneConflict, pod: podWithTwoConflicts,
nodeInfo: framework.NewNodeInfo(podWithOnePVC, podWithReadWriteManyPVC), nodeInfo: framework.NewNodeInfo(podWithTwoPVCs, podWithReadWriteManyPVC),
existingPods: []*v1.Pod{podWithOnePVC, podWithReadWriteManyPVC}, existingPods: []*v1.Pod{podWithTwoPVCs, podWithReadWriteManyPVC},
existingNodes: []*v1.Node{node}, existingNodes: []*v1.Node{node},
existingPVCs: []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteManyPVC}, existingPVCs: []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteOncePodPVC2, readWriteManyPVC},
enableReadWriteOncePod: true, preFilterWantStatus: nil,
preFilterWantStatus: nil, wantStatus: framework.NewStatus(framework.Unschedulable, ErrReasonReadWriteOncePodConflict),
wantStatus: framework.NewStatus(framework.Unschedulable, ErrReasonReadWriteOncePodConflict),
},
{
name: "two conflicts, unschedulable",
pod: podWithTwoConflicts,
nodeInfo: framework.NewNodeInfo(podWithTwoPVCs, podWithReadWriteManyPVC),
existingPods: []*v1.Pod{podWithTwoPVCs, podWithReadWriteManyPVC},
existingNodes: []*v1.Node{node},
existingPVCs: []*v1.PersistentVolumeClaim{readWriteOncePodPVC1, readWriteOncePodPVC2, readWriteManyPVC},
enableReadWriteOncePod: true,
preFilterWantStatus: nil,
wantStatus: framework.NewStatus(framework.Unschedulable, ErrReasonReadWriteOncePodConflict),
}, },
} }
@ -483,7 +461,7 @@ func TestAccessModeConflicts(t *testing.T) {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
p := newPluginWithListers(ctx, t, test.existingPods, test.existingNodes, test.existingPVCs, test.enableReadWriteOncePod) p := newPluginWithListers(ctx, t, test.existingPods, test.existingNodes, test.existingPVCs)
cycleState := framework.NewCycleState() cycleState := framework.NewCycleState()
_, preFilterGotStatus := p.(framework.PreFilterPlugin).PreFilter(ctx, cycleState, test.pod) _, preFilterGotStatus := p.(framework.PreFilterPlugin).PreFilter(ctx, cycleState, test.pod)
if diff := cmp.Diff(test.preFilterWantStatus, preFilterGotStatus); diff != "" { if diff := cmp.Diff(test.preFilterWantStatus, preFilterGotStatus); diff != "" {
@ -501,14 +479,12 @@ func TestAccessModeConflicts(t *testing.T) {
} }
func newPlugin(ctx context.Context, t *testing.T) framework.Plugin { func newPlugin(ctx context.Context, t *testing.T) framework.Plugin {
return newPluginWithListers(ctx, t, nil, nil, nil, true) return newPluginWithListers(ctx, t, nil, nil, nil)
} }
func newPluginWithListers(ctx context.Context, t *testing.T, pods []*v1.Pod, nodes []*v1.Node, pvcs []*v1.PersistentVolumeClaim, enableReadWriteOncePod bool) framework.Plugin { func newPluginWithListers(ctx context.Context, t *testing.T, pods []*v1.Pod, nodes []*v1.Node, pvcs []*v1.PersistentVolumeClaim) framework.Plugin {
pluginFactory := func(ctx context.Context, plArgs runtime.Object, fh framework.Handle) (framework.Plugin, error) { pluginFactory := func(ctx context.Context, plArgs runtime.Object, fh framework.Handle) (framework.Plugin, error) {
return New(ctx, plArgs, fh, feature.Features{ return New(ctx, plArgs, fh, feature.Features{})
EnableReadWriteOncePod: enableReadWriteOncePod,
})
} }
snapshot := cache.NewSnapshot(pods, nodes) snapshot := cache.NewSnapshot(pods, nodes)

View File

@ -370,7 +370,6 @@ func TestPluginConstructVolumeSpec(t *testing.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)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, tc.seLinuxMountEnabled)()
mounter, err := plug.NewMounter( mounter, err := plug.NewMounter(

View File

@ -580,8 +580,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
} }
// Enforce ReadWriteOncePod access mode if it is the only one present. This is also enforced during scheduling. // Enforce ReadWriteOncePod access mode if it is the only one present. This is also enforced during scheduling.
if utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod) && if actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) &&
actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) &&
// Because we do not know what access mode the pod intends to use if there are multiple. // Because we do not know what access mode the pod intends to use if there are multiple.
len(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes) == 1 && len(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes) == 1 &&
v1helper.ContainsAccessMode(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) { v1helper.ContainsAccessMode(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) {
@ -1071,8 +1070,7 @@ func (og *operationGenerator) GenerateMapVolumeFunc(
migrated := getMigratedStatusBySpec(volumeToMount.VolumeSpec) migrated := getMigratedStatusBySpec(volumeToMount.VolumeSpec)
// Enforce ReadWriteOncePod access mode. This is also enforced during scheduling. // Enforce ReadWriteOncePod access mode. This is also enforced during scheduling.
if utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod) && if actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) &&
actualStateOfWorld.IsVolumeMountedElsewhere(volumeToMount.VolumeName, volumeToMount.PodName) &&
// Because we do not know what access mode the pod intends to use if there are multiple. // Because we do not know what access mode the pod intends to use if there are multiple.
len(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes) == 1 && len(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes) == 1 &&
v1helper.ContainsAccessMode(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) { v1helper.ContainsAccessMode(volumeToMount.VolumeSpec.PersistentVolume.Spec.AccessModes, v1.ReadWriteOncePod) {

View File

@ -168,10 +168,6 @@ func SupportsSELinuxContextMount(volumeSpec *volume.Spec, volumePluginMgr *volum
// VolumeSupportsSELinuxMount returns true if given volume access mode can support mount with SELinux mount options. // VolumeSupportsSELinuxMount returns true if given volume access mode can support mount with SELinux mount options.
func VolumeSupportsSELinuxMount(volumeSpec *volume.Spec) bool { func VolumeSupportsSELinuxMount(volumeSpec *volume.Spec) bool {
// Right now, SELinux mount is supported only for ReadWriteOncePod volumes.
if !utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod) {
return false
}
if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) { if !utilfeature.DefaultFeatureGate.Enabled(features.SELinuxMountReadWriteOncePod) {
return false return false
} }

View File

@ -616,7 +616,6 @@ func TestMakeAbsolutePath(t *testing.T) {
} }
func TestGetPodVolumeNames(t *testing.T) { func TestGetPodVolumeNames(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
tests := []struct { tests := []struct {
name string name string

View File

@ -1554,11 +1554,10 @@ var (
func TestUnschedulablePodBecomesSchedulable(t *testing.T) { func TestUnschedulablePodBecomesSchedulable(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
init func(kubernetes.Interface, string) error init func(kubernetes.Interface, string) error
pod *testutils.PausePodConfig pod *testutils.PausePodConfig
update func(kubernetes.Interface, string) error update func(kubernetes.Interface, string) error
enableReadWriteOncePod bool
}{ }{
{ {
name: "node gets added", name: "node gets added",
@ -1765,13 +1764,10 @@ func TestUnschedulablePodBecomesSchedulable(t *testing.T) {
update: func(cs kubernetes.Interface, ns string) error { update: func(cs kubernetes.Interface, ns string) error {
return deletePod(cs, "pod-to-be-deleted", ns) return deletePod(cs, "pod-to-be-deleted", ns)
}, },
enableReadWriteOncePod: true,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ReadWriteOncePod, tt.enableReadWriteOncePod)()
testCtx := initTest(t, "scheduler-informer") testCtx := initTest(t, "scheduler-informer")
if tt.init != nil { if tt.init != nil {

View File

@ -1648,8 +1648,6 @@ func TestPreferNominatedNode(t *testing.T) {
// TestReadWriteOncePodPreemption tests preemption scenarios for pods with // TestReadWriteOncePodPreemption tests preemption scenarios for pods with
// ReadWriteOncePod PVCs. // ReadWriteOncePod PVCs.
func TestReadWriteOncePodPreemption(t *testing.T) { func TestReadWriteOncePodPreemption(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ReadWriteOncePod, true)()
cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{
Profiles: []configv1.KubeSchedulerProfile{{ Profiles: []configv1.KubeSchedulerProfile{{
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),