mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
Stop checking VolumeScheduling feature gate
This commit is contained in:
parent
ffc675163d
commit
73dcfe12da
@ -14,7 +14,6 @@ go_library(
|
|||||||
"//cmd/kube-scheduler/app/options:go_default_library",
|
"//cmd/kube-scheduler/app/options:go_default_library",
|
||||||
"//pkg/api/legacyscheme:go_default_library",
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/controller:go_default_library",
|
"//pkg/controller:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
|
||||||
"//pkg/scheduler:go_default_library",
|
"//pkg/scheduler:go_default_library",
|
||||||
"//pkg/scheduler/algorithmprovider:go_default_library",
|
"//pkg/scheduler/algorithmprovider:go_default_library",
|
||||||
"//pkg/scheduler/api: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/healthz:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/server/mux: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/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/flag:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/globalflag: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/kubernetes/typed/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/tools/leaderelection:go_default_library",
|
"//staging/src/k8s.io/client-go/tools/leaderelection:go_default_library",
|
||||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||||
|
@ -38,17 +38,14 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/server/healthz"
|
"k8s.io/apiserver/pkg/server/healthz"
|
||||||
"k8s.io/apiserver/pkg/server/mux"
|
"k8s.io/apiserver/pkg/server/mux"
|
||||||
"k8s.io/apiserver/pkg/server/routes"
|
"k8s.io/apiserver/pkg/server/routes"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
apiserverflag "k8s.io/apiserver/pkg/util/flag"
|
apiserverflag "k8s.io/apiserver/pkg/util/flag"
|
||||||
"k8s.io/apiserver/pkg/util/globalflag"
|
"k8s.io/apiserver/pkg/util/globalflag"
|
||||||
storageinformers "k8s.io/client-go/informers/storage/v1"
|
|
||||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
"k8s.io/client-go/tools/leaderelection"
|
"k8s.io/client-go/tools/leaderelection"
|
||||||
schedulerserverconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
|
schedulerserverconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
|
||||||
"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
|
"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler"
|
"k8s.io/kubernetes/pkg/scheduler"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/algorithmprovider"
|
"k8s.io/kubernetes/pkg/scheduler/algorithmprovider"
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
|
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.
|
// 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 {
|
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.
|
// Create the scheduler.
|
||||||
sched, err := scheduler.New(cc.Client,
|
sched, err := scheduler.New(cc.Client,
|
||||||
cc.InformerFactory.Core().V1().Nodes(),
|
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.Apps().V1().StatefulSets(),
|
||||||
cc.InformerFactory.Core().V1().Services(),
|
cc.InformerFactory.Core().V1().Services(),
|
||||||
cc.InformerFactory.Policy().V1beta1().PodDisruptionBudgets(),
|
cc.InformerFactory.Policy().V1beta1().PodDisruptionBudgets(),
|
||||||
storageClassInformer,
|
cc.InformerFactory.Storage().V1().StorageClasses(),
|
||||||
cc.Recorder,
|
cc.Recorder,
|
||||||
cc.ComponentConfig.AlgorithmSource,
|
cc.ComponentConfig.AlgorithmSource,
|
||||||
stopCh,
|
stopCh,
|
||||||
@ -335,11 +327,6 @@ func newHealthzHandler(config *kubeschedulerconfig.KubeSchedulerConfiguration, s
|
|||||||
|
|
||||||
// NewSchedulerConfig creates the scheduler configuration. This is exposed for use by tests.
|
// NewSchedulerConfig creates the scheduler configuration. This is exposed for use by tests.
|
||||||
func NewSchedulerConfig(s schedulerserverconfig.CompletedConfig) (*factory.Config, error) {
|
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.
|
// Set up the configurator which can create schedulers from configs.
|
||||||
configurator := factory.NewConfigFactory(&factory.ConfigFactoryArgs{
|
configurator := factory.NewConfigFactory(&factory.ConfigFactoryArgs{
|
||||||
SchedulerName: s.ComponentConfig.SchedulerName,
|
SchedulerName: s.ComponentConfig.SchedulerName,
|
||||||
@ -353,7 +340,7 @@ func NewSchedulerConfig(s schedulerserverconfig.CompletedConfig) (*factory.Confi
|
|||||||
StatefulSetInformer: s.InformerFactory.Apps().V1().StatefulSets(),
|
StatefulSetInformer: s.InformerFactory.Apps().V1().StatefulSets(),
|
||||||
ServiceInformer: s.InformerFactory.Core().V1().Services(),
|
ServiceInformer: s.InformerFactory.Core().V1().Services(),
|
||||||
PdbInformer: s.InformerFactory.Policy().V1beta1().PodDisruptionBudgets(),
|
PdbInformer: s.InformerFactory.Policy().V1beta1().PodDisruptionBudgets(),
|
||||||
StorageClassInformer: storageClassInformer,
|
StorageClassInformer: s.InformerFactory.Storage().V1().StorageClasses(),
|
||||||
HardPodAffinitySymmetricWeight: s.ComponentConfig.HardPodAffinitySymmetricWeight,
|
HardPodAffinitySymmetricWeight: s.ComponentConfig.HardPodAffinitySymmetricWeight,
|
||||||
DisablePreemption: s.ComponentConfig.DisablePreemption,
|
DisablePreemption: s.ComponentConfig.DisablePreemption,
|
||||||
PercentageOfNodesToScore: s.ComponentConfig.PercentageOfNodesToScore,
|
PercentageOfNodesToScore: s.ComponentConfig.PercentageOfNodesToScore,
|
||||||
|
@ -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"))...)
|
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
|
||||||
// Allow setting NodeAffinity if oldPv NodeAffinity was not set
|
if oldPv.Spec.NodeAffinity != nil {
|
||||||
if oldPv.Spec.NodeAffinity != nil {
|
allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.NodeAffinity, oldPv.Spec.NodeAffinity, field.NewPath("nodeAffinity"))...)
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.NodeAffinity, oldPv.Spec.NodeAffinity, field.NewPath("nodeAffinity"))...)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
@ -3168,22 +3166,17 @@ func ValidateTopologySelectorTerm(term core.TopologySelectorTerm, fldPath *field
|
|||||||
exprMap := make(map[string]sets.String)
|
exprMap := make(map[string]sets.String)
|
||||||
exprPath := fldPath.Child("matchLabelExpressions")
|
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 {
|
// Validate no duplicate keys exist.
|
||||||
idxPath := exprPath.Index(i)
|
if _, exists := exprMap[req.Key]; exists {
|
||||||
valueSet, exprErrs := validateTopologySelectorLabelRequirement(req, idxPath)
|
allErrs = append(allErrs, field.Duplicate(idxPath.Child("key"), req.Key))
|
||||||
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
|
|
||||||
}
|
}
|
||||||
} else if len(term.MatchLabelExpressions) != 0 {
|
exprMap[req.Key] = valueSet
|
||||||
allErrs = append(allErrs, field.Forbidden(fldPath, "field is disabled by feature-gate VolumeScheduling"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return exprMap, allErrs
|
return exprMap, allErrs
|
||||||
@ -5336,10 +5329,6 @@ func validateVolumeNodeAffinity(nodeAffinity *core.VolumeNodeAffinity, fldPath *
|
|||||||
return false, allErrs
|
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 {
|
if nodeAffinity.Required != nil {
|
||||||
allErrs = append(allErrs, ValidateNodeSelector(nodeAffinity.Required, fldPath.Child("required"))...)
|
allErrs = append(allErrs, ValidateNodeSelector(nodeAffinity.Required, fldPath.Child("required"))...)
|
||||||
} else {
|
} else {
|
||||||
|
@ -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 {
|
func testVolumeWithNodeAffinity(affinity *core.VolumeNodeAffinity) *core.PersistentVolume {
|
||||||
|
@ -39,7 +39,6 @@ go_test(
|
|||||||
srcs = ["util_test.go"],
|
srcs = ["util_test.go"],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
|
||||||
"//pkg/apis/storage:go_default_library",
|
"//pkg/apis/storage:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
"//pkg/features:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||||
|
@ -24,14 +24,6 @@ import (
|
|||||||
|
|
||||||
// DropDisabledFields removes disabled fields from the StorageClass object.
|
// DropDisabledFields removes disabled fields from the StorageClass object.
|
||||||
func DropDisabledFields(class, oldClass *storage.StorageClass) {
|
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) {
|
if !utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) && !allowVolumeExpansionInUse(oldClass) {
|
||||||
class.AllowVolumeExpansion = nil
|
class.AllowVolumeExpansion = nil
|
||||||
}
|
}
|
||||||
|
@ -24,53 +24,10 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/diff"
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
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/apis/storage"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"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) {
|
func TestDropAllowVolumeExpansion(t *testing.T) {
|
||||||
allowVolumeExpansion := false
|
allowVolumeExpansion := false
|
||||||
scWithoutAllowVolumeExpansion := func() *storage.StorageClass {
|
scWithoutAllowVolumeExpansion := func() *storage.StorageClass {
|
||||||
|
@ -19,13 +19,11 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/apis/storage: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/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/api/storage/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/conversion:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime: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/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 = [
|
deps = [
|
||||||
"//pkg/api/legacyscheme:go_default_library",
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/apis/storage/install: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/api/storage/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime: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",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -20,8 +20,6 @@ import (
|
|||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
storagev1 "k8s.io/api/storage/v1"
|
storagev1 "k8s.io/api/storage/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||||
@ -34,7 +32,7 @@ func SetDefaults_StorageClass(obj *storagev1.StorageClass) {
|
|||||||
*obj.ReclaimPolicy = v1.PersistentVolumeReclaimDelete
|
*obj.ReclaimPolicy = v1.PersistentVolumeReclaimDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.VolumeBindingMode == nil && utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
|
if obj.VolumeBindingMode == nil {
|
||||||
obj.VolumeBindingMode = new(storagev1.VolumeBindingMode)
|
obj.VolumeBindingMode = new(storagev1.VolumeBindingMode)
|
||||||
*obj.VolumeBindingMode = storagev1.VolumeBindingImmediate
|
*obj.VolumeBindingMode = storagev1.VolumeBindingImmediate
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,8 @@ import (
|
|||||||
|
|
||||||
storagev1 "k8s.io/api/storage/v1"
|
storagev1 "k8s.io/api/storage/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"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/api/legacyscheme"
|
||||||
_ "k8s.io/kubernetes/pkg/apis/storage/install"
|
_ "k8s.io/kubernetes/pkg/apis/storage/install"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
|
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) {
|
func TestSetDefaultVolumeBindingMode(t *testing.T) {
|
||||||
class := &storagev1.StorageClass{}
|
class := &storagev1.StorageClass{}
|
||||||
|
|
||||||
// When feature gate is enabled, field should be defaulted
|
// field should be defaulted
|
||||||
defaultMode := storagev1.VolumeBindingImmediate
|
defaultMode := storagev1.VolumeBindingImmediate
|
||||||
output := roundTrip(t, runtime.Object(class)).(*storagev1.StorageClass)
|
output := roundTrip(t, runtime.Object(class)).(*storagev1.StorageClass)
|
||||||
outMode := output.VolumeBindingMode
|
outMode := output.VolumeBindingMode
|
||||||
@ -62,13 +59,4 @@ func TestSetDefaultVolumeBindingMode(t *testing.T) {
|
|||||||
} else if *outMode != defaultMode {
|
} else if *outMode != defaultMode {
|
||||||
t.Errorf("Expected VolumeBindingMode to be defaulted to: %+v, got: %+v", defaultMode, outMode)
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,11 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/apis/storage: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/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/api/storage/v1beta1: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/conversion:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime: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/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 = [
|
deps = [
|
||||||
"//pkg/api/legacyscheme:go_default_library",
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/apis/storage/install: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/api/storage/v1beta1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime: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",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -20,8 +20,6 @@ import (
|
|||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||||
@ -34,7 +32,7 @@ func SetDefaults_StorageClass(obj *storagev1beta1.StorageClass) {
|
|||||||
*obj.ReclaimPolicy = v1.PersistentVolumeReclaimDelete
|
*obj.ReclaimPolicy = v1.PersistentVolumeReclaimDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.VolumeBindingMode == nil && utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
|
if obj.VolumeBindingMode == nil {
|
||||||
obj.VolumeBindingMode = new(storagev1beta1.VolumeBindingMode)
|
obj.VolumeBindingMode = new(storagev1beta1.VolumeBindingMode)
|
||||||
*obj.VolumeBindingMode = storagev1beta1.VolumeBindingImmediate
|
*obj.VolumeBindingMode = storagev1beta1.VolumeBindingImmediate
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,8 @@ import (
|
|||||||
|
|
||||||
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"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/api/legacyscheme"
|
||||||
_ "k8s.io/kubernetes/pkg/apis/storage/install"
|
_ "k8s.io/kubernetes/pkg/apis/storage/install"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
|
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) {
|
func TestSetDefaultVolumeBindingMode(t *testing.T) {
|
||||||
class := &storagev1beta1.StorageClass{}
|
class := &storagev1beta1.StorageClass{}
|
||||||
|
|
||||||
// When feature gate is enabled, field should be defaulted
|
// field should be defaulted
|
||||||
defaultMode := storagev1beta1.VolumeBindingImmediate
|
defaultMode := storagev1beta1.VolumeBindingImmediate
|
||||||
output := roundTrip(t, runtime.Object(class)).(*storagev1beta1.StorageClass)
|
output := roundTrip(t, runtime.Object(class)).(*storagev1beta1.StorageClass)
|
||||||
outMode := output.VolumeBindingMode
|
outMode := output.VolumeBindingMode
|
||||||
@ -62,14 +59,4 @@ func TestSetDefaultVolumeBindingMode(t *testing.T) {
|
|||||||
} else if *outMode != defaultMode {
|
} else if *outMode != defaultMode {
|
||||||
t.Errorf("Expected VolumeBindingMode to be defaulted to: %+v, got: %+v", defaultMode, outMode)
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,10 @@ go_library(
|
|||||||
"//pkg/apis/core/helper:go_default_library",
|
"//pkg/apis/core/helper:go_default_library",
|
||||||
"//pkg/apis/core/validation:go_default_library",
|
"//pkg/apis/core/validation:go_default_library",
|
||||||
"//pkg/apis/storage: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/api/equality:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets: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:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field: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 = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/apis/storage: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/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",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,12 +24,10 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/validation"
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||||
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
|
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/apis/storage"
|
"k8s.io/kubernetes/pkg/apis/storage"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -233,14 +231,10 @@ var supportedVolumeBindingModes = sets.NewString(string(storage.VolumeBindingImm
|
|||||||
// validateVolumeBindingMode tests that VolumeBindingMode specifies valid values.
|
// validateVolumeBindingMode tests that VolumeBindingMode specifies valid values.
|
||||||
func validateVolumeBindingMode(mode *storage.VolumeBindingMode, fldPath *field.Path) field.ErrorList {
|
func validateVolumeBindingMode(mode *storage.VolumeBindingMode, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
|
if mode == nil {
|
||||||
if mode == nil {
|
allErrs = append(allErrs, field.Required(fldPath, ""))
|
||||||
allErrs = append(allErrs, field.Required(fldPath, ""))
|
} else if !supportedVolumeBindingModes.Has(string(*mode)) {
|
||||||
} else if !supportedVolumeBindingModes.Has(string(*mode)) {
|
allErrs = append(allErrs, field.NotSupported(fldPath, mode, supportedVolumeBindingModes.List()))
|
||||||
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"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
@ -254,10 +248,6 @@ func validateAllowedTopologies(topologies []api.TopologySelectorTerm, fldPath *f
|
|||||||
return allErrs
|
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))
|
rawTopologies := make([]map[string]sets.String, len(topologies))
|
||||||
for i, term := range topologies {
|
for i, term := range topologies {
|
||||||
idxPath := fldPath.Index(i)
|
idxPath := fldPath.Index(i)
|
||||||
|
@ -22,11 +22,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
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"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/storage"
|
"k8s.io/kubernetes/pkg/apis/storage"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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 {
|
type bindingTest struct {
|
||||||
class *storage.StorageClass
|
class *storage.StorageClass
|
||||||
shouldSucceed bool
|
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 {
|
for testName, testCase := range cases {
|
||||||
errs := ValidateStorageClass(testCase.class)
|
errs := ValidateStorageClass(testCase.class)
|
||||||
if testCase.shouldSucceed && len(errs) != 0 {
|
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 {
|
for testName, testCase := range cases {
|
||||||
errs := ValidateStorageClassUpdate(testCase.newClass, testCase.oldClass)
|
errs := ValidateStorageClassUpdate(testCase.newClass, testCase.oldClass)
|
||||||
if testCase.shouldSucceed && len(errs) != 0 {
|
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 {
|
for testName, testCase := range cases {
|
||||||
errs := ValidateStorageClass(testCase.class)
|
errs := ValidateStorageClass(testCase.class)
|
||||||
if testCase.shouldSucceed && len(errs) != 0 {
|
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)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ go_library(
|
|||||||
"//pkg/api/v1/node:go_default_library",
|
"//pkg/api/v1/node:go_default_library",
|
||||||
"//pkg/apis/core/v1/helper:go_default_library",
|
"//pkg/apis/core/v1/helper:go_default_library",
|
||||||
"//pkg/controller:go_default_library",
|
"//pkg/controller:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
|
||||||
"//pkg/kubelet/apis:go_default_library",
|
"//pkg/kubelet/apis:go_default_library",
|
||||||
"//pkg/scheduler/api:go_default_library",
|
"//pkg/scheduler/api:go_default_library",
|
||||||
"//pkg/util/node: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/strategicpatch:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait: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/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/informers/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/kubernetes/scheme: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/cloudprovider/providers/fake:go_default_library",
|
||||||
"//pkg/controller:go_default_library",
|
"//pkg/controller:go_default_library",
|
||||||
"//pkg/controller/testutil:go_default_library",
|
"//pkg/controller/testutil:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
|
||||||
"//pkg/kubelet/apis:go_default_library",
|
"//pkg/kubelet/apis:go_default_library",
|
||||||
"//pkg/scheduler/api:go_default_library",
|
"//pkg/scheduler/api:go_default_library",
|
||||||
"//pkg/volume/util: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/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/types: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/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:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/informers/core/v1: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",
|
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||||
|
@ -33,7 +33,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
corelisters "k8s.io/client-go/listers/core/v1"
|
corelisters "k8s.io/client-go/listers/core/v1"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
@ -41,7 +40,6 @@ import (
|
|||||||
cloudprovider "k8s.io/cloud-provider"
|
cloudprovider "k8s.io/cloud-provider"
|
||||||
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
volumeutil "k8s.io/kubernetes/pkg/volume/util"
|
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) {
|
func (pvlc *PersistentVolumeLabelController) createPatch(vol *v1.PersistentVolume, volLabels map[string]string) ([]byte, error) {
|
||||||
volName := vol.Name
|
volName := vol.Name
|
||||||
newVolume := vol.DeepCopyObject().(*v1.PersistentVolume)
|
newVolume := vol.DeepCopyObject().(*v1.PersistentVolume)
|
||||||
populateAffinity := utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) && len(volLabels) != 0
|
populateAffinity := len(volLabels) != 0
|
||||||
|
|
||||||
if newVolume.Labels == nil {
|
if newVolume.Labels == nil {
|
||||||
newVolume.Labels = make(map[string]string)
|
newVolume.Labels = make(map[string]string)
|
||||||
|
@ -27,11 +27,8 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
|
||||||
sets "k8s.io/apimachinery/pkg/util/sets"
|
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"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
core "k8s.io/client-go/testing"
|
core "k8s.io/client-go/testing"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
volumeutil "k8s.io/kubernetes/pkg/volume/util"
|
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 {
|
for d, tc := range testCases {
|
||||||
cloud := &fakecloud.FakeCloud{}
|
cloud := &fakecloud.FakeCloud{}
|
||||||
client := fake.NewSimpleClientset()
|
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 {
|
for d, tc := range testCases {
|
||||||
labeledCh := make(chan bool, 1)
|
labeledCh := make(chan bool, 1)
|
||||||
client := fake.NewSimpleClientset()
|
client := fake.NewSimpleClientset()
|
||||||
|
@ -286,10 +286,6 @@ func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctrl *PersistentVolumeController) shouldDelayBinding(claim *v1.PersistentVolumeClaim) (bool, error) {
|
func (ctrl *PersistentVolumeController) shouldDelayBinding(claim *v1.PersistentVolumeClaim) (bool, error) {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// When feature VolumeScheduling enabled,
|
// When feature VolumeScheduling enabled,
|
||||||
// Scheduler signal to the PV controller to start dynamic
|
// Scheduler signal to the PV controller to start dynamic
|
||||||
// provisioning by setting the "annSelectedNode" annotation
|
// provisioning by setting the "annSelectedNode" annotation
|
||||||
|
@ -24,15 +24,12 @@ import (
|
|||||||
storagev1 "k8s.io/api/storage/v1"
|
storagev1 "k8s.io/api/storage/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"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/informers"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
core "k8s.io/client-go/testing"
|
core "k8s.io/client-go/testing"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -413,7 +413,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
|
|||||||
PodShareProcessNamespace: {Default: true, PreRelease: utilfeature.Beta},
|
PodShareProcessNamespace: {Default: true, PreRelease: utilfeature.Beta},
|
||||||
PodPriority: {Default: true, PreRelease: utilfeature.Beta},
|
PodPriority: {Default: true, PreRelease: utilfeature.Beta},
|
||||||
TaintNodesByCondition: {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},
|
QOSReserved: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
ExpandPersistentVolumes: {Default: true, PreRelease: utilfeature.Beta},
|
ExpandPersistentVolumes: {Default: true, PreRelease: utilfeature.Beta},
|
||||||
ExpandInUsePersistentVolumes: {Default: false, PreRelease: utilfeature.Alpha},
|
ExpandInUsePersistentVolumes: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
@ -422,7 +422,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
|
|||||||
CPUCFSQuotaPeriod: {Default: false, PreRelease: utilfeature.Alpha},
|
CPUCFSQuotaPeriod: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
ServiceNodeExclusion: {Default: false, PreRelease: utilfeature.Alpha},
|
ServiceNodeExclusion: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
MountContainers: {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},
|
CSIPersistentVolume: {Default: true, PreRelease: utilfeature.GA},
|
||||||
CSIDriverRegistry: {Default: false, PreRelease: utilfeature.Alpha},
|
CSIDriverRegistry: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
CSINodeInfo: {Default: false, PreRelease: utilfeature.Alpha},
|
CSINodeInfo: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
|
@ -9,7 +9,6 @@ go_library(
|
|||||||
importpath = "k8s.io/kubernetes/pkg/scheduler",
|
importpath = "k8s.io/kubernetes/pkg/scheduler",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/features:go_default_library",
|
|
||||||
"//pkg/scheduler/algorithm:go_default_library",
|
"//pkg/scheduler/algorithm:go_default_library",
|
||||||
"//pkg/scheduler/algorithm/predicates:go_default_library",
|
"//pkg/scheduler/algorithm/predicates:go_default_library",
|
||||||
"//pkg/scheduler/api: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/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets: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/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/apps/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/informers/core/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",
|
"//staging/src/k8s.io/client-go/informers/policy/v1beta1:go_default_library",
|
||||||
@ -46,7 +44,6 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/legacyscheme:go_default_library",
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/controller/volume/persistentvolume:go_default_library",
|
"//pkg/controller/volume/persistentvolume:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
|
||||||
"//pkg/scheduler/algorithm:go_default_library",
|
"//pkg/scheduler/algorithm:go_default_library",
|
||||||
"//pkg/scheduler/algorithm/predicates:go_default_library",
|
"//pkg/scheduler/algorithm/predicates:go_default_library",
|
||||||
"//pkg/scheduler/api: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/diff:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets: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/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/informers:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/kubernetes/fake: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",
|
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
|
||||||
|
@ -635,18 +635,16 @@ func (c *VolumeZoneChecker) predicate(pod *v1.Pod, meta PredicateMetadata, nodeI
|
|||||||
|
|
||||||
pvName := pvc.Spec.VolumeName
|
pvName := pvc.Spec.VolumeName
|
||||||
if pvName == "" {
|
if pvName == "" {
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
|
scName := v1helper.GetPersistentVolumeClaimClass(pvc)
|
||||||
scName := v1helper.GetPersistentVolumeClaimClass(pvc)
|
if len(scName) > 0 {
|
||||||
if len(scName) > 0 {
|
class, _ := c.classInfo.GetStorageClassInfo(scName)
|
||||||
class, _ := c.classInfo.GetStorageClassInfo(scName)
|
if class != nil {
|
||||||
if class != nil {
|
if class.VolumeBindingMode == nil {
|
||||||
if class.VolumeBindingMode == nil {
|
return false, nil, fmt.Errorf("VolumeBindingMode not set for StorageClass %q", scName)
|
||||||
return false, nil, fmt.Errorf("VolumeBindingMode not set for StorageClass %q", scName)
|
}
|
||||||
}
|
if *class.VolumeBindingMode == storagev1.VolumeBindingWaitForFirstConsumer {
|
||||||
if *class.VolumeBindingMode == storagev1.VolumeBindingWaitForFirstConsumer {
|
// Skip unbound volumes
|
||||||
// Skip unbound volumes
|
continue
|
||||||
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) {
|
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()
|
node := nodeInfo.Node()
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return false, nil, fmt.Errorf("node not found")
|
return false, nil, fmt.Errorf("node not found")
|
||||||
|
@ -29,10 +29,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"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"
|
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
|
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
|
||||||
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
|
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 {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
fit := NewVolumeZonePredicate(pvInfo, pvcInfo, classInfo)
|
fit := NewVolumeZonePredicate(pvInfo, pvcInfo, classInfo)
|
||||||
|
@ -12,7 +12,6 @@ go_library(
|
|||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/v1/pod:go_default_library",
|
"//pkg/api/v1/pod:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
|
||||||
"//pkg/kubelet/apis:go_default_library",
|
"//pkg/kubelet/apis:go_default_library",
|
||||||
"//pkg/scheduler/algorithm:go_default_library",
|
"//pkg/scheduler/algorithm:go_default_library",
|
||||||
"//pkg/scheduler/algorithm/predicates: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/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets: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/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/apps/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/informers/core/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",
|
"//staging/src/k8s.io/client-go/informers/policy/v1beta1:go_default_library",
|
||||||
|
@ -38,7 +38,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/runtime"
|
"k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
appsinformers "k8s.io/client-go/informers/apps/v1"
|
appsinformers "k8s.io/client-go/informers/apps/v1"
|
||||||
coreinformers "k8s.io/client-go/informers/core/v1"
|
coreinformers "k8s.io/client-go/informers/core/v1"
|
||||||
policyinformers "k8s.io/client-go/informers/policy/v1beta1"
|
policyinformers "k8s.io/client-go/informers/policy/v1beta1"
|
||||||
@ -51,7 +50,6 @@ import (
|
|||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/algorithm"
|
"k8s.io/kubernetes/pkg/scheduler/algorithm"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
|
"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
|
||||||
// Setup volume binder
|
c.volumeBinder = volumebinder.NewVolumeBinder(args.Client, args.PvcInformer, args.PvInformer, args.StorageClassInformer, time.Duration(args.BindTimeoutSeconds)*time.Second)
|
||||||
c.volumeBinder = volumebinder.NewVolumeBinder(args.Client, args.PvcInformer, args.PvInformer, args.StorageClassInformer, time.Duration(args.BindTimeoutSeconds)*time.Second)
|
|
||||||
|
|
||||||
args.StorageClassInformer.Informer().AddEventHandler(
|
args.StorageClassInformer.Informer().AddEventHandler(
|
||||||
cache.ResourceEventHandlerFuncs{
|
cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: c.onStorageClassAdd,
|
AddFunc: c.onStorageClassAdd,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
// Setup cache comparer
|
// Setup cache comparer
|
||||||
debugger := cachedebugger.New(
|
debugger := cachedebugger.New(
|
||||||
@ -491,9 +487,6 @@ func (c *configFactory) onPvcAdd(obj interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *configFactory) onPvcUpdate(old, new interface{}) {
|
func (c *configFactory) onPvcUpdate(old, new interface{}) {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.podQueue.MoveAllToActiveQueue()
|
c.podQueue.MoveAllToActiveQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,14 +29,12 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
appsinformers "k8s.io/client-go/informers/apps/v1"
|
appsinformers "k8s.io/client-go/informers/apps/v1"
|
||||||
coreinformers "k8s.io/client-go/informers/core/v1"
|
coreinformers "k8s.io/client-go/informers/core/v1"
|
||||||
policyinformers "k8s.io/client-go/informers/policy/v1beta1"
|
policyinformers "k8s.io/client-go/informers/policy/v1beta1"
|
||||||
storageinformers "k8s.io/client-go/informers/storage/v1"
|
storageinformers "k8s.io/client-go/informers/storage/v1"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
|
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
|
||||||
latestschedulerapi "k8s.io/kubernetes/pkg/scheduler/api/latest"
|
latestschedulerapi "k8s.io/kubernetes/pkg/scheduler/api/latest"
|
||||||
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
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.
|
// This function modifies assumed if volume binding is required.
|
||||||
func (sched *Scheduler) assumeVolumes(assumed *v1.Pod, host string) (allBound bool, err error) {
|
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)
|
||||||
allBound, err = sched.config.VolumeBinder.Binder.AssumePodVolumes(assumed, host)
|
if err != nil {
|
||||||
if err != nil {
|
sched.recordSchedulingFailure(assumed, err, SchedulerError,
|
||||||
sched.recordSchedulingFailure(assumed, err, SchedulerError,
|
fmt.Sprintf("AssumePodVolumes failed: %v", err))
|
||||||
fmt.Sprintf("AssumePodVolumes failed: %v", err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/diff"
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"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"
|
"k8s.io/client-go/informers"
|
||||||
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
||||||
corelister "k8s.io/client-go/listers/core/v1"
|
corelister "k8s.io/client-go/listers/core/v1"
|
||||||
@ -41,7 +39,6 @@ import (
|
|||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/controller/volume/persistentvolume"
|
"k8s.io/kubernetes/pkg/controller/volume/persistentvolume"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/algorithm"
|
"k8s.io/kubernetes/pkg/scheduler/algorithm"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
|
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/api"
|
"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
|
// This can be small because we wait for pod to finish scheduling first
|
||||||
chanTimeout := 2 * time.Second
|
chanTimeout := 2 * time.Second
|
||||||
|
|
||||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)()
|
|
||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
expectError error
|
expectError error
|
||||||
|
@ -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 = new(v1.VolumeNodeAffinity)
|
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
|
||||||
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
|
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1)
|
||||||
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1)
|
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements
|
||||||
pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements
|
|
||||||
}
|
|
||||||
|
|
||||||
return pv, nil
|
return pv, nil
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
if zoned {
|
||||||
// Set node affinity labels based on availability zone labels.
|
// Set node affinity labels based on availability zone labels.
|
||||||
if len(labels) > 0 {
|
if len(labels) > 0 {
|
||||||
requirements := make([]v1.NodeSelectorRequirement, 0)
|
requirements := make([]v1.NodeSelectorRequirement, 0)
|
||||||
for k, v := range labels {
|
for k, v := range labels {
|
||||||
requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}})
|
requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}})
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{
|
nodeSelectorTerms = append(nodeSelectorTerms, v1.NodeSelectorTerm{
|
||||||
MatchExpressions: requirements,
|
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if len(nodeSelectorTerms) > 0 {
|
// Set node affinity labels based on fault domains.
|
||||||
pv.Spec.NodeAffinity = &v1.VolumeNodeAffinity{
|
// This is required because unzoned AzureDisk can't be attached to zoned nodes.
|
||||||
Required: &v1.NodeSelector{
|
// There are at most 3 fault domains available in each region.
|
||||||
NodeSelectorTerms: nodeSelectorTerms,
|
// 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,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,20 +561,18 @@ func (c *cinderVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopolo
|
|||||||
pv.Spec.AccessModes = c.plugin.GetAccessModes()
|
pv.Spec.AccessModes = c.plugin.GetAccessModes()
|
||||||
}
|
}
|
||||||
|
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
|
requirements := make([]v1.NodeSelectorRequirement, 0)
|
||||||
requirements := make([]v1.NodeSelectorRequirement, 0)
|
for k, v := range labels {
|
||||||
for k, v := range labels {
|
if v != "" {
|
||||||
if v != "" {
|
requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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
|
return pv, nil
|
||||||
}
|
}
|
||||||
|
@ -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 = new(v1.VolumeNodeAffinity)
|
||||||
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
|
pv.Spec.NodeAffinity.Required = new(v1.NodeSelector)
|
||||||
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1)
|
pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1)
|
||||||
|
@ -60,7 +60,6 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core/install:go_default_library",
|
"//pkg/apis/core/install:go_default_library",
|
||||||
"//pkg/apis/core/v1/helper:go_default_library",
|
"//pkg/apis/core/v1/helper:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
|
||||||
"//pkg/kubelet/apis:go_default_library",
|
"//pkg/kubelet/apis:go_default_library",
|
||||||
"//pkg/util/mount:go_default_library",
|
"//pkg/util/mount:go_default_library",
|
||||||
"//pkg/util/slice: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/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/types: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/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",
|
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -24,7 +24,6 @@ import (
|
|||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
|
||||||
utiltesting "k8s.io/client-go/util/testing"
|
utiltesting "k8s.io/client-go/util/testing"
|
||||||
|
|
||||||
// util.go uses api.Codecs.LegacyCodec so import this package to do some
|
// util.go uses api.Codecs.LegacyCodec so import this package to do some
|
||||||
@ -32,7 +31,6 @@ import (
|
|||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
|
|
||||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
|
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -40,7 +38,6 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/util/slice"
|
"k8s.io/kubernetes/pkg/util/slice"
|
||||||
@ -1065,7 +1062,6 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
ZonesWithNodes string
|
ZonesWithNodes string
|
||||||
Node *v1.Node
|
Node *v1.Node
|
||||||
AllowedTopologies []v1.TopologySelectorTerm
|
AllowedTopologies []v1.TopologySelectorTerm
|
||||||
VolumeScheduling bool
|
|
||||||
// Expectations around returned zone from SelectZoneForVolume
|
// Expectations around returned zone from SelectZoneForVolume
|
||||||
Reject bool // expect error due to validation failing
|
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)
|
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
|
// [1] Node irrelevant
|
||||||
// [2] Zone and Zones parameters presents
|
// [2] Zone and Zones parameters presents
|
||||||
// [3] AllowedTopologies irrelevant
|
// [3] AllowedTopologies irrelevant
|
||||||
// [4] VolumeScheduling irrelevant
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_with_Zone_Zones_parameters_present",
|
Name: "Nil_Node_with_Zone_Zones_parameters_present",
|
||||||
ZonePresent: true,
|
ZonePresent: true,
|
||||||
@ -1092,53 +1087,45 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
// [1] Node with no zone labels
|
// [1] Node with no zone labels
|
||||||
// [2] Zone/Zones parameter irrelevant
|
// [2] Zone/Zones parameter irrelevant
|
||||||
// [3] AllowedTopologies irrelevant
|
// [3] AllowedTopologies irrelevant
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Node_with_no_Zone_labels",
|
Name: "Node_with_no_Zone_labels",
|
||||||
Node: nodeWithNoLabels,
|
Node: nodeWithNoLabels,
|
||||||
VolumeScheduling: true,
|
Reject: true,
|
||||||
Reject: true,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Node with Zone labels as well as Zone parameter specified [Fail]
|
// Node with Zone labels as well as Zone parameter specified [Fail]
|
||||||
// [1] Node with zone labels
|
// [1] Node with zone labels
|
||||||
// [2] Zone parameter specified
|
// [2] Zone parameter specified
|
||||||
// [3] AllowedTopologies irrelevant
|
// [3] AllowedTopologies irrelevant
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Node_with_Zone_labels_and_Zone_parameter_present",
|
Name: "Node_with_Zone_labels_and_Zone_parameter_present",
|
||||||
Node: nodeWithZoneLabels,
|
Node: nodeWithZoneLabels,
|
||||||
ZonePresent: true,
|
ZonePresent: true,
|
||||||
Zone: "zoneX",
|
Zone: "zoneX",
|
||||||
VolumeScheduling: true,
|
Reject: true,
|
||||||
Reject: true,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Node with Zone labels as well as Zones parameter specified [Fail]
|
// Node with Zone labels as well as Zones parameter specified [Fail]
|
||||||
// [1] Node with zone labels
|
// [1] Node with zone labels
|
||||||
// [2] Zones parameter specified
|
// [2] Zones parameter specified
|
||||||
// [3] AllowedTopologies irrelevant
|
// [3] AllowedTopologies irrelevant
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Node_with_Zone_labels_and_Zones_parameter_present",
|
Name: "Node_with_Zone_labels_and_Zones_parameter_present",
|
||||||
Node: nodeWithZoneLabels,
|
Node: nodeWithZoneLabels,
|
||||||
ZonesPresent: true,
|
ZonesPresent: true,
|
||||||
Zones: "zoneX,zoneY",
|
Zones: "zoneX,zoneY",
|
||||||
VolumeScheduling: true,
|
Reject: true,
|
||||||
Reject: true,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Zone parameter as well as AllowedTopologies specified [Fail]
|
// Zone parameter as well as AllowedTopologies specified [Fail]
|
||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] Zone parameter specified
|
// [2] Zone parameter specified
|
||||||
// [3] AllowedTopologies specified
|
// [3] AllowedTopologies specified
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_and_Zone_parameter_and_Allowed_Topology_term",
|
Name: "Nil_Node_and_Zone_parameter_and_Allowed_Topology_term",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
ZonePresent: true,
|
ZonePresent: true,
|
||||||
Zone: "zoneX",
|
Zone: "zoneX",
|
||||||
VolumeScheduling: true,
|
|
||||||
AllowedTopologies: []v1.TopologySelectorTerm{
|
AllowedTopologies: []v1.TopologySelectorTerm{
|
||||||
{
|
{
|
||||||
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
||||||
@ -1156,13 +1143,11 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] Zones parameter specified
|
// [2] Zones parameter specified
|
||||||
// [3] AllowedTopologies specified
|
// [3] AllowedTopologies specified
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_and_Zones_parameter_and_Allowed_Topology_term",
|
Name: "Nil_Node_and_Zones_parameter_and_Allowed_Topology_term",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
ZonesPresent: true,
|
ZonesPresent: true,
|
||||||
Zones: "zoneX,zoneY",
|
Zones: "zoneX,zoneY",
|
||||||
VolumeScheduling: true,
|
|
||||||
AllowedTopologies: []v1.TopologySelectorTerm{
|
AllowedTopologies: []v1.TopologySelectorTerm{
|
||||||
{
|
{
|
||||||
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
||||||
@ -1180,11 +1165,9 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] no Zone/Zones parameter
|
// [2] no Zone/Zones parameter
|
||||||
// [3] AllowedTopologies with invalid key specified
|
// [3] AllowedTopologies with invalid key specified
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_and_Invalid_Allowed_Topology_Key",
|
Name: "Nil_Node_and_Invalid_Allowed_Topology_Key",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
VolumeScheduling: true,
|
|
||||||
AllowedTopologies: []v1.TopologySelectorTerm{
|
AllowedTopologies: []v1.TopologySelectorTerm{
|
||||||
{
|
{
|
||||||
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
||||||
@ -1206,11 +1189,9 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] no Zone/Zones parameter
|
// [2] no Zone/Zones parameter
|
||||||
// [3] Invalid AllowedTopologies
|
// [3] Invalid AllowedTopologies
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_and_Invalid_AllowedTopologies",
|
Name: "Nil_Node_and_Invalid_AllowedTopologies",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
VolumeScheduling: true,
|
|
||||||
AllowedTopologies: []v1.TopologySelectorTerm{
|
AllowedTopologies: []v1.TopologySelectorTerm{
|
||||||
{
|
{
|
||||||
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{},
|
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{},
|
||||||
@ -1219,77 +1200,29 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
Reject: true,
|
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
|
// POSITIVE TESTS WITH VolumeScheduling ENABLED
|
||||||
|
|
||||||
// Select zone from active zones [Pass]
|
// Select zone from active zones [Pass]
|
||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] no Zone parameter specified
|
// [2] no Zone parameter specified
|
||||||
// [3] no AllowedTopologies
|
// [3] no AllowedTopologies
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_and_No_Zone_Zones_parameter_and_no_Allowed_topologies_and_VolumeScheduling_enabled",
|
Name: "Nil_Node_and_No_Zone_Zones_parameter_and_no_Allowed_topologies_and_VolumeScheduling_enabled",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
ZonesWithNodes: "zoneX,zoneY",
|
ZonesWithNodes: "zoneX,zoneY",
|
||||||
VolumeScheduling: true,
|
Reject: false,
|
||||||
Reject: false,
|
ExpectedZones: "zoneX,zoneY",
|
||||||
ExpectedZones: "zoneX,zoneY",
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Select zone from single zone parameter [Pass]
|
// Select zone from single zone parameter [Pass]
|
||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] Zone parameter specified
|
// [2] Zone parameter specified
|
||||||
// [3] no AllowedTopology specified
|
// [3] no AllowedTopology specified
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_and_Zone_parameter_present_and_VolumeScheduling_enabled",
|
Name: "Nil_Node_and_Zone_parameter_present_and_VolumeScheduling_enabled",
|
||||||
ZonePresent: true,
|
ZonePresent: true,
|
||||||
Zone: "zoneX",
|
Zone: "zoneX",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
VolumeScheduling: true,
|
|
||||||
Reject: false,
|
Reject: false,
|
||||||
ExpectSpecificZone: true,
|
ExpectSpecificZone: true,
|
||||||
ExpectedZone: "zoneX",
|
ExpectedZone: "zoneX",
|
||||||
@ -1299,26 +1232,22 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] Zones parameter specified
|
// [2] Zones parameter specified
|
||||||
// [3] no AllowedTopology
|
// [3] no AllowedTopology
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_and_Zones_parameter_present_and_VolumeScheduling_enabled",
|
Name: "Nil_Node_and_Zones_parameter_present_and_VolumeScheduling_enabled",
|
||||||
ZonesPresent: true,
|
ZonesPresent: true,
|
||||||
Zones: "zoneX,zoneY",
|
Zones: "zoneX,zoneY",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
VolumeScheduling: true,
|
Reject: false,
|
||||||
Reject: false,
|
ExpectedZones: "zoneX,zoneY",
|
||||||
ExpectedZones: "zoneX,zoneY",
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Select zone from node label [Pass]
|
// Select zone from node label [Pass]
|
||||||
// [1] Node with zone labels
|
// [1] Node with zone labels
|
||||||
// [2] no zone/zones parameters
|
// [2] no zone/zones parameters
|
||||||
// [3] no AllowedTopology
|
// [3] no AllowedTopology
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Node_with_Zone_labels_and_VolumeScheduling_enabled",
|
Name: "Node_with_Zone_labels_and_VolumeScheduling_enabled",
|
||||||
Node: nodeWithZoneLabels,
|
Node: nodeWithZoneLabels,
|
||||||
VolumeScheduling: true,
|
|
||||||
Reject: false,
|
Reject: false,
|
||||||
ExpectSpecificZone: true,
|
ExpectSpecificZone: true,
|
||||||
ExpectedZone: "zoneX",
|
ExpectedZone: "zoneX",
|
||||||
@ -1328,11 +1257,9 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
// [1] Node with zone labels
|
// [1] Node with zone labels
|
||||||
// [2] no Zone/Zones parameters
|
// [2] no Zone/Zones parameters
|
||||||
// [3] AllowedTopology with single term with multiple values specified (ignored)
|
// [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",
|
Name: "Node_with_Zone_labels_and_Multiple_Allowed_Topology_values_and_VolumeScheduling_enabled",
|
||||||
Node: nodeWithZoneLabels,
|
Node: nodeWithZoneLabels,
|
||||||
VolumeScheduling: true,
|
|
||||||
AllowedTopologies: []v1.TopologySelectorTerm{
|
AllowedTopologies: []v1.TopologySelectorTerm{
|
||||||
{
|
{
|
||||||
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
||||||
@ -1352,11 +1279,9 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] no Zone/Zones parametes specified
|
// [2] no Zone/Zones parametes specified
|
||||||
// [3] AllowedTopologies with single term with multiple values specified
|
// [3] AllowedTopologies with single term with multiple values specified
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_with_Multiple_Allowed_Topology_values_and_VolumeScheduling_enabled",
|
Name: "Nil_Node_with_Multiple_Allowed_Topology_values_and_VolumeScheduling_enabled",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
VolumeScheduling: true,
|
|
||||||
AllowedTopologies: []v1.TopologySelectorTerm{
|
AllowedTopologies: []v1.TopologySelectorTerm{
|
||||||
{
|
{
|
||||||
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
||||||
@ -1375,11 +1300,9 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] no Zone/Zones parametes specified
|
// [2] no Zone/Zones parametes specified
|
||||||
// [3] AllowedTopologies with multiple terms specified
|
// [3] AllowedTopologies with multiple terms specified
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_and_Multiple_Allowed_Topology_terms_and_VolumeScheduling_enabled",
|
Name: "Nil_Node_and_Multiple_Allowed_Topology_terms_and_VolumeScheduling_enabled",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
VolumeScheduling: true,
|
|
||||||
AllowedTopologies: []v1.TopologySelectorTerm{
|
AllowedTopologies: []v1.TopologySelectorTerm{
|
||||||
{
|
{
|
||||||
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
||||||
@ -1407,11 +1330,9 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
// [1] nil Node
|
// [1] nil Node
|
||||||
// [2] no Zone/Zones parametes specified
|
// [2] no Zone/Zones parametes specified
|
||||||
// [3] AllowedTopologies with single term and value specified
|
// [3] AllowedTopologies with single term and value specified
|
||||||
// [4] VolumeScheduling enabled
|
|
||||||
{
|
{
|
||||||
Name: "Nil_Node_and_Single_Allowed_Topology_term_value_and_VolumeScheduling_enabled",
|
Name: "Nil_Node_and_Single_Allowed_Topology_term_value_and_VolumeScheduling_enabled",
|
||||||
Node: nil,
|
Node: nil,
|
||||||
VolumeScheduling: true,
|
|
||||||
AllowedTopologies: []v1.TopologySelectorTerm{
|
AllowedTopologies: []v1.TopologySelectorTerm{
|
||||||
{
|
{
|
||||||
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
||||||
@ -1430,8 +1351,6 @@ func TestSelectZoneForVolume(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, test.VolumeScheduling)()
|
|
||||||
|
|
||||||
var zonesParameter, zonesWithNodes sets.String
|
var zonesParameter, zonesWithNodes sets.String
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -18,13 +18,11 @@ go_library(
|
|||||||
"//pkg/cloudprovider/providers/aws:go_default_library",
|
"//pkg/cloudprovider/providers/aws:go_default_library",
|
||||||
"//pkg/cloudprovider/providers/azure:go_default_library",
|
"//pkg/cloudprovider/providers/azure:go_default_library",
|
||||||
"//pkg/cloudprovider/providers/gce:go_default_library",
|
"//pkg/cloudprovider/providers/gce:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
|
||||||
"//pkg/kubeapiserver/admission:go_default_library",
|
"//pkg/kubeapiserver/admission:go_default_library",
|
||||||
"//pkg/kubelet/apis:go_default_library",
|
"//pkg/kubelet/apis:go_default_library",
|
||||||
"//pkg/volume:go_default_library",
|
"//pkg/volume:go_default_library",
|
||||||
"//pkg/volume/util: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/admission:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
|
||||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||||
"//vendor/k8s.io/klog:go_default_library",
|
"//vendor/k8s.io/klog:go_default_library",
|
||||||
],
|
],
|
||||||
@ -37,15 +35,12 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/cloudprovider/providers/aws:go_default_library",
|
"//pkg/cloudprovider/providers/aws:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
|
||||||
"//pkg/kubelet/apis:go_default_library",
|
"//pkg/kubelet/apis:go_default_library",
|
||||||
"//pkg/volume/util: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/api/resource:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1: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/apimachinery/pkg/types:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission: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",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,14 +23,12 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
cloudprovider "k8s.io/cloud-provider"
|
cloudprovider "k8s.io/cloud-provider"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
|
"k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/azure"
|
"k8s.io/kubernetes/pkg/cloudprovider/providers/azure"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
|
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
|
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
|
||||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
vol "k8s.io/kubernetes/pkg/volume"
|
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})
|
requirements = append(requirements, api.NodeSelectorRequirement{Key: k, Operator: api.NodeSelectorOpIn, Values: values})
|
||||||
}
|
}
|
||||||
|
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
|
if volume.Spec.NodeAffinity == nil {
|
||||||
if volume.Spec.NodeAffinity == nil {
|
volume.Spec.NodeAffinity = new(api.VolumeNodeAffinity)
|
||||||
volume.Spec.NodeAffinity = new(api.VolumeNodeAffinity)
|
}
|
||||||
}
|
if volume.Spec.NodeAffinity.Required == nil {
|
||||||
if volume.Spec.NodeAffinity.Required == nil {
|
volume.Spec.NodeAffinity.Required = new(api.NodeSelector)
|
||||||
volume.Spec.NodeAffinity.Required = new(api.NodeSelector)
|
}
|
||||||
}
|
if len(volume.Spec.NodeAffinity.Required.NodeSelectorTerms) == 0 {
|
||||||
if len(volume.Spec.NodeAffinity.Required.NodeSelectorTerms) == 0 {
|
// Need at least one term pre-allocated whose MatchExpressions can be appended to
|
||||||
// Need at least one term pre-allocated whose MatchExpressions can be appended to
|
volume.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]api.NodeSelectorTerm, 1)
|
||||||
volume.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]api.NodeSelectorTerm, 1)
|
}
|
||||||
}
|
if nodeSelectorRequirementKeysExistInNodeSelectorTerms(requirements, volume.Spec.NodeAffinity.Required.NodeSelectorTerms) {
|
||||||
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.",
|
||||||
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)
|
||||||
requirements, volume.Spec.NodeAffinity)
|
} else {
|
||||||
} else {
|
for _, req := range requirements {
|
||||||
for _, req := range requirements {
|
for i := range volume.Spec.NodeAffinity.Required.NodeSelectorTerms {
|
||||||
for i := range volume.Spec.NodeAffinity.Required.NodeSelectorTerms {
|
volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions = append(volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions, req)
|
||||||
volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions = append(volume.Spec.NodeAffinity.Required.NodeSelectorTerms[i].MatchExpressions, req)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,8 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"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"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
|
"k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
volumeutil "k8s.io/kubernetes/pkg/volume/util"
|
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
|
// 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))
|
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 {
|
if err != nil {
|
||||||
|
@ -489,17 +489,14 @@ func ClusterRoles() []rbacv1.ClusterRole {
|
|||||||
rbacv1helpers.NewRule("create").Groups(certificatesGroup).Resources("certificatesigningrequests/selfnodeclient").RuleOrDie(),
|
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"},
|
ObjectMeta: metav1.ObjectMeta{Name: "system:volume-scheduler"},
|
||||||
Rules: []rbacv1.PolicyRule{
|
Rules: []rbacv1.PolicyRule{
|
||||||
rbacv1helpers.NewRule(ReadUpdate...).Groups(legacyGroup).Resources("persistentvolumes").RuleOrDie(),
|
rbacv1helpers.NewRule(ReadUpdate...).Groups(legacyGroup).Resources("persistentvolumes").RuleOrDie(),
|
||||||
rbacv1helpers.NewRule(Read...).Groups(storageGroup).Resources("storageclasses").RuleOrDie(),
|
rbacv1helpers.NewRule(Read...).Groups(storageGroup).Resources("storageclasses").RuleOrDie(),
|
||||||
rbacv1helpers.NewRule(ReadUpdate...).Groups(legacyGroup).Resources("persistentvolumeclaims").RuleOrDie(),
|
rbacv1helpers.NewRule(ReadUpdate...).Groups(legacyGroup).Resources("persistentvolumeclaims").RuleOrDie(),
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
externalProvisionerRules := []rbacv1.PolicyRule{
|
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-dns").SAs("kube-system", "kube-dns").BindingOrDie(),
|
||||||
rbacv1helpers.NewClusterBinding("system:kube-scheduler").Users(user.KubeScheduler).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: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 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.
|
// 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)
|
addClusterRoleBindingLabel(rolebindings)
|
||||||
|
|
||||||
return rolebindings
|
return rolebindings
|
||||||
|
@ -63,7 +63,11 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type FeatureSpec struct {
|
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
|
PreRelease prerelease
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,6 +203,9 @@ func (f *featureGate) SetFromMap(m map[string]bool) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unrecognized feature gate: %s", k)
|
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
|
enabled[k] = v
|
||||||
// Handle "special" features like "all alpha gates"
|
// Handle "special" features like "all alpha gates"
|
||||||
if fn, found := f.special[k]; found {
|
if fn, found := f.special[k]; found {
|
||||||
|
@ -221,6 +221,8 @@ func TestFeatureGateSetFromMap(t *testing.T) {
|
|||||||
// gates for testing
|
// gates for testing
|
||||||
const testAlphaGate Feature = "TestAlpha"
|
const testAlphaGate Feature = "TestAlpha"
|
||||||
const testBetaGate Feature = "TestBeta"
|
const testBetaGate Feature = "TestBeta"
|
||||||
|
const testLockedTrueGate Feature = "TestLockedTrue"
|
||||||
|
const testLockedFalseGate Feature = "TestLockedFalse"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -270,17 +272,54 @@ func TestFeatureGateSetFromMap(t *testing.T) {
|
|||||||
},
|
},
|
||||||
setmapError: "unrecognized feature gate:",
|
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 {
|
for i, test := range tests {
|
||||||
t.Run(fmt.Sprintf("SetFromMap %s", test.name), func(t *testing.T) {
|
t.Run(fmt.Sprintf("SetFromMap %s", test.name), func(t *testing.T) {
|
||||||
f := NewFeatureGate()
|
f := NewFeatureGate()
|
||||||
f.Add(map[Feature]FeatureSpec{
|
f.Add(map[Feature]FeatureSpec{
|
||||||
testAlphaGate: {Default: false, PreRelease: Alpha},
|
testAlphaGate: {Default: false, PreRelease: Alpha},
|
||||||
testBetaGate: {Default: false, PreRelease: Beta},
|
testBetaGate: {Default: false, PreRelease: Beta},
|
||||||
|
testLockedTrueGate: {Default: true, PreRelease: GA, LockToDefault: true},
|
||||||
|
testLockedFalseGate: {Default: false, PreRelease: GA, LockToDefault: true},
|
||||||
})
|
})
|
||||||
err := f.SetFromMap(test.setmap)
|
err := f.SetFromMap(test.setmap)
|
||||||
if test.setmapError != "" {
|
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)
|
t.Errorf("%d: SetFromMap(%#v) Expected err:%v, Got err:%v", i, test.setmap, test.setmapError, err)
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -97,7 +97,6 @@ type testPVC struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVolumeBinding(t *testing.T) {
|
func TestVolumeBinding(t *testing.T) {
|
||||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)()
|
|
||||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)()
|
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)()
|
||||||
config := setupCluster(t, "volume-scheduling-", 2, 0, 0)
|
config := setupCluster(t, "volume-scheduling-", 2, 0, 0)
|
||||||
defer config.teardown()
|
defer config.teardown()
|
||||||
@ -268,7 +267,6 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
|
|
||||||
// TestVolumeBindingRescheduling tests scheduler will retry scheduling when needed.
|
// TestVolumeBindingRescheduling tests scheduler will retry scheduling when needed.
|
||||||
func TestVolumeBindingRescheduling(t *testing.T) {
|
func TestVolumeBindingRescheduling(t *testing.T) {
|
||||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)()
|
|
||||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)()
|
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)()
|
||||||
config := setupCluster(t, "volume-scheduling-", 2, 0, 0)
|
config := setupCluster(t, "volume-scheduling-", 2, 0, 0)
|
||||||
defer config.teardown()
|
defer config.teardown()
|
||||||
@ -412,7 +410,6 @@ func TestVolumeBindingDynamicStressSlow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testVolumeBindingStress(t *testing.T, schedulerResyncPeriod time.Duration, dynamic bool, provisionDelaySeconds int) {
|
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)()
|
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)()
|
||||||
config := setupCluster(t, "volume-binding-stress-", 1, schedulerResyncPeriod, provisionDelaySeconds)
|
config := setupCluster(t, "volume-binding-stress-", 1, schedulerResyncPeriod, provisionDelaySeconds)
|
||||||
defer config.teardown()
|
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) {
|
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)()
|
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)()
|
||||||
config := setupCluster(t, "volume-pod-affinity-", numNodes, 0, 0)
|
config := setupCluster(t, "volume-pod-affinity-", numNodes, 0, 0)
|
||||||
defer config.teardown()
|
defer config.teardown()
|
||||||
@ -629,7 +625,6 @@ func TestVolumeBindingWithAffinity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPVAffinityConflict(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)()
|
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)()
|
||||||
config := setupCluster(t, "volume-scheduling-", 3, 0, 0)
|
config := setupCluster(t, "volume-scheduling-", 3, 0, 0)
|
||||||
defer config.teardown()
|
defer config.teardown()
|
||||||
@ -690,7 +685,6 @@ func TestPVAffinityConflict(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVolumeProvision(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)()
|
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentLocalVolumes, true)()
|
||||||
config := setupCluster(t, "volume-scheduling", 1, 0, 0)
|
config := setupCluster(t, "volume-scheduling", 1, 0, 0)
|
||||||
defer config.teardown()
|
defer config.teardown()
|
||||||
@ -830,7 +824,6 @@ func TestVolumeProvision(t *testing.T) {
|
|||||||
// on provision failure.
|
// on provision failure.
|
||||||
func TestRescheduleProvisioning(t *testing.T) {
|
func TestRescheduleProvisioning(t *testing.T) {
|
||||||
// Set feature gates
|
// Set feature gates
|
||||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeScheduling, true)()
|
|
||||||
controllerCh := make(chan struct{})
|
controllerCh := make(chan struct{})
|
||||||
|
|
||||||
context := initTestMaster(t, "reschedule-volume-provision", nil)
|
context := initTestMaster(t, "reschedule-volume-provision", nil)
|
||||||
|
Loading…
Reference in New Issue
Block a user