remove ExpandPersistentVolume feature gate

This commit is contained in:
Hemant Kumar 2022-03-24 10:02:47 -04:00
parent 6d071d6593
commit 9343cce20b
17 changed files with 75 additions and 334 deletions

View File

@ -65,7 +65,6 @@ import (
persistentvolumecontroller "k8s.io/kubernetes/pkg/controller/volume/persistentvolume"
"k8s.io/kubernetes/pkg/controller/volume/pvcprotection"
"k8s.io/kubernetes/pkg/controller/volume/pvprotection"
"k8s.io/kubernetes/pkg/features"
quotainstall "k8s.io/kubernetes/pkg/quota/v1/install"
"k8s.io/kubernetes/pkg/volume/csimigration"
netutils "k8s.io/utils/net"
@ -336,36 +335,34 @@ func startAttachDetachController(ctx context.Context, controllerContext Controll
}
func startVolumeExpandController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {
if utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
plugins, err := ProbeExpandableVolumePlugins(controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration)
if err != nil {
return nil, true, fmt.Errorf("failed to probe volume plugins when starting volume expand controller: %v", err)
}
csiTranslator := csitrans.New()
filteredDialOptions, err := options.ParseVolumeHostFilters(
controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeHostCIDRDenylist,
controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeHostAllowLocalLoopback)
if err != nil {
return nil, true, err
}
expandController, expandControllerErr := expand.NewExpandController(
controllerContext.ClientBuilder.ClientOrDie("expand-controller"),
controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(),
controllerContext.InformerFactory.Core().V1().PersistentVolumes(),
controllerContext.Cloud,
plugins,
csiTranslator,
csimigration.NewPluginManager(csiTranslator, utilfeature.DefaultFeatureGate),
filteredDialOptions,
)
if expandControllerErr != nil {
return nil, true, fmt.Errorf("failed to start volume expand controller: %v", expandControllerErr)
}
go expandController.Run(ctx)
return nil, true, nil
plugins, err := ProbeExpandableVolumePlugins(controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration)
if err != nil {
return nil, true, fmt.Errorf("failed to probe volume plugins when starting volume expand controller: %v", err)
}
return nil, false, nil
csiTranslator := csitrans.New()
filteredDialOptions, err := options.ParseVolumeHostFilters(
controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeHostCIDRDenylist,
controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeHostAllowLocalLoopback)
if err != nil {
return nil, true, err
}
expandController, expandControllerErr := expand.NewExpandController(
controllerContext.ClientBuilder.ClientOrDie("expand-controller"),
controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(),
controllerContext.InformerFactory.Core().V1().PersistentVolumes(),
controllerContext.Cloud,
plugins,
csiTranslator,
csimigration.NewPluginManager(csiTranslator, utilfeature.DefaultFeatureGate),
filteredDialOptions,
)
if expandControllerErr != nil {
return nil, true, fmt.Errorf("failed to start volume expand controller: %v", expandControllerErr)
}
go expandController.Run(ctx)
return nil, true, nil
}
func startEphemeralVolumeController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {

View File

@ -75,10 +75,6 @@ func EnforceDataSourceBackwardsCompatibility(pvcSpec, oldPVCSpec *core.Persisten
}
func DropDisabledFieldsFromStatus(pvc, oldPVC *core.PersistentVolumeClaim) {
if !utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) && oldPVC.Status.Conditions == nil {
pvc.Status.Conditions = nil
}
if !utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure) {
if !allocatedResourcesInUse(oldPVC) {
pvc.Status.AllocatedResources = nil

View File

@ -2022,8 +2022,6 @@ func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *core.PersistentVolume) f
type PersistentVolumeClaimSpecValidationOptions struct {
// Allow spec to contain the "ReadWiteOncePod" access mode
AllowReadWriteOncePod bool
// Allow pvc expansion after PVC is created and bound to a PV
EnableExpansion bool
// Allow users to recover from previously failing expansion operation
EnableRecoverFromExpansionFailure bool
}
@ -2031,7 +2029,6 @@ type PersistentVolumeClaimSpecValidationOptions struct {
func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolumeClaim) PersistentVolumeClaimSpecValidationOptions {
opts := PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod),
EnableExpansion: utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes),
EnableRecoverFromExpansionFailure: utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure),
}
if oldPvc == nil {
@ -2178,40 +2175,30 @@ func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeCl
allErrs = append(allErrs, ValidateImmutableAnnotation(newPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], oldPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], v1.BetaStorageClassAnnotation, field.NewPath("metadata"))...)
}
if opts.EnableExpansion {
// lets make sure storage values are same.
if newPvc.Status.Phase == core.ClaimBound && newPvcClone.Spec.Resources.Requests != nil {
newPvcClone.Spec.Resources.Requests["storage"] = oldPvc.Spec.Resources.Requests["storage"] // +k8s:verify-mutation:reason=clone
}
// lets make sure storage values are same.
if newPvc.Status.Phase == core.ClaimBound && newPvcClone.Spec.Resources.Requests != nil {
newPvcClone.Spec.Resources.Requests["storage"] = oldPvc.Spec.Resources.Requests["storage"] // +k8s:verify-mutation:reason=clone
}
oldSize := oldPvc.Spec.Resources.Requests["storage"]
newSize := newPvc.Spec.Resources.Requests["storage"]
statusSize := oldPvc.Status.Capacity["storage"]
oldSize := oldPvc.Spec.Resources.Requests["storage"]
newSize := newPvc.Spec.Resources.Requests["storage"]
statusSize := oldPvc.Status.Capacity["storage"]
if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) {
specDiff := cmp.Diff(oldPvcClone.Spec, newPvcClone.Spec)
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), fmt.Sprintf("spec is immutable after creation except resources.requests for bound claims\n%v", specDiff)))
}
if newSize.Cmp(oldSize) < 0 {
if !opts.EnableRecoverFromExpansionFailure {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than previous value"))
} else {
// This validation permits reducing pvc requested size up to capacity recorded in pvc.status
// so that users can recover from volume expansion failure, but Kubernetes does not actually
// support volume shrinking
if newSize.Cmp(statusSize) <= 0 {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than status.capacity"))
}
if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) {
specDiff := cmp.Diff(oldPvcClone.Spec, newPvcClone.Spec)
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), fmt.Sprintf("spec is immutable after creation except resources.requests for bound claims\n%v", specDiff)))
}
if newSize.Cmp(oldSize) < 0 {
if !opts.EnableRecoverFromExpansionFailure {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than previous value"))
} else {
// This validation permits reducing pvc requested size up to capacity recorded in pvc.status
// so that users can recover from volume expansion failure, but Kubernetes does not actually
// support volume shrinking
if newSize.Cmp(statusSize) <= 0 {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than status.capacity"))
}
}
} else {
// changes to Spec are not allowed, but updates to label/and some annotations are OK.
// no-op updates pass validation.
if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) {
specDiff := cmp.Diff(oldPvcClone.Spec, newPvcClone.Spec)
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), fmt.Sprintf("field is immutable after creation\n%v", specDiff)))
}
}
allErrs = append(allErrs, ValidateImmutableField(newPvc.Spec.VolumeMode, oldPvc.Spec.VolumeMode, field.NewPath("volumeMode"))...)

