From 73dcfe12dac3e3dc8997e7296f34701c0c15ec67 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Thu, 27 Dec 2018 17:45:04 -0500 Subject: [PATCH] Stop checking VolumeScheduling feature gate --- cmd/kube-scheduler/app/BUILD | 3 - cmd/kube-scheduler/app/server.go | 17 +- pkg/apis/core/validation/validation.go | 35 ++-- pkg/apis/core/validation/validation_test.go | 13 -- pkg/apis/storage/util/BUILD | 1 - pkg/apis/storage/util/util.go | 8 - pkg/apis/storage/util/util_test.go | 43 ----- pkg/apis/storage/v1/BUILD | 5 - pkg/apis/storage/v1/defaults.go | 4 +- pkg/apis/storage/v1/defaults_test.go | 14 +- pkg/apis/storage/v1beta1/BUILD | 5 - pkg/apis/storage/v1beta1/defaults.go | 4 +- pkg/apis/storage/v1beta1/defaults_test.go | 15 +- pkg/apis/storage/validation/BUILD | 5 - pkg/apis/storage/validation/validation.go | 18 +- .../storage/validation/validation_test.go | 32 ---- pkg/controller/cloud/BUILD | 5 - pkg/controller/cloud/pvlcontroller.go | 4 +- pkg/controller/cloud/pvlcontroller_test.go | 6 - .../volume/persistentvolume/pv_controller.go | 4 - .../persistentvolume/pv_controller_test.go | 24 --- pkg/features/kube_features.go | 4 +- pkg/scheduler/BUILD | 5 - .../algorithm/predicates/predicates.go | 26 ++- .../algorithm/predicates/predicates_test.go | 5 - pkg/scheduler/factory/BUILD | 2 - pkg/scheduler/factory/factory.go | 21 +-- pkg/scheduler/scheduler.go | 12 +- pkg/scheduler/scheduler_test.go | 5 - pkg/volume/awsebs/aws_ebs.go | 10 +- pkg/volume/azure_dd/azure_provision.go | 78 ++++---- pkg/volume/cinder/cinder.go | 22 ++- pkg/volume/gcepd/gce_pd.go | 2 +- pkg/volume/util/BUILD | 3 - pkg/volume/util/util_test.go | 169 +++++------------- .../storage/persistentvolume/label/BUILD | 5 - .../persistentvolume/label/admission.go | 38 ++-- .../persistentvolume/label/admission_test.go | 5 - .../authorizer/rbac/bootstrappolicy/policy.go | 12 +- .../pkg/util/feature/feature_gate.go | 9 +- .../pkg/util/feature/feature_gate_test.go | 45 ++++- .../scheduler/volume_binding_test.go | 7 - 42 files changed, 213 insertions(+), 537 deletions(-) diff --git a/cmd/kube-scheduler/app/BUILD b/cmd/kube-scheduler/app/BUILD index a3243f96ab4..21a9687b190 100644 --- a/cmd/kube-scheduler/app/BUILD +++ b/cmd/kube-scheduler/app/BUILD @@ -14,7 +14,6 @@ go_library( "//cmd/kube-scheduler/app/options:go_default_library", "//pkg/api/legacyscheme:go_default_library", "//pkg/controller:go_default_library", - "//pkg/features:go_default_library", "//pkg/scheduler:go_default_library", "//pkg/scheduler/algorithmprovider:go_default_library", "//pkg/scheduler/api:go_default_library", @@ -38,10 +37,8 @@ go_library( "//staging/src/k8s.io/apiserver/pkg/server/healthz:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/mux:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/routes:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/flag:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/globalflag:go_default_library", - "//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", "//staging/src/k8s.io/client-go/tools/leaderelection:go_default_library", "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go index 096a6b4caeb..252d161cc8f 100644 --- a/cmd/kube-scheduler/app/server.go +++ b/cmd/kube-scheduler/app/server.go @@ -38,17 +38,14 @@ import ( "k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/server/mux" "k8s.io/apiserver/pkg/server/routes" - utilfeature "k8s.io/apiserver/pkg/util/feature" apiserverflag "k8s.io/apiserver/pkg/util/flag" "k8s.io/apiserver/pkg/util/globalflag" - storageinformers "k8s.io/client-go/informers/storage/v1" v1core "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/tools/leaderelection" schedulerserverconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config" "k8s.io/kubernetes/cmd/kube-scheduler/app/options" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/controller" - "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/scheduler" "k8s.io/kubernetes/pkg/scheduler/algorithmprovider" schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" @@ -165,11 +162,6 @@ func runCommand(cmd *cobra.Command, args []string, opts *options.Options) error // Run executes the scheduler based on the given configuration. It only return on error or when stopCh is closed. func Run(cc schedulerserverconfig.CompletedConfig, stopCh <-chan struct{}) error { - var storageClassInformer storageinformers.StorageClassInformer - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - storageClassInformer = cc.InformerFactory.Storage().V1().StorageClasses() - } - // Create the scheduler. sched, err := scheduler.New(cc.Client, cc.InformerFactory.Core().V1().Nodes(), @@ -181,7 +173,7 @@ func Run(cc schedulerserverconfig.CompletedConfig, stopCh <-chan struct{}) error cc.InformerFactory.Apps().V1().StatefulSets(), cc.InformerFactory.Core().V1().Services(), cc.InformerFactory.Policy().V1beta1().PodDisruptionBudgets(), - storageClassInformer, + cc.InformerFactory.Storage().V1().StorageClasses(), cc.Recorder, cc.ComponentConfig.AlgorithmSource, stopCh, @@ -335,11 +327,6 @@ func newHealthzHandler(config *kubeschedulerconfig.KubeSchedulerConfiguration, s // NewSchedulerConfig creates the scheduler configuration. This is exposed for use by tests. func NewSchedulerConfig(s schedulerserverconfig.CompletedConfig) (*factory.Config, error) { - var storageClassInformer storageinformers.StorageClassInformer - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - storageClassInformer = s.InformerFactory.Storage().V1().StorageClasses() - } - // Set up the configurator which can create schedulers from configs. configurator := factory.NewConfigFactory(&factory.ConfigFactoryArgs{ SchedulerName: s.ComponentConfig.SchedulerName, @@ -353,7 +340,7 @@ func NewSchedulerConfig(s schedulerserverconfig.CompletedConfig) (*factory.Confi StatefulSetInformer: s.InformerFactory.Apps().V1().StatefulSets(), ServiceInformer: s.InformerFactory.Core().V1().Services(), PdbInformer: s.InformerFactory.Policy().V1beta1().PodDisruptionBudgets(), - StorageClassInformer: storageClassInformer, + StorageClassInformer: s.InformerFactory.Storage().V1().StorageClasses(), HardPodAffinitySymmetricWeight: s.ComponentConfig.HardPodAffinitySymmetricWeight, DisablePreemption: s.ComponentConfig.DisablePreemption, PercentageOfNodesToScore: s.ComponentConfig.PercentageOfNodesToScore, diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index 43dc6562790..fe197057391 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -1783,11 +1783,9 @@ func ValidatePersistentVolumeUpdate(newPv, oldPv *core.PersistentVolume) field.E allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.VolumeMode, oldPv.Spec.VolumeMode, field.NewPath("volumeMode"))...) - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - // Allow setting NodeAffinity if oldPv NodeAffinity was not set - if oldPv.Spec.NodeAffinity != nil { - allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.NodeAffinity, oldPv.Spec.NodeAffinity, field.NewPath("nodeAffinity"))...) - } + // Allow setting NodeAffinity if oldPv NodeAffinity was not set + if oldPv.Spec.NodeAffinity != nil { + allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.NodeAffinity, oldPv.Spec.NodeAffinity, field.NewPath("nodeAffinity"))...) } return allErrs @@ -3168,22 +3166,17 @@ func ValidateTopologySelectorTerm(term core.TopologySelectorTerm, fldPath *field exprMap := make(map[string]sets.String) exprPath := fldPath.Child("matchLabelExpressions") - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - // Allow empty MatchLabelExpressions, in case this field becomes optional in the future. + // Allow empty MatchLabelExpressions, in case this field becomes optional in the future. + for i, req := range term.MatchLabelExpressions { + idxPath := exprPath.Index(i) + valueSet, exprErrs := validateTopologySelectorLabelRequirement(req, idxPath) + allErrs = append(allErrs, exprErrs...) - for i, req := range term.MatchLabelExpressions { - idxPath := exprPath.Index(i) - valueSet, exprErrs := validateTopologySelectorLabelRequirement(req, idxPath) - allErrs = append(allErrs, exprErrs...) - - // Validate no duplicate keys exist. - if _, exists := exprMap[req.Key]; exists { - allErrs = append(allErrs, field.Duplicate(idxPath.Child("key"), req.Key)) - } - exprMap[req.Key] = valueSet + // Validate no duplicate keys exist. + if _, exists := exprMap[req.Key]; exists { + allErrs = append(allErrs, field.Duplicate(idxPath.Child("key"), req.Key)) } - } else if len(term.MatchLabelExpressions) != 0 { - allErrs = append(allErrs, field.Forbidden(fldPath, "field is disabled by feature-gate VolumeScheduling")) + exprMap[req.Key] = valueSet } return exprMap, allErrs @@ -5336,10 +5329,6 @@ func validateVolumeNodeAffinity(nodeAffinity *core.VolumeNodeAffinity, fldPath * return false, allErrs } - if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - allErrs = append(allErrs, field.Forbidden(fldPath, "Volume node affinity is disabled by feature-gate")) - } - if nodeAffinity.Required != nil { allErrs = append(allErrs, ValidateNodeSelector(nodeAffinity.Required, fldPath.Child("required"))...) } else { diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index f707aad0f4f..6a26ba92db2 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -577,19 +577,6 @@ func TestValidateLocalVolumesDisabled(t *testing.T) { } }) } - - for name, scenario := range scenarios { - t.Run(name+" VolumeScheduling disabled", func(t *testing.T) { - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, false)() - errs := ValidatePersistentVolume(scenario.volume) - if len(errs) == 0 && scenario.isExpectedFailure { - t.Errorf("Unexpected success for scenario: %s", name) - } - if len(errs) > 0 && !scenario.isExpectedFailure { - t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs) - } - }) - } } func testVolumeWithNodeAffinity(affinity *core.VolumeNodeAffinity) *core.PersistentVolume { diff --git a/pkg/apis/storage/util/BUILD b/pkg/apis/storage/util/BUILD index 629d7cfa2fe..c8d8964d98a 100644 --- a/pkg/apis/storage/util/BUILD +++ b/pkg/apis/storage/util/BUILD @@ -39,7 +39,6 @@ go_test( srcs = ["util_test.go"], embed = [":go_default_library"], deps = [ - "//pkg/apis/core:go_default_library", "//pkg/apis/storage:go_default_library", "//pkg/features:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library", diff --git a/pkg/apis/storage/util/util.go b/pkg/apis/storage/util/util.go index 0eaf9a8f70c..135c548125d 100644 --- a/pkg/apis/storage/util/util.go +++ b/pkg/apis/storage/util/util.go @@ -24,14 +24,6 @@ import ( // DropDisabledFields removes disabled fields from the StorageClass object. func DropDisabledFields(class, oldClass *storage.StorageClass) { - if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - class.VolumeBindingMode = nil - class.AllowedTopologies = nil - if oldClass != nil { - oldClass.VolumeBindingMode = nil - oldClass.AllowedTopologies = nil - } - } if !utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) && !allowVolumeExpansionInUse(oldClass) { class.AllowVolumeExpansion = nil } diff --git a/pkg/apis/storage/util/util_test.go b/pkg/apis/storage/util/util_test.go index 5fe8820d87b..564d7b3a244 100644 --- a/pkg/apis/storage/util/util_test.go +++ b/pkg/apis/storage/util/util_test.go @@ -24,53 +24,10 @@ import ( "k8s.io/apimachinery/pkg/util/diff" utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" - api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/features" ) -func TestDropAlphaFields(t *testing.T) { - bindingMode := storage.VolumeBindingWaitForFirstConsumer - allowedTopologies := []api.TopologySelectorTerm{ - { - MatchLabelExpressions: []api.TopologySelectorLabelRequirement{ - { - Key: "kubernetes.io/hostname", - Values: []string{"node1"}, - }, - }, - }, - } - - // Test that field gets dropped when feature gate is not set - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, false)() - class := &storage.StorageClass{ - VolumeBindingMode: &bindingMode, - AllowedTopologies: allowedTopologies, - } - DropDisabledFields(class, nil) - if class.VolumeBindingMode != nil { - t.Errorf("VolumeBindingMode field didn't get dropped: %+v", class.VolumeBindingMode) - } - if class.AllowedTopologies != nil { - t.Errorf("AllowedTopologies field didn't get dropped: %+v", class.AllowedTopologies) - } - - // Test that field does not get dropped when feature gate is set - class = &storage.StorageClass{ - VolumeBindingMode: &bindingMode, - AllowedTopologies: allowedTopologies, - } - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() - DropDisabledFields(class, nil) - if class.VolumeBindingMode != &bindingMode { - t.Errorf("VolumeBindingMode field got unexpectantly modified: %+v", class.VolumeBindingMode) - } - if !reflect.DeepEqual(class.AllowedTopologies, allowedTopologies) { - t.Errorf("AllowedTopologies field got unexpectantly modified: %+v", class.AllowedTopologies) - } -} - func TestDropAllowVolumeExpansion(t *testing.T) { allowVolumeExpansion := false scWithoutAllowVolumeExpansion := func() *storage.StorageClass { diff --git a/pkg/apis/storage/v1/BUILD b/pkg/apis/storage/v1/BUILD index 05bd5565a79..622bbecf28d 100644 --- a/pkg/apis/storage/v1/BUILD +++ b/pkg/apis/storage/v1/BUILD @@ -19,13 +19,11 @@ go_library( deps = [ "//pkg/apis/core:go_default_library", "//pkg/apis/storage:go_default_library", - "//pkg/features:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", ], ) @@ -52,10 +50,7 @@ go_test( deps = [ "//pkg/api/legacyscheme:go_default_library", "//pkg/apis/storage/install:go_default_library", - "//pkg/features:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", ], ) diff --git a/pkg/apis/storage/v1/defaults.go b/pkg/apis/storage/v1/defaults.go index 6f574f4867c..e50475a8000 100644 --- a/pkg/apis/storage/v1/defaults.go +++ b/pkg/apis/storage/v1/defaults.go @@ -20,8 +20,6 @@ import ( "k8s.io/api/core/v1" storagev1 "k8s.io/api/storage/v1" "k8s.io/apimachinery/pkg/runtime" - utilfeature "k8s.io/apiserver/pkg/util/feature" - "k8s.io/kubernetes/pkg/features" ) func addDefaultingFuncs(scheme *runtime.Scheme) error { @@ -34,7 +32,7 @@ func SetDefaults_StorageClass(obj *storagev1.StorageClass) { *obj.ReclaimPolicy = v1.PersistentVolumeReclaimDelete } - if obj.VolumeBindingMode == nil && utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { + if obj.VolumeBindingMode == nil { obj.VolumeBindingMode = new(storagev1.VolumeBindingMode) *obj.VolumeBindingMode = storagev1.VolumeBindingImmediate } diff --git a/pkg/apis/storage/v1/defaults_test.go b/pkg/apis/storage/v1/defaults_test.go index 82ea60f0bd1..48a45a27199 100644 --- a/pkg/apis/storage/v1/defaults_test.go +++ b/pkg/apis/storage/v1/defaults_test.go @@ -22,11 +22,8 @@ import ( storagev1 "k8s.io/api/storage/v1" "k8s.io/apimachinery/pkg/runtime" - utilfeature "k8s.io/apiserver/pkg/util/feature" - utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" "k8s.io/kubernetes/pkg/api/legacyscheme" _ "k8s.io/kubernetes/pkg/apis/storage/install" - "k8s.io/kubernetes/pkg/features" ) func roundTrip(t *testing.T, obj runtime.Object) runtime.Object { @@ -53,7 +50,7 @@ func roundTrip(t *testing.T, obj runtime.Object) runtime.Object { func TestSetDefaultVolumeBindingMode(t *testing.T) { class := &storagev1.StorageClass{} - // When feature gate is enabled, field should be defaulted + // field should be defaulted defaultMode := storagev1.VolumeBindingImmediate output := roundTrip(t, runtime.Object(class)).(*storagev1.StorageClass) outMode := output.VolumeBindingMode @@ -62,13 +59,4 @@ func TestSetDefaultVolumeBindingMode(t *testing.T) { } else if *outMode != defaultMode { t.Errorf("Expected VolumeBindingMode to be defaulted to: %+v, got: %+v", defaultMode, outMode) } - - class = &storagev1.StorageClass{} - - // When feature gate is disabled, field should not be defaulted - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, false)() - output = roundTrip(t, runtime.Object(class)).(*storagev1.StorageClass) - if output.VolumeBindingMode != nil { - t.Errorf("Expected VolumeBindingMode to not be defaulted, got: %+v", output.VolumeBindingMode) - } } diff --git a/pkg/apis/storage/v1beta1/BUILD b/pkg/apis/storage/v1beta1/BUILD index 7be33870151..65c7b40975f 100644 --- a/pkg/apis/storage/v1beta1/BUILD +++ b/pkg/apis/storage/v1beta1/BUILD @@ -19,13 +19,11 @@ go_library( deps = [ "//pkg/apis/core:go_default_library", "//pkg/apis/storage:go_default_library", - "//pkg/features:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", ], ) @@ -52,10 +50,7 @@ go_test( deps = [ "//pkg/api/legacyscheme:go_default_library", "//pkg/apis/storage/install:go_default_library", - "//pkg/features:go_default_library", "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", ], ) diff --git a/pkg/apis/storage/v1beta1/defaults.go b/pkg/apis/storage/v1beta1/defaults.go index 97dbff2f378..f2db7d84bfe 100644 --- a/pkg/apis/storage/v1beta1/defaults.go +++ b/pkg/apis/storage/v1beta1/defaults.go @@ -20,8 +20,6 @@ import ( "k8s.io/api/core/v1" storagev1beta1 "k8s.io/api/storage/v1beta1" "k8s.io/apimachinery/pkg/runtime" - utilfeature "k8s.io/apiserver/pkg/util/feature" - "k8s.io/kubernetes/pkg/features" ) func addDefaultingFuncs(scheme *runtime.Scheme) error { @@ -34,7 +32,7 @@ func SetDefaults_StorageClass(obj *storagev1beta1.StorageClass) { *obj.ReclaimPolicy = v1.PersistentVolumeReclaimDelete } - if obj.VolumeBindingMode == nil && utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { + if obj.VolumeBindingMode == nil { obj.VolumeBindingMode = new(storagev1beta1.VolumeBindingMode) *obj.VolumeBindingMode = storagev1beta1.VolumeBindingImmediate } diff --git a/pkg/apis/storage/v1beta1/defaults_test.go b/pkg/apis/storage/v1beta1/defaults_test.go index 2e1086dad89..d920c5c7f95 100644 --- a/pkg/apis/storage/v1beta1/defaults_test.go +++ b/pkg/apis/storage/v1beta1/defaults_test.go @@ -22,11 +22,8 @@ import ( storagev1beta1 "k8s.io/api/storage/v1beta1" "k8s.io/apimachinery/pkg/runtime" - utilfeature "k8s.io/apiserver/pkg/util/feature" - utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" "k8s.io/kubernetes/pkg/api/legacyscheme" _ "k8s.io/kubernetes/pkg/apis/storage/install" - "k8s.io/kubernetes/pkg/features" ) func roundTrip(t *testing.T, obj runtime.Object) runtime.Object { @@ -53,7 +50,7 @@ func roundTrip(t *testing.T, obj runtime.Object) runtime.Object { func TestSetDefaultVolumeBindingMode(t *testing.T) { class := &storagev1beta1.StorageClass{} - // When feature gate is enabled, field should be defaulted + // field should be defaulted defaultMode := storagev1beta1.VolumeBindingImmediate output := roundTrip(t, runtime.Object(class)).(*storagev1beta1.StorageClass) outMode := output.VolumeBindingMode @@ -62,14 +59,4 @@ func TestSetDefaultVolumeBindingMode(t *testing.T) { } else if *outMode != defaultMode { t.Errorf("Expected VolumeBindingMode to be defaulted to: %+v, got: %+v", defaultMode, outMode) } - - class = &storagev1beta1.StorageClass{} - - // When feature gate is disabled, field should not be defaulted - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, false)() - output = roundTrip(t, runtime.Object(class)).(*storagev1beta1.StorageClass) - if output.VolumeBindingMode != nil { - t.Errorf("Expected VolumeBindingMode to not be defaulted, got: %+v", output.VolumeBindingMode) - } - } diff --git a/pkg/apis/storage/validation/BUILD b/pkg/apis/storage/validation/BUILD index a91f11d93e1..8051af18fbb 100644 --- a/pkg/apis/storage/validation/BUILD +++ b/pkg/apis/storage/validation/BUILD @@ -15,12 +15,10 @@ go_library( "//pkg/apis/core/helper:go_default_library", "//pkg/apis/core/validation:go_default_library", "//pkg/apis/storage:go_default_library", - "//pkg/features:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", ], ) @@ -31,10 +29,7 @@ go_test( deps = [ "//pkg/apis/core:go_default_library", "//pkg/apis/storage:go_default_library", - "//pkg/features:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", ], ) diff --git a/pkg/apis/storage/validation/validation.go b/pkg/apis/storage/validation/validation.go index 7a738186f03..db974939546 100644 --- a/pkg/apis/storage/validation/validation.go +++ b/pkg/apis/storage/validation/validation.go @@ -24,12 +24,10 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" - utilfeature "k8s.io/apiserver/pkg/util/feature" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/core/helper" apivalidation "k8s.io/kubernetes/pkg/apis/core/validation" "k8s.io/kubernetes/pkg/apis/storage" - "k8s.io/kubernetes/pkg/features" ) const ( @@ -233,14 +231,10 @@ var supportedVolumeBindingModes = sets.NewString(string(storage.VolumeBindingImm // validateVolumeBindingMode tests that VolumeBindingMode specifies valid values. func validateVolumeBindingMode(mode *storage.VolumeBindingMode, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - if mode == nil { - allErrs = append(allErrs, field.Required(fldPath, "")) - } else if !supportedVolumeBindingModes.Has(string(*mode)) { - allErrs = append(allErrs, field.NotSupported(fldPath, mode, supportedVolumeBindingModes.List())) - } - } else if mode != nil { - allErrs = append(allErrs, field.Forbidden(fldPath, "field is disabled by feature-gate VolumeScheduling")) + if mode == nil { + allErrs = append(allErrs, field.Required(fldPath, "")) + } else if !supportedVolumeBindingModes.Has(string(*mode)) { + allErrs = append(allErrs, field.NotSupported(fldPath, mode, supportedVolumeBindingModes.List())) } return allErrs @@ -254,10 +248,6 @@ func validateAllowedTopologies(topologies []api.TopologySelectorTerm, fldPath *f return allErrs } - if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - allErrs = append(allErrs, field.Forbidden(fldPath, "field is disabled by feature-gate VolumeScheduling")) - } - rawTopologies := make([]map[string]sets.String, len(topologies)) for i, term := range topologies { idxPath := fldPath.Index(i) diff --git a/pkg/apis/storage/validation/validation_test.go b/pkg/apis/storage/validation/validation_test.go index b72d0db89df..f5b20041314 100644 --- a/pkg/apis/storage/validation/validation_test.go +++ b/pkg/apis/storage/validation/validation_test.go @@ -22,11 +22,8 @@ import ( "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - utilfeature "k8s.io/apiserver/pkg/util/feature" - utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/storage" - "k8s.io/kubernetes/pkg/features" ) var ( @@ -480,22 +477,6 @@ func makeClass(mode *storage.VolumeBindingMode, topologies []api.TopologySelecto } } -// TODO: Remove these tests once feature gate is not required -func TestValidateVolumeBindingModeAlphaDisabled(t *testing.T) { - errorCases := map[string]*storage.StorageClass{ - "immediate mode": makeClass(&immediateMode1, nil), - "waiting mode": makeClass(&waitingMode, nil), - "invalid mode": makeClass(&invalidMode, nil), - } - - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, false)() - for testName, storageClass := range errorCases { - if errs := ValidateStorageClass(storageClass); len(errs) == 0 { - t.Errorf("Expected failure for test: %v", testName) - } - } -} - type bindingTest struct { class *storage.StorageClass shouldSucceed bool @@ -521,8 +502,6 @@ func TestValidateVolumeBindingMode(t *testing.T) { }, } - // TODO: remove when feature gate not required - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() for testName, testCase := range cases { errs := ValidateStorageClass(testCase.class) if testCase.shouldSucceed && len(errs) != 0 { @@ -579,8 +558,6 @@ func TestValidateUpdateVolumeBindingMode(t *testing.T) { }, } - // TODO: remove when feature gate not required - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() for testName, testCase := range cases { errs := ValidateStorageClassUpdate(testCase.newClass, testCase.oldClass) if testCase.shouldSucceed && len(errs) != 0 { @@ -883,7 +860,6 @@ func TestValidateAllowedTopologies(t *testing.T) { }, } - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() for testName, testCase := range cases { errs := ValidateStorageClass(testCase.class) if testCase.shouldSucceed && len(errs) != 0 { @@ -893,12 +869,4 @@ func TestValidateAllowedTopologies(t *testing.T) { t.Errorf("Expected failure for test %q, got success", testName) } } - - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, false)() - for testName, testCase := range cases { - errs := ValidateStorageClass(testCase.class) - if len(errs) == 0 && testCase.class.AllowedTopologies != nil { - t.Errorf("Expected failure for test %q, got success", testName) - } - } } diff --git a/pkg/controller/cloud/BUILD b/pkg/controller/cloud/BUILD index d31c5f2a80e..1348d836c50 100644 --- a/pkg/controller/cloud/BUILD +++ b/pkg/controller/cloud/BUILD @@ -18,7 +18,6 @@ go_library( "//pkg/api/v1/node:go_default_library", "//pkg/apis/core/v1/helper:go_default_library", "//pkg/controller:go_default_library", - "//pkg/features:go_default_library", "//pkg/kubelet/apis:go_default_library", "//pkg/scheduler/api:go_default_library", "//pkg/util/node:go_default_library", @@ -33,7 +32,6 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/client-go/informers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library", @@ -60,7 +58,6 @@ go_test( "//pkg/cloudprovider/providers/fake:go_default_library", "//pkg/controller:go_default_library", "//pkg/controller/testutil:go_default_library", - "//pkg/features:go_default_library", "//pkg/kubelet/apis:go_default_library", "//pkg/scheduler/api:go_default_library", "//pkg/volume/util:go_default_library", @@ -69,8 +66,6 @@ go_test( "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", "//staging/src/k8s.io/client-go/informers:go_default_library", "//staging/src/k8s.io/client-go/informers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", diff --git a/pkg/controller/cloud/pvlcontroller.go b/pkg/controller/cloud/pvlcontroller.go index 82c5536aac5..d33d98f3a7e 100644 --- a/pkg/controller/cloud/pvlcontroller.go +++ b/pkg/controller/cloud/pvlcontroller.go @@ -33,7 +33,6 @@ import ( "k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" - utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/kubernetes" corelisters "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" @@ -41,7 +40,6 @@ import ( cloudprovider "k8s.io/cloud-provider" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" "k8s.io/kubernetes/pkg/controller" - "k8s.io/kubernetes/pkg/features" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" volumeutil "k8s.io/kubernetes/pkg/volume/util" ) @@ -204,7 +202,7 @@ func (pvlc *PersistentVolumeLabelController) addLabelsAndAffinityToVolume(vol *v func (pvlc *PersistentVolumeLabelController) createPatch(vol *v1.PersistentVolume, volLabels map[string]string) ([]byte, error) { volName := vol.Name newVolume := vol.DeepCopyObject().(*v1.PersistentVolume) - populateAffinity := utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) && len(volLabels) != 0 + populateAffinity := len(volLabels) != 0 if newVolume.Labels == nil { newVolume.Labels = make(map[string]string) diff --git a/pkg/controller/cloud/pvlcontroller_test.go b/pkg/controller/cloud/pvlcontroller_test.go index 1931540d1ef..96d12421c47 100644 --- a/pkg/controller/cloud/pvlcontroller_test.go +++ b/pkg/controller/cloud/pvlcontroller_test.go @@ -27,11 +27,8 @@ import ( "k8s.io/apimachinery/pkg/runtime" sets "k8s.io/apimachinery/pkg/util/sets" - utilfeature "k8s.io/apiserver/pkg/util/feature" - utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" - "k8s.io/kubernetes/pkg/features" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" volumeutil "k8s.io/kubernetes/pkg/volume/util" @@ -451,7 +448,6 @@ func TestCreatePatch(t *testing.T) { }, } - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() for d, tc := range testCases { cloud := &fakecloud.FakeCloud{} client := fake.NewSimpleClientset() @@ -520,8 +516,6 @@ func TestAddLabelsToVolume(t *testing.T) { }, } - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() - for d, tc := range testCases { labeledCh := make(chan bool, 1) client := fake.NewSimpleClientset() diff --git a/pkg/controller/volume/persistentvolume/pv_controller.go b/pkg/controller/volume/persistentvolume/pv_controller.go index e50da0ad4fa..cd9143e2800 100644 --- a/pkg/controller/volume/persistentvolume/pv_controller.go +++ b/pkg/controller/volume/persistentvolume/pv_controller.go @@ -286,10 +286,6 @@ func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVo } func (ctrl *PersistentVolumeController) shouldDelayBinding(claim *v1.PersistentVolumeClaim) (bool, error) { - if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - return false, nil - } - // When feature VolumeScheduling enabled, // Scheduler signal to the PV controller to start dynamic // provisioning by setting the "annSelectedNode" annotation diff --git a/pkg/controller/volume/persistentvolume/pv_controller_test.go b/pkg/controller/volume/persistentvolume/pv_controller_test.go index 514617e5f1d..37b223abf3f 100644 --- a/pkg/controller/volume/persistentvolume/pv_controller_test.go +++ b/pkg/controller/volume/persistentvolume/pv_controller_test.go @@ -24,15 +24,12 @@ import ( storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/watch" - utilfeature "k8s.io/apiserver/pkg/util/feature" - utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" "k8s.io/client-go/tools/cache" "k8s.io/klog" "k8s.io/kubernetes/pkg/controller" - "k8s.io/kubernetes/pkg/features" ) var ( @@ -336,24 +333,3 @@ func TestDelayBinding(t *testing.T) { } } } - -func TestDelayBindingDisabled(t *testing.T) { - // When volumeScheduling feature gate is disabled, should always be immediate - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, false)() - - client := &fake.Clientset{} - informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc()) - classInformer := informerFactory.Storage().V1().StorageClasses() - ctrl := &PersistentVolumeController{ - classLister: classInformer.Lister(), - } - - name := "volumeScheduling-feature-disabled" - shouldDelay, err := ctrl.shouldDelayBinding(makePVCClass(&classWaitMode, false)) - if err != nil { - t.Errorf("Test %q returned error: %v", name, err) - } - if shouldDelay { - t.Errorf("Test %q returned true, expected false", name) - } -} diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 65e4900007b..fbd0c3d7f6e 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -413,7 +413,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS PodShareProcessNamespace: {Default: true, PreRelease: utilfeature.Beta}, PodPriority: {Default: true, PreRelease: utilfeature.Beta}, TaintNodesByCondition: {Default: true, PreRelease: utilfeature.Beta}, - MountPropagation: {Default: true, PreRelease: utilfeature.GA}, + MountPropagation: {Default: true, PreRelease: utilfeature.GA, LockToDefault: true}, // remove in 1.14 QOSReserved: {Default: false, PreRelease: utilfeature.Alpha}, ExpandPersistentVolumes: {Default: true, PreRelease: utilfeature.Beta}, ExpandInUsePersistentVolumes: {Default: false, PreRelease: utilfeature.Alpha}, @@ -422,7 +422,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS CPUCFSQuotaPeriod: {Default: false, PreRelease: utilfeature.Alpha}, ServiceNodeExclusion: {Default: false, PreRelease: utilfeature.Alpha}, MountContainers: {Default: false, PreRelease: utilfeature.Alpha}, - VolumeScheduling: {Default: true, PreRelease: utilfeature.GA}, + VolumeScheduling: {Default: true, PreRelease: utilfeature.GA, LockToDefault: true}, // remove in 1.16 CSIPersistentVolume: {Default: true, PreRelease: utilfeature.GA}, CSIDriverRegistry: {Default: false, PreRelease: utilfeature.Alpha}, CSINodeInfo: {Default: false, PreRelease: utilfeature.Alpha}, diff --git a/pkg/scheduler/BUILD b/pkg/scheduler/BUILD index e12ee333630..b781d2178e6 100644 --- a/pkg/scheduler/BUILD +++ b/pkg/scheduler/BUILD @@ -9,7 +9,6 @@ go_library( importpath = "k8s.io/kubernetes/pkg/scheduler", visibility = ["//visibility:public"], deps = [ - "//pkg/features:go_default_library", "//pkg/scheduler/algorithm:go_default_library", "//pkg/scheduler/algorithm/predicates:go_default_library", "//pkg/scheduler/api:go_default_library", @@ -27,7 +26,6 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/client-go/informers/apps/v1:go_default_library", "//staging/src/k8s.io/client-go/informers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/informers/policy/v1beta1:go_default_library", @@ -46,7 +44,6 @@ go_test( deps = [ "//pkg/api/legacyscheme:go_default_library", "//pkg/controller/volume/persistentvolume:go_default_library", - "//pkg/features:go_default_library", "//pkg/scheduler/algorithm:go_default_library", "//pkg/scheduler/algorithm/predicates:go_default_library", "//pkg/scheduler/api:go_default_library", @@ -66,8 +63,6 @@ go_test( "//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", "//staging/src/k8s.io/client-go/informers:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", "//staging/src/k8s.io/client-go/listers/core/v1:go_default_library", diff --git a/pkg/scheduler/algorithm/predicates/predicates.go b/pkg/scheduler/algorithm/predicates/predicates.go index a6ea4671dcb..3fcc02b0ca9 100644 --- a/pkg/scheduler/algorithm/predicates/predicates.go +++ b/pkg/scheduler/algorithm/predicates/predicates.go @@ -635,18 +635,16 @@ func (c *VolumeZoneChecker) predicate(pod *v1.Pod, meta PredicateMetadata, nodeI pvName := pvc.Spec.VolumeName if pvName == "" { - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - scName := v1helper.GetPersistentVolumeClaimClass(pvc) - if len(scName) > 0 { - class, _ := c.classInfo.GetStorageClassInfo(scName) - if class != nil { - if class.VolumeBindingMode == nil { - return false, nil, fmt.Errorf("VolumeBindingMode not set for StorageClass %q", scName) - } - if *class.VolumeBindingMode == storagev1.VolumeBindingWaitForFirstConsumer { - // Skip unbound volumes - continue - } + scName := v1helper.GetPersistentVolumeClaimClass(pvc) + if len(scName) > 0 { + class, _ := c.classInfo.GetStorageClassInfo(scName) + if class != nil { + if class.VolumeBindingMode == nil { + return false, nil, fmt.Errorf("VolumeBindingMode not set for StorageClass %q", scName) + } + if *class.VolumeBindingMode == storagev1.VolumeBindingWaitForFirstConsumer { + // Skip unbound volumes + continue } } } @@ -1618,10 +1616,6 @@ func NewVolumeBindingPredicate(binder *volumebinder.VolumeBinder) FitPredicate { } func (c *VolumeBindingChecker) predicate(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) { - if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - return true, nil, nil - } - node := nodeInfo.Node() if node == nil { return false, nil, fmt.Errorf("node not found") diff --git a/pkg/scheduler/algorithm/predicates/predicates_test.go b/pkg/scheduler/algorithm/predicates/predicates_test.go index 0e5058478c9..0a9305aa8e1 100644 --- a/pkg/scheduler/algorithm/predicates/predicates_test.go +++ b/pkg/scheduler/algorithm/predicates/predicates_test.go @@ -29,10 +29,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" - utilfeature "k8s.io/apiserver/pkg/util/feature" - utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" - "k8s.io/kubernetes/pkg/features" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo" @@ -4884,8 +4881,6 @@ func TestVolumeZonePredicateWithVolumeBinding(t *testing.T) { }, } - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() - for _, test := range tests { t.Run(test.name, func(t *testing.T) { fit := NewVolumeZonePredicate(pvInfo, pvcInfo, classInfo) diff --git a/pkg/scheduler/factory/BUILD b/pkg/scheduler/factory/BUILD index 593d07d1a98..0b8931a4e43 100644 --- a/pkg/scheduler/factory/BUILD +++ b/pkg/scheduler/factory/BUILD @@ -12,7 +12,6 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/api/v1/pod:go_default_library", - "//pkg/features:go_default_library", "//pkg/kubelet/apis:go_default_library", "//pkg/scheduler/algorithm:go_default_library", "//pkg/scheduler/algorithm/predicates:go_default_library", @@ -38,7 +37,6 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/client-go/informers/apps/v1:go_default_library", "//staging/src/k8s.io/client-go/informers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/informers/policy/v1beta1:go_default_library", diff --git a/pkg/scheduler/factory/factory.go b/pkg/scheduler/factory/factory.go index 99d570466c4..5faaa174672 100644 --- a/pkg/scheduler/factory/factory.go +++ b/pkg/scheduler/factory/factory.go @@ -38,7 +38,6 @@ import ( "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" - utilfeature "k8s.io/apiserver/pkg/util/feature" appsinformers "k8s.io/client-go/informers/apps/v1" coreinformers "k8s.io/client-go/informers/core/v1" policyinformers "k8s.io/client-go/informers/policy/v1beta1" @@ -51,7 +50,6 @@ import ( "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" podutil "k8s.io/kubernetes/pkg/api/v1/pod" - "k8s.io/kubernetes/pkg/features" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" "k8s.io/kubernetes/pkg/scheduler/algorithm" "k8s.io/kubernetes/pkg/scheduler/algorithm/predicates" @@ -378,16 +376,14 @@ func NewConfigFactory(args *ConfigFactoryArgs) Configurator { }, ) - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - // Setup volume binder - c.volumeBinder = volumebinder.NewVolumeBinder(args.Client, args.PvcInformer, args.PvInformer, args.StorageClassInformer, time.Duration(args.BindTimeoutSeconds)*time.Second) + // Setup volume binder + c.volumeBinder = volumebinder.NewVolumeBinder(args.Client, args.PvcInformer, args.PvInformer, args.StorageClassInformer, time.Duration(args.BindTimeoutSeconds)*time.Second) - args.StorageClassInformer.Informer().AddEventHandler( - cache.ResourceEventHandlerFuncs{ - AddFunc: c.onStorageClassAdd, - }, - ) - } + args.StorageClassInformer.Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: c.onStorageClassAdd, + }, + ) // Setup cache comparer debugger := cachedebugger.New( @@ -491,9 +487,6 @@ func (c *configFactory) onPvcAdd(obj interface{}) { } func (c *configFactory) onPvcUpdate(old, new interface{}) { - if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - return - } c.podQueue.MoveAllToActiveQueue() } diff --git a/pkg/scheduler/scheduler.go b/pkg/scheduler/scheduler.go index a9e2d12ec66..0992ffe203e 100644 --- a/pkg/scheduler/scheduler.go +++ b/pkg/scheduler/scheduler.go @@ -29,14 +29,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" - utilfeature "k8s.io/apiserver/pkg/util/feature" appsinformers "k8s.io/client-go/informers/apps/v1" coreinformers "k8s.io/client-go/informers/core/v1" policyinformers "k8s.io/client-go/informers/policy/v1beta1" storageinformers "k8s.io/client-go/informers/storage/v1" clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/record" - "k8s.io/kubernetes/pkg/features" schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" latestschedulerapi "k8s.io/kubernetes/pkg/scheduler/api/latest" kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" @@ -352,12 +350,10 @@ func (sched *Scheduler) preempt(preemptor *v1.Pod, scheduleErr error) (string, e // // This function modifies assumed if volume binding is required. func (sched *Scheduler) assumeVolumes(assumed *v1.Pod, host string) (allBound bool, err error) { - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - allBound, err = sched.config.VolumeBinder.Binder.AssumePodVolumes(assumed, host) - if err != nil { - sched.recordSchedulingFailure(assumed, err, SchedulerError, - fmt.Sprintf("AssumePodVolumes failed: %v", err)) - } + allBound, err = sched.config.VolumeBinder.Binder.AssumePodVolumes(assumed, host) + if err != nil { + sched.recordSchedulingFailure(assumed, err, SchedulerError, + fmt.Sprintf("AssumePodVolumes failed: %v", err)) } return } diff --git a/pkg/scheduler/scheduler_test.go b/pkg/scheduler/scheduler_test.go index 619ef079502..e20fe44eaea 100644 --- a/pkg/scheduler/scheduler_test.go +++ b/pkg/scheduler/scheduler_test.go @@ -32,8 +32,6 @@ import ( "k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" - utilfeature "k8s.io/apiserver/pkg/util/feature" - utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" "k8s.io/client-go/informers" clientsetfake "k8s.io/client-go/kubernetes/fake" corelister "k8s.io/client-go/listers/core/v1" @@ -41,7 +39,6 @@ import ( "k8s.io/client-go/tools/record" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/controller/volume/persistentvolume" - "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/scheduler/algorithm" "k8s.io/kubernetes/pkg/scheduler/algorithm/predicates" "k8s.io/kubernetes/pkg/scheduler/api" @@ -779,8 +776,6 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { // This can be small because we wait for pod to finish scheduling first chanTimeout := 2 * time.Second - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() - table := []struct { name string expectError error diff --git a/pkg/volume/awsebs/aws_ebs.go b/pkg/volume/awsebs/aws_ebs.go index c6270c1752a..ac934eccafe 100644 --- a/pkg/volume/awsebs/aws_ebs.go +++ b/pkg/volume/awsebs/aws_ebs.go @@ -576,12 +576,10 @@ func (c *awsElasticBlockStoreProvisioner) Provision(selectedNode *v1.Node, allow } } - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity) - pv.Spec.NodeAffinity.Required = new(v1.NodeSelector) - pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1) - pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements - } + pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity) + pv.Spec.NodeAffinity.Required = new(v1.NodeSelector) + pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1) + pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements return pv, nil } diff --git a/pkg/volume/azure_dd/azure_provision.go b/pkg/volume/azure_dd/azure_provision.go index ca49550a5c4..c915f7b47c9 100644 --- a/pkg/volume/azure_dd/azure_provision.go +++ b/pkg/volume/azure_dd/azure_provision.go @@ -311,51 +311,49 @@ func (p *azureDiskProvisioner) Provision(selectedNode *v1.Node, allowedTopologie }, } - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - nodeSelectorTerms := make([]v1.NodeSelectorTerm, 0) + nodeSelectorTerms := make([]v1.NodeSelectorTerm, 0) - if zoned { - // Set node affinity labels based on availability zone labels. - if len(labels) > 0 { - requirements := make([]v1.NodeSelectorRequirement, 0) - for k, v := range labels { - requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}}) - } + if zoned { + // Set node affinity labels based on availability zone labels. + if len(labels) > 0 { + requirements := make([]v1.NodeSelectorRequirement, 0) + for k, v := range labels { + requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}}) + } - nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{ - MatchExpressions: requirements, - }) - } - } else { - // Set node affinity labels based on fault domains. - // This is required because unzoned AzureDisk can't be attached to zoned nodes. - // There are at most 3 fault domains available in each region. - // Refer https://docs.microsoft.com/en-us/azure/virtual-machines/windows/manage-availability. - for i := 0; i < 3; i++ { - requirements := []v1.NodeSelectorRequirement{ - { - Key: kubeletapis.LabelZoneRegion, - Operator: v1.NodeSelectorOpIn, - Values: []string{diskController.GetLocation()}, - }, - { - Key: kubeletapis.LabelZoneFailureDomain, - Operator: v1.NodeSelectorOpIn, - Values: []string{strconv.Itoa(i)}, - }, - } - nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{ - MatchExpressions: requirements, - }) - } + nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{ + MatchExpressions: requirements, + }) } - - if len(nodeSelectorTerms) > 0 { - pv.Spec.NodeAffinity = &v1.VolumeNodeAffinity{ - Required: &v1.NodeSelector{ - NodeSelectorTerms: nodeSelectorTerms, + } else { + // Set node affinity labels based on fault domains. + // This is required because unzoned AzureDisk can't be attached to zoned nodes. + // There are at most 3 fault domains available in each region. + // Refer https://docs.microsoft.com/en-us/azure/virtual-machines/windows/manage-availability. + for i := 0; i < 3; i++ { + requirements := []v1.NodeSelectorRequirement{ + { + Key: kubeletapis.LabelZoneRegion, + Operator: v1.NodeSelectorOpIn, + Values: []string{diskController.GetLocation()}, + }, + { + Key: kubeletapis.LabelZoneFailureDomain, + Operator: v1.NodeSelectorOpIn, + Values: []string{strconv.Itoa(i)}, }, } + nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{ + MatchExpressions: requirements, + }) + } + } + + if len(nodeSelectorTerms) > 0 { + pv.Spec.NodeAffinity = &v1.VolumeNodeAffinity{ + Required: &v1.NodeSelector{ + NodeSelectorTerms: nodeSelectorTerms, + }, } } diff --git a/pkg/volume/cinder/cinder.go b/pkg/volume/cinder/cinder.go index 953c4660f45..e4e488b8d2e 100644 --- a/pkg/volume/cinder/cinder.go +++ b/pkg/volume/cinder/cinder.go @@ -561,20 +561,18 @@ func (c *cinderVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopolo pv.Spec.AccessModes = c.plugin.GetAccessModes() } - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - requirements := make([]v1.NodeSelectorRequirement, 0) - for k, v := range labels { - if v != "" { - requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}}) - } - } - if len(requirements) > 0 { - pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity) - pv.Spec.NodeAffinity.Required = new(v1.NodeSelector) - pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1) - pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements + requirements := make([]v1.NodeSelectorRequirement, 0) + for k, v := range labels { + if v != "" { + requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}}) } } + if len(requirements) > 0 { + pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity) + pv.Spec.NodeAffinity.Required = new(v1.NodeSelector) + pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1) + pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements + } return pv, nil } diff --git a/pkg/volume/gcepd/gce_pd.go b/pkg/volume/gcepd/gce_pd.go index 45572203320..74cf74ce627 100644 --- a/pkg/volume/gcepd/gce_pd.go +++ b/pkg/volume/gcepd/gce_pd.go @@ -551,7 +551,7 @@ func (c *gcePersistentDiskProvisioner) Provision(selectedNode *v1.Node, allowedT } } - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) && len(requirements) > 0 { + if len(requirements) > 0 { pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity) pv.Spec.NodeAffinity.Required = new(v1.NodeSelector) pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1) diff --git a/pkg/volume/util/BUILD b/pkg/volume/util/BUILD index ffd1d032151..d53a67c9c11 100644 --- a/pkg/volume/util/BUILD +++ b/pkg/volume/util/BUILD @@ -60,7 +60,6 @@ go_test( deps = [ "//pkg/apis/core/install:go_default_library", "//pkg/apis/core/v1/helper:go_default_library", - "//pkg/features:go_default_library", "//pkg/kubelet/apis:go_default_library", "//pkg/util/mount:go_default_library", "//pkg/util/slice:go_default_library", @@ -70,8 +69,6 @@ go_test( "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", "//staging/src/k8s.io/client-go/util/testing:go_default_library", ], ) diff --git a/pkg/volume/util/util_test.go b/pkg/volume/util/util_test.go index 8f376a3adb3..c7b7d1a1fb2 100644 --- a/pkg/volume/util/util_test.go +++ b/pkg/volume/util/util_test.go @@ -24,7 +24,6 @@ import ( "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/sets" - utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" utiltesting "k8s.io/client-go/util/testing" // util.go uses api.Codecs.LegacyCodec so import this package to do some @@ -32,7 +31,6 @@ import ( "hash/fnv" _ "k8s.io/kubernetes/pkg/apis/core/install" - "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/util/mount" "reflect" @@ -40,7 +38,6 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - utilfeature "k8s.io/apiserver/pkg/util/feature" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" "k8s.io/kubernetes/pkg/util/slice" @@ -1065,7 +1062,6 @@ func TestSelectZoneForVolume(t *testing.T) { ZonesWithNodes string Node *v1.Node AllowedTopologies []v1.TopologySelectorTerm - VolumeScheduling bool // Expectations around returned zone from SelectZoneForVolume Reject bool // expect error due to validation failing ExpectSpecificZone bool // expect returned zone to specifically match a single zone (rather than one from a set) @@ -1078,7 +1074,6 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] Node irrelevant // [2] Zone and Zones parameters presents // [3] AllowedTopologies irrelevant - // [4] VolumeScheduling irrelevant { Name: "Nil_Node_with_Zone_Zones_parameters_present", ZonePresent: true, @@ -1092,53 +1087,45 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] Node with no zone labels // [2] Zone/Zones parameter irrelevant // [3] AllowedTopologies irrelevant - // [4] VolumeScheduling enabled { - Name: "Node_with_no_Zone_labels", - Node: nodeWithNoLabels, - VolumeScheduling: true, - Reject: true, + Name: "Node_with_no_Zone_labels", + Node: nodeWithNoLabels, + Reject: true, }, // Node with Zone labels as well as Zone parameter specified [Fail] // [1] Node with zone labels // [2] Zone parameter specified // [3] AllowedTopologies irrelevant - // [4] VolumeScheduling enabled { - Name: "Node_with_Zone_labels_and_Zone_parameter_present", - Node: nodeWithZoneLabels, - ZonePresent: true, - Zone: "zoneX", - VolumeScheduling: true, - Reject: true, + Name: "Node_with_Zone_labels_and_Zone_parameter_present", + Node: nodeWithZoneLabels, + ZonePresent: true, + Zone: "zoneX", + Reject: true, }, // Node with Zone labels as well as Zones parameter specified [Fail] // [1] Node with zone labels // [2] Zones parameter specified // [3] AllowedTopologies irrelevant - // [4] VolumeScheduling enabled { - Name: "Node_with_Zone_labels_and_Zones_parameter_present", - Node: nodeWithZoneLabels, - ZonesPresent: true, - Zones: "zoneX,zoneY", - VolumeScheduling: true, - Reject: true, + Name: "Node_with_Zone_labels_and_Zones_parameter_present", + Node: nodeWithZoneLabels, + ZonesPresent: true, + Zones: "zoneX,zoneY", + Reject: true, }, // Zone parameter as well as AllowedTopologies specified [Fail] // [1] nil Node // [2] Zone parameter specified // [3] AllowedTopologies specified - // [4] VolumeScheduling enabled { - Name: "Nil_Node_and_Zone_parameter_and_Allowed_Topology_term", - Node: nil, - ZonePresent: true, - Zone: "zoneX", - VolumeScheduling: true, + Name: "Nil_Node_and_Zone_parameter_and_Allowed_Topology_term", + Node: nil, + ZonePresent: true, + Zone: "zoneX", AllowedTopologies: []v1.TopologySelectorTerm{ { MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{ @@ -1156,13 +1143,11 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] nil Node // [2] Zones parameter specified // [3] AllowedTopologies specified - // [4] VolumeScheduling enabled { - Name: "Nil_Node_and_Zones_parameter_and_Allowed_Topology_term", - Node: nil, - ZonesPresent: true, - Zones: "zoneX,zoneY", - VolumeScheduling: true, + Name: "Nil_Node_and_Zones_parameter_and_Allowed_Topology_term", + Node: nil, + ZonesPresent: true, + Zones: "zoneX,zoneY", AllowedTopologies: []v1.TopologySelectorTerm{ { MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{ @@ -1180,11 +1165,9 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] nil Node // [2] no Zone/Zones parameter // [3] AllowedTopologies with invalid key specified - // [4] VolumeScheduling enabled { - Name: "Nil_Node_and_Invalid_Allowed_Topology_Key", - Node: nil, - VolumeScheduling: true, + Name: "Nil_Node_and_Invalid_Allowed_Topology_Key", + Node: nil, AllowedTopologies: []v1.TopologySelectorTerm{ { MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{ @@ -1206,11 +1189,9 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] nil Node // [2] no Zone/Zones parameter // [3] Invalid AllowedTopologies - // [4] VolumeScheduling enabled { - Name: "Nil_Node_and_Invalid_AllowedTopologies", - Node: nil, - VolumeScheduling: true, + Name: "Nil_Node_and_Invalid_AllowedTopologies", + Node: nil, AllowedTopologies: []v1.TopologySelectorTerm{ { MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{}, @@ -1219,77 +1200,29 @@ func TestSelectZoneForVolume(t *testing.T) { Reject: true, }, - // POSITIVE TESTS WITH VolumeScheduling DISABLED - - // Select zone from active zones [Pass] - // [1] nil Node (Node irrelevant) - // [2] no Zone parameter - // [3] no AllowedTopologies - // [4] VolumeScheduling disabled - { - Name: "No_Zone_Zones_parameter_and_VolumeScheduling_disabled", - ZonesWithNodes: "zoneX,zoneY", - VolumeScheduling: false, - Reject: false, - ExpectedZones: "zoneX,zoneY", - }, - - // Select zone from single zone parameter [Pass] - // [1] nil Node (Node irrelevant) - // [2] Zone parameter specified - // [3] no AllowedTopologies - // [4] VolumeScheduling disabled - { - Name: "Zone_parameter_present_and_VolumeScheduling_disabled", - ZonePresent: true, - Zone: "zoneX", - VolumeScheduling: false, - Reject: false, - ExpectSpecificZone: true, - ExpectedZone: "zoneX", - }, - - // Select zone from zones parameter [Pass] - // [1] nil Node (Node irrelevant) - // [2] Zones parameter specified - // [3] no AllowedTopologies - // [4] VolumeScheduling disabled - { - Name: "Zones_parameter_present_and_VolumeScheduling_disabled", - ZonesPresent: true, - Zones: "zoneX,zoneY", - VolumeScheduling: false, - Reject: false, - ExpectedZones: "zoneX,zoneY", - }, - // POSITIVE TESTS WITH VolumeScheduling ENABLED // Select zone from active zones [Pass] // [1] nil Node // [2] no Zone parameter specified // [3] no AllowedTopologies - // [4] VolumeScheduling enabled { - Name: "Nil_Node_and_No_Zone_Zones_parameter_and_no_Allowed_topologies_and_VolumeScheduling_enabled", - Node: nil, - ZonesWithNodes: "zoneX,zoneY", - VolumeScheduling: true, - Reject: false, - ExpectedZones: "zoneX,zoneY", + Name: "Nil_Node_and_No_Zone_Zones_parameter_and_no_Allowed_topologies_and_VolumeScheduling_enabled", + Node: nil, + ZonesWithNodes: "zoneX,zoneY", + Reject: false, + ExpectedZones: "zoneX,zoneY", }, // Select zone from single zone parameter [Pass] // [1] nil Node // [2] Zone parameter specified // [3] no AllowedTopology specified - // [4] VolumeScheduling enabled { Name: "Nil_Node_and_Zone_parameter_present_and_VolumeScheduling_enabled", ZonePresent: true, Zone: "zoneX", Node: nil, - VolumeScheduling: true, Reject: false, ExpectSpecificZone: true, ExpectedZone: "zoneX", @@ -1299,26 +1232,22 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] nil Node // [2] Zones parameter specified // [3] no AllowedTopology - // [4] VolumeScheduling enabled { - Name: "Nil_Node_and_Zones_parameter_present_and_VolumeScheduling_enabled", - ZonesPresent: true, - Zones: "zoneX,zoneY", - Node: nil, - VolumeScheduling: true, - Reject: false, - ExpectedZones: "zoneX,zoneY", + Name: "Nil_Node_and_Zones_parameter_present_and_VolumeScheduling_enabled", + ZonesPresent: true, + Zones: "zoneX,zoneY", + Node: nil, + Reject: false, + ExpectedZones: "zoneX,zoneY", }, // Select zone from node label [Pass] // [1] Node with zone labels // [2] no zone/zones parameters // [3] no AllowedTopology - // [4] VolumeScheduling enabled { Name: "Node_with_Zone_labels_and_VolumeScheduling_enabled", Node: nodeWithZoneLabels, - VolumeScheduling: true, Reject: false, ExpectSpecificZone: true, ExpectedZone: "zoneX", @@ -1328,11 +1257,9 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] Node with zone labels // [2] no Zone/Zones parameters // [3] AllowedTopology with single term with multiple values specified (ignored) - // [4] VolumeScheduling enabled { - Name: "Node_with_Zone_labels_and_Multiple_Allowed_Topology_values_and_VolumeScheduling_enabled", - Node: nodeWithZoneLabels, - VolumeScheduling: true, + Name: "Node_with_Zone_labels_and_Multiple_Allowed_Topology_values_and_VolumeScheduling_enabled", + Node: nodeWithZoneLabels, AllowedTopologies: []v1.TopologySelectorTerm{ { MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{ @@ -1352,11 +1279,9 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] nil Node // [2] no Zone/Zones parametes specified // [3] AllowedTopologies with single term with multiple values specified - // [4] VolumeScheduling enabled { - Name: "Nil_Node_with_Multiple_Allowed_Topology_values_and_VolumeScheduling_enabled", - Node: nil, - VolumeScheduling: true, + Name: "Nil_Node_with_Multiple_Allowed_Topology_values_and_VolumeScheduling_enabled", + Node: nil, AllowedTopologies: []v1.TopologySelectorTerm{ { MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{ @@ -1375,11 +1300,9 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] nil Node // [2] no Zone/Zones parametes specified // [3] AllowedTopologies with multiple terms specified - // [4] VolumeScheduling enabled { - Name: "Nil_Node_and_Multiple_Allowed_Topology_terms_and_VolumeScheduling_enabled", - Node: nil, - VolumeScheduling: true, + Name: "Nil_Node_and_Multiple_Allowed_Topology_terms_and_VolumeScheduling_enabled", + Node: nil, AllowedTopologies: []v1.TopologySelectorTerm{ { MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{ @@ -1407,11 +1330,9 @@ func TestSelectZoneForVolume(t *testing.T) { // [1] nil Node // [2] no Zone/Zones parametes specified // [3] AllowedTopologies with single term and value specified - // [4] VolumeScheduling enabled { - Name: "Nil_Node_and_Single_Allowed_Topology_term_value_and_VolumeScheduling_enabled", - Node: nil, - VolumeScheduling: true, + Name: "Nil_Node_and_Single_Allowed_Topology_term_value_and_VolumeScheduling_enabled", + Node: nil, AllowedTopologies: []v1.TopologySelectorTerm{ { MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{ @@ -1430,8 +1351,6 @@ func TestSelectZoneForVolume(t *testing.T) { for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, test.VolumeScheduling)() - var zonesParameter, zonesWithNodes sets.String var err error diff --git a/plugin/pkg/admission/storage/persistentvolume/label/BUILD b/plugin/pkg/admission/storage/persistentvolume/label/BUILD index d93e3e75c1f..74fe386c138 100644 --- a/plugin/pkg/admission/storage/persistentvolume/label/BUILD +++ b/plugin/pkg/admission/storage/persistentvolume/label/BUILD @@ -18,13 +18,11 @@ go_library( "//pkg/cloudprovider/providers/aws:go_default_library", "//pkg/cloudprovider/providers/azure:go_default_library", "//pkg/cloudprovider/providers/gce:go_default_library", - "//pkg/features:go_default_library", "//pkg/kubeapiserver/admission:go_default_library", "//pkg/kubelet/apis:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//staging/src/k8s.io/apiserver/pkg/admission:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], @@ -37,15 +35,12 @@ go_test( deps = [ "//pkg/apis/core:go_default_library", "//pkg/cloudprovider/providers/aws:go_default_library", - "//pkg/features:go_default_library", "//pkg/kubelet/apis:go_default_library", "//pkg/volume/util:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apiserver/pkg/admission:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", ], ) diff --git a/plugin/pkg/admission/storage/persistentvolume/label/admission.go b/plugin/pkg/admission/storage/persistentvolume/label/admission.go index db291c86f44..4125dd52c35 100644 --- a/plugin/pkg/admission/storage/persistentvolume/label/admission.go +++ b/plugin/pkg/admission/storage/persistentvolume/label/admission.go @@ -23,14 +23,12 @@ import ( "sync" "k8s.io/apiserver/pkg/admission" - utilfeature "k8s.io/apiserver/pkg/util/feature" cloudprovider "k8s.io/cloud-provider" "k8s.io/klog" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/cloudprovider/providers/aws" "k8s.io/kubernetes/pkg/cloudprovider/providers/azure" "k8s.io/kubernetes/pkg/cloudprovider/providers/gce" - "k8s.io/kubernetes/pkg/features" kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" vol "k8s.io/kubernetes/pkg/volume" @@ -158,25 +156,23 @@ func (l *persistentVolumeLabel) Admit(a admission.Attributes) (err error) { requirements = append(requirements, api.NodeSelectorRequirement{Key: k, Operator: api.NodeSelectorOpIn, Values: values}) } - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - if volume.Spec.NodeAffinity == nil { - volume.Spec.NodeAffinity = new(api.VolumeNodeAffinity) - } - if volume.Spec.NodeAffinity.Required == nil { - volume.Spec.NodeAffinity.Required = new(api.NodeSelector) - } - if len(volume.Spec.NodeAffinity.Required.NodeSelectorTerms) == 0 { - // Need at least one term pre-allocated whose MatchExpressions can be appended to - volume.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]api.NodeSelectorTerm, 1) - } - if nodeSelectorRequirementKeysExistInNodeSelectorTerms(requirements, volume.Spec.NodeAffinity.Required.NodeSelectorTerms) { - klog.V(4).Infof("NodeSelectorRequirements for cloud labels %v conflict with existing NodeAffinity %v. Skipping addition of NodeSelectorRequirements for cloud labels.", - requirements, volume.Spec.NodeAffinity) - } else { - for _, req := range requirements { - for i := range volume.Spec.NodeAffinity.Required.NodeSelectorTerms { - volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions = append(volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions, req) - } + if volume.Spec.NodeAffinity == nil { + volume.Spec.NodeAffinity = new(api.VolumeNodeAffinity) + } + if volume.Spec.NodeAffinity.Required == nil { + volume.Spec.NodeAffinity.Required = new(api.NodeSelector) + } + if len(volume.Spec.NodeAffinity.Required.NodeSelectorTerms) == 0 { + // Need at least one term pre-allocated whose MatchExpressions can be appended to + volume.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]api.NodeSelectorTerm, 1) + } + if nodeSelectorRequirementKeysExistInNodeSelectorTerms(requirements, volume.Spec.NodeAffinity.Required.NodeSelectorTerms) { + klog.V(4).Infof("NodeSelectorRequirements for cloud labels %v conflict with existing NodeAffinity %v. Skipping addition of NodeSelectorRequirements for cloud labels.", + requirements, volume.Spec.NodeAffinity) + } else { + for _, req := range requirements { + for i := range volume.Spec.NodeAffinity.Required.NodeSelectorTerms { + volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions = append(volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions, req) } } } diff --git a/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go b/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go index 5b6dc02041d..99c1843f1b5 100644 --- a/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go +++ b/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go @@ -27,11 +27,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apiserver/pkg/admission" - utilfeature "k8s.io/apiserver/pkg/util/feature" - utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/cloudprovider/providers/aws" - "k8s.io/kubernetes/pkg/features" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" volumeutil "k8s.io/kubernetes/pkg/volume/util" ) @@ -125,8 +122,6 @@ func TestAdmission(t *testing.T) { }, } - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() - // Non-cloud PVs are ignored err := handler.Admit(admission.NewAttributesRecord(&ignoredPV, nil, api.Kind("PersistentVolume").WithVersion("version"), ignoredPV.Namespace, ignoredPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, false, nil)) if err != nil { diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go index 1972220c25e..e3aaef39a8c 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go @@ -489,17 +489,14 @@ func ClusterRoles() []rbacv1.ClusterRole { rbacv1helpers.NewRule("create").Groups(certificatesGroup).Resources("certificatesigningrequests/selfnodeclient").RuleOrDie(), }, }, - } - - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - roles = append(roles, rbacv1.ClusterRole{ + { ObjectMeta: metav1.ObjectMeta{Name: "system:volume-scheduler"}, Rules: []rbacv1.PolicyRule{ rbacv1helpers.NewRule(ReadUpdate...).Groups(legacyGroup).Resources("persistentvolumes").RuleOrDie(), rbacv1helpers.NewRule(Read...).Groups(storageGroup).Resources("storageclasses").RuleOrDie(), rbacv1helpers.NewRule(ReadUpdate...).Groups(legacyGroup).Resources("persistentvolumeclaims").RuleOrDie(), }, - }) + }, } externalProvisionerRules := []rbacv1.PolicyRule{ @@ -535,6 +532,7 @@ func ClusterRoleBindings() []rbacv1.ClusterRoleBinding { rbacv1helpers.NewClusterBinding("system:kube-dns").SAs("kube-system", "kube-dns").BindingOrDie(), rbacv1helpers.NewClusterBinding("system:kube-scheduler").Users(user.KubeScheduler).BindingOrDie(), rbacv1helpers.NewClusterBinding("system:aws-cloud-provider").SAs("kube-system", "aws-cloud-provider").BindingOrDie(), + rbacv1helpers.NewClusterBinding("system:volume-scheduler").Users(user.KubeScheduler).BindingOrDie(), // This default binding of the system:node role to the system:nodes group is deprecated in 1.7 with the availability of the Node authorizer. // This leaves the binding, but with an empty set of subjects, so that tightening reconciliation can remove the subject. @@ -544,10 +542,6 @@ func ClusterRoleBindings() []rbacv1.ClusterRoleBinding { }, } - if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { - rolebindings = append(rolebindings, rbacv1helpers.NewClusterBinding("system:volume-scheduler").Users(user.KubeScheduler).BindingOrDie()) - } - addClusterRoleBindingLabel(rolebindings) return rolebindings diff --git a/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate.go b/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate.go index a8bce27f3a7..90f8300bd32 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate.go +++ b/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate.go @@ -63,7 +63,11 @@ var ( ) type FeatureSpec struct { - Default bool + // Default is the default enablement state for the feature + Default bool + // LockToDefault indicates that the feature is locked to its default and cannot be changed + LockToDefault bool + // PreRelease indicates the maturity level of the feature PreRelease prerelease } @@ -199,6 +203,9 @@ func (f *featureGate) SetFromMap(m map[string]bool) error { if !ok { return fmt.Errorf("unrecognized feature gate: %s", k) } + if featureSpec.LockToDefault && featureSpec.Default != v { + return fmt.Errorf("cannot set feature gate %v to %v, feature is locked to %v", k, v, featureSpec.Default) + } enabled[k] = v // Handle "special" features like "all alpha gates" if fn, found := f.special[k]; found { diff --git a/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go b/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go index 194ed1f0723..aa42b3d3e94 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go +++ b/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go @@ -221,6 +221,8 @@ func TestFeatureGateSetFromMap(t *testing.T) { // gates for testing const testAlphaGate Feature = "TestAlpha" const testBetaGate Feature = "TestBeta" + const testLockedTrueGate Feature = "TestLockedTrue" + const testLockedFalseGate Feature = "TestLockedFalse" tests := []struct { name string @@ -270,17 +272,54 @@ func TestFeatureGateSetFromMap(t *testing.T) { }, setmapError: "unrecognized feature gate:", }, + { + name: "set locked gates", + setmap: map[string]bool{ + "TestLockedTrue": true, + "TestLockedFalse": false, + }, + expect: map[Feature]bool{ + testAlphaGate: false, + testBetaGate: false, + }, + }, + { + name: "set locked gates", + setmap: map[string]bool{ + "TestLockedTrue": false, + }, + expect: map[Feature]bool{ + testAlphaGate: false, + testBetaGate: false, + }, + setmapError: "cannot set feature gate TestLockedTrue to false, feature is locked to true", + }, + { + name: "set locked gates", + setmap: map[string]bool{ + "TestLockedFalse": true, + }, + expect: map[Feature]bool{ + testAlphaGate: false, + testBetaGate: false, + }, + setmapError: "cannot set feature gate TestLockedFalse to true, feature is locked to false", + }, } for i, test := range tests { t.Run(fmt.Sprintf("SetFromMap %s", test.name), func(t *testing.T) { f := NewFeatureGate() f.Add(map[Feature]FeatureSpec{ - testAlphaGate: {Default: false, PreRelease: Alpha}, - testBetaGate: {Default: false, PreRelease: Beta}, + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: false, PreRelease: Beta}, + testLockedTrueGate: {Default: true, PreRelease: GA, LockToDefault: true}, + testLockedFalseGate: {Default: false, PreRelease: GA, LockToDefault: true}, }) err := f.SetFromMap(test.setmap) if test.setmapError != "" { - if !strings.Contains(err.Error(), test.setmapError) { + if err == nil { + t.Errorf("expected error, got none") + } else if !strings.Contains(err.Error(), test.setmapError) { t.Errorf("%d: SetFromMap(%#v) Expected err:%v, Got err:%v", i, test.setmap, test.setmapError, err) } } else if err != nil { diff --git a/test/integration/scheduler/volume_binding_test.go b/test/integration/scheduler/volume_binding_test.go index 609a45958d3..58b4c538985 100644 --- a/test/integration/scheduler/volume_binding_test.go +++ b/test/integration/scheduler/volume_binding_test.go @@ -97,7 +97,6 @@ type testPVC struct { } func TestVolumeBinding(t *testing.T) { - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)() config := setupCluster(t, "volume-scheduling-", 2, 0, 0) defer config.teardown() @@ -268,7 +267,6 @@ func TestVolumeBinding(t *testing.T) { // TestVolumeBindingRescheduling tests scheduler will retry scheduling when needed. func TestVolumeBindingRescheduling(t *testing.T) { - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)() config := setupCluster(t, "volume-scheduling-", 2, 0, 0) defer config.teardown() @@ -412,7 +410,6 @@ func TestVolumeBindingDynamicStressSlow(t *testing.T) { } func testVolumeBindingStress(t *testing.T, schedulerResyncPeriod time.Duration, dynamic bool, provisionDelaySeconds int) { - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)() config := setupCluster(t, "volume-binding-stress-", 1, schedulerResyncPeriod, provisionDelaySeconds) defer config.teardown() @@ -502,7 +499,6 @@ func testVolumeBindingStress(t *testing.T, schedulerResyncPeriod time.Duration, } func testVolumeBindingWithAffinity(t *testing.T, anti bool, numNodes, numPods, numPVsFirstNode int) { - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)() config := setupCluster(t, "volume-pod-affinity-", numNodes, 0, 0) defer config.teardown() @@ -629,7 +625,6 @@ func TestVolumeBindingWithAffinity(t *testing.T) { } func TestPVAffinityConflict(t *testing.T) { - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)() config := setupCluster(t, "volume-scheduling-", 3, 0, 0) defer config.teardown() @@ -690,7 +685,6 @@ func TestPVAffinityConflict(t *testing.T) { } func TestVolumeProvision(t *testing.T) { - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)() config := setupCluster(t, "volume-scheduling", 1, 0, 0) defer config.teardown() @@ -830,7 +824,6 @@ func TestVolumeProvision(t *testing.T) { // on provision failure. func TestRescheduleProvisioning(t *testing.T) { // Set feature gates - defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)() controllerCh := make(chan struct{}) context := initTestMaster(t, "reschedule-volume-provision", nil)