View File

@ -2108,215 +2108,173 @@ func TestValidatePersistentVolumeClaimUpdate(t *testing.T) {
isExpectedFailure bool
oldClaim *core.PersistentVolumeClaim
newClaim *core.PersistentVolumeClaim
enableResize bool
enableRecoverFromExpansion bool
}{
"valid-update-volumeName-only": {
isExpectedFailure: false,
oldClaim: validClaim,
newClaim: validUpdateClaim,
enableResize: false,
},
"valid-no-op-update": {
isExpectedFailure: false,
oldClaim: validUpdateClaim,
newClaim: validUpdateClaim,
enableResize: false,
},
"invalid-update-change-resources-on-bound-claim": {
isExpectedFailure: true,
oldClaim: validUpdateClaim,
newClaim: invalidUpdateClaimResources,
enableResize: false,
},
"invalid-update-change-access-modes-on-bound-claim": {
isExpectedFailure: true,
oldClaim: validUpdateClaim,
newClaim: invalidUpdateClaimAccessModes,
enableResize: false,
},
"valid-update-volume-mode-block-to-block": {
isExpectedFailure: false,
oldClaim: validClaimVolumeModeBlock,
newClaim: validClaimVolumeModeBlock,
enableResize: false,
},
"valid-update-volume-mode-file-to-file": {
isExpectedFailure: false,
oldClaim: validClaimVolumeModeFile,
newClaim: validClaimVolumeModeFile,
enableResize: false,
},
"invalid-update-volume-mode-to-block": {
isExpectedFailure: true,
oldClaim: validClaimVolumeModeFile,
newClaim: validClaimVolumeModeBlock,
enableResize: false,
},
"invalid-update-volume-mode-to-file": {
isExpectedFailure: true,
oldClaim: validClaimVolumeModeBlock,
newClaim: validClaimVolumeModeFile,
enableResize: false,
},
"invalid-update-volume-mode-nil-to-file": {
isExpectedFailure: true,
oldClaim: invalidClaimVolumeModeNil,
newClaim: validClaimVolumeModeFile,
enableResize: false,
},
"invalid-update-volume-mode-nil-to-block": {
isExpectedFailure: true,
oldClaim: invalidClaimVolumeModeNil,
newClaim: validClaimVolumeModeBlock,
enableResize: false,
},
"invalid-update-volume-mode-block-to-nil": {
isExpectedFailure: true,
oldClaim: validClaimVolumeModeBlock,
newClaim: invalidClaimVolumeModeNil,
enableResize: false,
},
"invalid-update-volume-mode-file-to-nil": {
isExpectedFailure: true,
oldClaim: validClaimVolumeModeFile,
newClaim: invalidClaimVolumeModeNil,
enableResize: false,
},
"invalid-update-volume-mode-empty-to-mode": {
isExpectedFailure: true,
oldClaim: validClaim,
newClaim: validClaimVolumeModeBlock,
enableResize: false,
},
"invalid-update-volume-mode-mode-to-empty": {
isExpectedFailure: true,
oldClaim: validClaimVolumeModeBlock,
newClaim: validClaim,
enableResize: false,
},
"invalid-update-change-storage-class-annotation-after-creation": {
isExpectedFailure: true,
oldClaim: validClaimStorageClass,
newClaim: invalidUpdateClaimStorageClass,
enableResize: false,
},
"valid-update-mutable-annotation": {
isExpectedFailure: false,
oldClaim: validClaimAnnotation,
newClaim: validUpdateClaimMutableAnnotation,
enableResize: false,
},
"valid-update-add-annotation": {
isExpectedFailure: false,
oldClaim: validClaim,
newClaim: validAddClaimAnnotation,
enableResize: false,
},
"valid-size-update-resize-disabled": {
isExpectedFailure: true,
oldClaim: validClaim,
newClaim: validSizeUpdate,
enableResize: false,
oldClaim: validClaim,
newClaim: validSizeUpdate,
},
"valid-size-update-resize-enabled": {
isExpectedFailure: false,
oldClaim: validClaim,
newClaim: validSizeUpdate,
enableResize: true,
},
"invalid-size-update-resize-enabled": {
isExpectedFailure: true,
oldClaim: validClaim,
newClaim: invalidSizeUpdate,
enableResize: true,
},
"unbound-size-update-resize-enabled": {
isExpectedFailure: true,
oldClaim: validClaim,
newClaim: unboundSizeUpdate,
enableResize: true,
},
"valid-upgrade-storage-class-annotation-to-spec": {
isExpectedFailure: false,
oldClaim: validClaimStorageClass,
newClaim: validClaimStorageClassInSpec,
enableResize: false,
},
"invalid-upgrade-storage-class-annotation-to-spec": {
isExpectedFailure: true,
oldClaim: validClaimStorageClass,
newClaim: invalidClaimStorageClassInSpec,
enableResize: false,
},
"valid-upgrade-storage-class-annotation-to-annotation-and-spec": {
isExpectedFailure: false,
oldClaim: validClaimStorageClass,
newClaim: validClaimStorageClassInAnnotationAndSpec,
enableResize: false,
},
"invalid-upgrade-storage-class-annotation-to-annotation-and-spec": {
isExpectedFailure: true,
oldClaim: validClaimStorageClass,
newClaim: invalidClaimStorageClassInAnnotationAndSpec,
enableResize: false,
},
"invalid-upgrade-storage-class-in-spec": {
isExpectedFailure: true,
oldClaim: validClaimStorageClassInSpec,
newClaim: invalidClaimStorageClassInSpec,
enableResize: false,
},
"invalid-downgrade-storage-class-spec-to-annotation": {
isExpectedFailure: true,
oldClaim: validClaimStorageClassInSpec,
newClaim: validClaimStorageClass,
enableResize: false,
},
"valid-update-rwop-used-and-rwop-feature-disabled": {
isExpectedFailure: false,
oldClaim: validClaimRWOPAccessMode,
newClaim: validClaimRWOPAccessModeAddAnnotation,
enableResize: false,
},
"valid-expand-shrink-resize-enabled": {
oldClaim: validClaimShrinkInitial,
newClaim: validClaimShrink,
enableResize: true,
enableRecoverFromExpansion: true,
},
"invalid-expand-shrink-resize-enabled": {
oldClaim: validClaimShrinkInitial,
newClaim: invalidClaimShrink,
enableResize: true,
enableRecoverFromExpansion: true,
isExpectedFailure: true,
},
"invalid-expand-shrink-to-status-resize-enabled": {
oldClaim: validClaimShrinkInitial,
newClaim: invalidShrinkToStatus,
enableResize: true,
enableRecoverFromExpansion: true,
isExpectedFailure: true,
},
"invalid-expand-shrink-recover-disabled": {
oldClaim: validClaimShrinkInitial,
newClaim: validClaimShrink,
enableResize: true,
enableRecoverFromExpansion: false,
isExpectedFailure: true,
},
"invalid-expand-shrink-resize-disabled": {
oldClaim: validClaimShrinkInitial,
newClaim: validClaimShrink,
enableResize: false,
enableRecoverFromExpansion: true,
isExpectedFailure: true,
},
"unbound-size-shrink-resize-enabled": {
oldClaim: validClaimShrinkInitial,
newClaim: unboundShrink,
enableResize: true,
enableRecoverFromExpansion: true,
isExpectedFailure: true,
},
@ -2324,7 +2282,6 @@ func TestValidatePersistentVolumeClaimUpdate(t *testing.T) {
for name, scenario := range scenarios {
t.Run(name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandPersistentVolumes, scenario.enableResize)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RecoverVolumeExpansionFailure, scenario.enableRecoverFromExpansion)()
scenario.oldClaim.ResourceVersion = "1"
scenario.newClaim.ResourceVersion = "1"
@ -2351,7 +2308,6 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) {
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
EnableExpansion: true,
EnableRecoverFromExpansionFailure: false,
},
},
@ -2360,7 +2316,6 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) {
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
EnableExpansion: true,
EnableRecoverFromExpansionFailure: false,
},
},
@ -2369,7 +2324,6 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) {
enableReadWriteOncePod: false,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: false,
EnableExpansion: true,
EnableRecoverFromExpansionFailure: false,
},
},
@ -2378,7 +2332,6 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) {
enableReadWriteOncePod: true,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
EnableExpansion: true,
EnableRecoverFromExpansionFailure: false,
},
},
@ -2387,7 +2340,6 @@ func TestValidationOptionsForPersistentVolumeClaim(t *testing.T) {
enableReadWriteOncePod: false,
expectValidationOpts: PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: true,
EnableExpansion: true,
EnableRecoverFromExpansionFailure: false,
},
},

View File

@ -1,40 +0,0 @@
/*
Copyright 2017 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 (
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/apis/storage"
"k8s.io/kubernetes/pkg/features"
)
// DropDisabledFields removes disabled fields from the StorageClass object.
func DropDisabledFields(class, oldClass *storage.StorageClass) {
if !utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) && !allowVolumeExpansionInUse(oldClass) {
class.AllowVolumeExpansion = nil
}
}
func allowVolumeExpansionInUse(oldClass *storage.StorageClass) bool {
if oldClass == nil {
return false
}
if oldClass.AllowVolumeExpansion != nil {
return true
}
return false
}

View File

@ -1,108 +0,0 @@
/*
Copyright 2017 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"
"reflect"
"testing"
"k8s.io/apimachinery/pkg/util/diff"
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/pkg/apis/storage"
"k8s.io/kubernetes/pkg/features"
)
func TestDropAllowVolumeExpansion(t *testing.T) {
allowVolumeExpansion := false
scWithoutAllowVolumeExpansion := func() *storage.StorageClass {
return &storage.StorageClass{}
}
scWithAllowVolumeExpansion := func() *storage.StorageClass {
return &storage.StorageClass{
AllowVolumeExpansion: &allowVolumeExpansion,
}
}
scInfo := []struct {
description string
hasAllowVolumeExpansion bool
sc func() *storage.StorageClass
}{
{
description: "StorageClass Without AllowVolumeExpansion",
hasAllowVolumeExpansion: false,
sc: scWithoutAllowVolumeExpansion,
},
{
description: "StorageClass With AllowVolumeExpansion",
hasAllowVolumeExpansion: true,
sc: scWithAllowVolumeExpansion,
},
{
description: "is nil",
hasAllowVolumeExpansion: false,
sc: func() *storage.StorageClass { return nil },
},
}
for _, enabled := range []bool{true, false} {
for _, oldStorageClassInfo := range scInfo {
for _, newStorageClassInfo := range scInfo {
oldStorageClassHasAllowVolumeExpansion, oldStorageClass := oldStorageClassInfo.hasAllowVolumeExpansion, oldStorageClassInfo.sc()
newStorageClassHasAllowVolumeExpansion, newStorageClass := newStorageClassInfo.hasAllowVolumeExpansion, newStorageClassInfo.sc()
if newStorageClass == nil {
continue
}
t.Run(fmt.Sprintf("feature enabled=%v, old StorageClass %v, new StorageClass %v", enabled, oldStorageClassInfo.description, newStorageClassInfo.description), func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandPersistentVolumes, enabled)()
DropDisabledFields(newStorageClass, oldStorageClass)
// old StorageClass should never be changed
if !reflect.DeepEqual(oldStorageClass, oldStorageClassInfo.sc()) {
t.Errorf("old StorageClass changed: %v", diff.ObjectReflectDiff(oldStorageClass, oldStorageClassInfo.sc()))
}
switch {
case enabled || oldStorageClassHasAllowVolumeExpansion:
// new StorageClass should not be changed if the feature is enabled, or if the old StorageClass had AllowVolumeExpansion
if !reflect.DeepEqual(newStorageClass, newStorageClassInfo.sc()) {
t.Errorf("new StorageClass changed: %v", diff.ObjectReflectDiff(newStorageClass, newStorageClassInfo.sc()))
}
case newStorageClassHasAllowVolumeExpansion:
// new StorageClass should be changed
if reflect.DeepEqual(newStorageClass, newStorageClassInfo.sc()) {
t.Errorf("new StorageClass was not changed")
}
// new StorageClass should not have AllowVolumeExpansion
if !reflect.DeepEqual(newStorageClass, scWithoutAllowVolumeExpansion()) {
t.Errorf("new StorageClass had StorageClassAllowVolumeExpansion: %v", diff.ObjectReflectDiff(newStorageClass, scWithoutAllowVolumeExpansion()))
}
default:
// new StorageClass should not need to be changed
if !reflect.DeepEqual(newStorageClass, newStorageClassInfo.sc()) {
t.Errorf("new StorageClass changed: %v", diff.ObjectReflectDiff(newStorageClass, newStorageClassInfo.sc()))
}
}
})
}
}
}
}

View File

@ -94,7 +94,7 @@ func (p *pvcEvaluator) Handles(a admission.Attributes) bool {
if op == admission.Create {
return true
}
if op == admission.Update && utilfeature.DefaultFeatureGate.Enabled(k8sfeatures.ExpandPersistentVolumes) {
if op == admission.Update {
return true
}
return false

View File

@ -76,15 +76,13 @@ func TestDropConditions(t *testing.T) {
},
}
for _, enabled := range []bool{true, false} {
for _, enabled := range []bool{true} {
for _, oldPvcInfo := range pvcInfo {
for _, newPvcInfo := range pvcInfo {
oldPvcHasConditins, oldPvc := oldPvcInfo.hasConditions, oldPvcInfo.pvc()
newPvcHasConditions, newPvc := newPvcInfo.hasConditions, newPvcInfo.pvc()
t.Run(fmt.Sprintf("feature enabled=%v, old pvc %v, new pvc %v", enabled, oldPvcInfo.description, newPvcInfo.description), func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandPersistentVolumes, enabled)()
StatusStrategy.PrepareForUpdate(ctx, newPvc, oldPvc)
// old pvc should never be changed

View File

@ -24,7 +24,6 @@ import (
"k8s.io/apiserver/pkg/storage/names"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/storage"
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
"k8s.io/kubernetes/pkg/apis/storage/validation"
)
@ -44,9 +43,6 @@ func (storageClassStrategy) NamespaceScoped() bool {
// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation.
func (storageClassStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
class := obj.(*storage.StorageClass)
storageutil.DropDisabledFields(class, nil)
}
func (storageClassStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
@ -69,10 +65,6 @@ func (storageClassStrategy) AllowCreateOnUpdate() bool {
// PrepareForUpdate sets the Status fields which is not allowed to be set by an end user updating a PV
func (storageClassStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
newClass := obj.(*storage.StorageClass)
oldClass := old.(*storage.StorageClass)
storageutil.DropDisabledFields(oldClass, newClass)
}
func (storageClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {

View File

@ -2025,10 +2025,6 @@ func (og *operationGenerator) nodeExpandVolume(
volumeToMount VolumeToMount,
actualStateOfWorld ActualStateOfWorldMounterUpdater,
rsOpts volume.NodeResizeOptions) (bool, error) {
if !utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
klog.V(4).Infof("Resizing is not enabled for this volume %s", volumeToMount.VolumeName)
return true, nil
}
if volumeToMount.VolumeSpec != nil &&
volumeToMount.VolumeSpec.InlineVolumeSpecForCSIMigration {

View File

@ -71,8 +71,7 @@ type Plugin struct {
podsGetter corev1lister.PodLister
nodesGetter corev1lister.NodeLister
expandPersistentVolumesEnabled bool
expansionRecoveryEnabled bool
expansionRecoveryEnabled bool
}
var (
@ -83,7 +82,6 @@ var (
// InspectFeatureGates allows setting bools without taking a dep on a global variable
func (p *Plugin) InspectFeatureGates(featureGates featuregate.FeatureGate) {
p.expandPersistentVolumesEnabled = featureGates.Enabled(features.ExpandPersistentVolumes)
p.expansionRecoveryEnabled = featureGates.Enabled(features.RecoverVolumeExpansionFailure)
}
@ -336,10 +334,6 @@ func (p *Plugin) admitPodEviction(nodeName string, a admission.Attributes) error
func (p *Plugin) admitPVCStatus(nodeName string, a admission.Attributes) error {
switch a.GetOperation() {
case admission.Update:
if !p.expandPersistentVolumesEnabled {
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to update persistentvolumeclaim metadata", nodeName))
}
oldPVC, ok := a.GetOldObject().(*api.PersistentVolumeClaim)
if !ok {
return admission.NewForbidden(a, fmt.Errorf("unexpected type %T", a.GetOldObject()))

View File

@ -18,14 +18,15 @@ package noderestriction
import (
"context"
"k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/pkg/features"
"reflect"
"strings"
"testing"
"time"
"k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/pkg/features"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -1527,8 +1528,6 @@ func TestAdmitPVCStatus(t *testing.T) {
attributes := admission.NewAttributesRecord(
test.newObj, test.oldObj, schema.GroupVersionKind{},
metav1.NamespaceDefault, "foo", apiResource, test.subresource, operation, &metav1.CreateOptions{}, false, mynode)
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ExpandPersistentVolumes, test.expansionFeatureEnabled)()
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.RecoverVolumeExpansionFailure, test.recoveryFeatureEnabled)()
a := &admitTestCase{
name: test.name,

View File

@ -30,15 +30,12 @@ import (
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/plugin/resourcequota"
resourcequotaapi "k8s.io/apiserver/pkg/admission/plugin/resourcequota/apis/resourcequota"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
testcore "k8s.io/client-go/testing"
"k8s.io/client-go/tools/cache"
featuregatetesting "k8s.io/component-base/featuregate/testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/quota/v1/install"
)
@ -408,8 +405,6 @@ func TestAdmitHandlesNegativePVCUpdates(t *testing.T) {
stopCh := make(chan struct{})
defer close(stopCh)
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandPersistentVolumes, true)()
kubeClient := fake.NewSimpleClientset(resourceQuota)
informerFactory := informers.NewSharedInformerFactory(kubeClient, 0)
@ -458,8 +453,6 @@ func TestAdmitHandlesPVCUpdates(t *testing.T) {
},
}
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandPersistentVolumes, true)()
// start up quota system
stopCh := make(chan struct{})
defer close(stopCh)

View File

@ -32,7 +32,6 @@ import (
api "k8s.io/kubernetes/pkg/apis/core"
storageapi "k8s.io/kubernetes/pkg/apis/storage"
"k8s.io/kubernetes/pkg/auth/nodeidentifier"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac"
"k8s.io/kubernetes/third_party/forked/gonum/graph"
"k8s.io/kubernetes/third_party/forked/gonum/graph/traverse"
@ -112,10 +111,8 @@ func (r *NodeAuthorizer) Authorize(ctx context.Context, attrs authorizer.Attribu
case configMapResource:
return r.authorizeReadNamespacedObject(nodeName, configMapVertexType, attrs)
case pvcResource:
if r.features.Enabled(features.ExpandPersistentVolumes) {
if attrs.GetSubresource() == "status" {
return r.authorizeStatusUpdate(nodeName, pvcVertexType, attrs)
}
if attrs.GetSubresource() == "status" {
return r.authorizeStatusUpdate(nodeName, pvcVertexType, attrs)
}
return r.authorizeGet(nodeName, pvcVertexType, attrs)
case pvResource:

View File

@ -177,21 +177,19 @@ func buildControllerRoles() ([]rbacv1.ClusterRole, []rbacv1.ClusterRoleBinding)
},
})
if utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
addControllerRole(&controllerRoles, &controllerRoleBindings, rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{Name: saRolePrefix + "expand-controller"},
Rules: []rbacv1.PolicyRule{
rbacv1helpers.NewRule("get", "list", "watch", "update", "patch").Groups(legacyGroup).Resources("persistentvolumes").RuleOrDie(),
rbacv1helpers.NewRule("update", "patch").Groups(legacyGroup).Resources("persistentvolumeclaims/status").RuleOrDie(),
rbacv1helpers.NewRule("get", "list", "watch").Groups(legacyGroup).Resources("persistentvolumeclaims").RuleOrDie(),
// glusterfs
rbacv1helpers.NewRule("get", "list", "watch").Groups(storageGroup).Resources("storageclasses").RuleOrDie(),
rbacv1helpers.NewRule("get").Groups(legacyGroup).Resources("services", "endpoints").RuleOrDie(),
rbacv1helpers.NewRule("get").Groups(legacyGroup).Resources("secrets").RuleOrDie(),
eventsRule(),
},
})
}
addControllerRole(&controllerRoles, &controllerRoleBindings, rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{Name: saRolePrefix + "expand-controller"},
Rules: []rbacv1.PolicyRule{
rbacv1helpers.NewRule("get", "list", "watch", "update", "patch").Groups(legacyGroup).Resources("persistentvolumes").RuleOrDie(),
rbacv1helpers.NewRule("update", "patch").Groups(legacyGroup).Resources("persistentvolumeclaims/status").RuleOrDie(),
rbacv1helpers.NewRule("get", "list", "watch").Groups(legacyGroup).Resources("persistentvolumeclaims").RuleOrDie(),
// glusterfs
rbacv1helpers.NewRule("get", "list", "watch").Groups(storageGroup).Resources("storageclasses").RuleOrDie(),
rbacv1helpers.NewRule("get").Groups(legacyGroup).Resources("services", "endpoints").RuleOrDie(),
rbacv1helpers.NewRule("get").Groups(legacyGroup).Resources("secrets").RuleOrDie(),
eventsRule(),
},
})
addControllerRole(&controllerRoles, &controllerRoleBindings, rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{Name: saRolePrefix + "ephemeral-volume-controller"},

View File

@ -24,9 +24,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authentication/serviceaccount"
"k8s.io/apiserver/pkg/authentication/user"
utilfeature "k8s.io/apiserver/pkg/util/feature"
rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
"k8s.io/kubernetes/pkg/features"
)
// Write and other vars are slices of the allowed verbs.
@ -161,12 +159,10 @@ func NodeRules() []rbacv1.PolicyRule {
rbacv1helpers.NewRule("create").Groups(legacyGroup).Resources("serviceaccounts/token").RuleOrDie(),
}
if utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
// Use the Node authorization mode to limit a node to update status of pvc objects referenced by pods bound to itself.
// Use the NodeRestriction admission plugin to limit a node to just update the status stanza.
pvcStatusPolicyRule := rbacv1helpers.NewRule("get", "update", "patch").Groups(legacyGroup).Resources("persistentvolumeclaims/status").RuleOrDie()
nodePolicyRules = append(nodePolicyRules, pvcStatusPolicyRule)
}
// Use the Node authorization mode to limit a node to update status of pvc objects referenced by pods bound to itself.
// Use the NodeRestriction admission plugin to limit a node to just update the status stanza.
pvcStatusPolicyRule := rbacv1helpers.NewRule("get", "update", "patch").Groups(legacyGroup).Resources("persistentvolumeclaims/status").RuleOrDie()
nodePolicyRules = append(nodePolicyRules, pvcStatusPolicyRule)
// CSI
csiDriverRule := rbacv1helpers.NewRule("get", "watch", "list").Groups("storage.k8s.io").Resources("csidrivers").RuleOrDie()

View File

@ -567,13 +567,7 @@ func TestNodeAuthorizer(t *testing.T) {
// re-create a pod as an admin to add object references
expectAllowed(t, createNode2NormalPod(superuserClient))
// ExpandPersistentVolumes feature disabled
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandPersistentVolumes, false)()
expectForbidden(t, updatePVCCapacity(node1Client))
expectForbidden(t, updatePVCCapacity(node2Client))
// ExpandPersistentVolumes feature enabled
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandPersistentVolumes, true)()
expectForbidden(t, updatePVCCapacity(node1Client))
expectAllowed(t, updatePVCCapacity(node2Client))
expectForbidden(t, updatePVCPhase(node2Client))