diff --git a/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate.go b/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate.go index ebb81425d6..e7226688c9 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate.go +++ b/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate.go @@ -50,10 +50,7 @@ var ( } // DefaultFeatureGate is a shared global FeatureGate. - DefaultFeatureGate = &featureGate{ - known: defaultFeatures, - special: specialFeatures, - } + DefaultFeatureGate FeatureGate = NewFeatureGate() ) type FeatureSpec struct { @@ -75,43 +72,9 @@ const ( type FeatureGate interface { AddFlag(fs *pflag.FlagSet) Set(value string) error - Add(features map[Feature]FeatureSpec) + Enabled(key Feature) bool + Add(features map[Feature]FeatureSpec) error KnownFeatures() []string - - // Every feature gate should add method here following this template: - // - // // owner: @username - // // alpha: v1.4 - // MyFeature() bool - - // owner: @timstclair - // beta: v1.4 - AppArmor() bool - - // owner: @girishkalele - // alpha: v1.4 - ExternalTrafficLocalOnly() bool - - // owner: @saad-ali - // alpha: v1.3 - DynamicVolumeProvisioning() bool - - // owner: @mtaufen - // alpha: v1.4 - DynamicKubeletConfig() bool - - // owner: timstclair - // alpha: v1.5 - StreamingProxyRedirects() bool - - // owner: @pweil- - // alpha: v1.5 - ExperimentalHostUserNamespaceDefaulting() bool - - // owner: @davidopp - // alpha: v1.6 - // TODO: remove when alpha support for affinity is removed - AffinityInAnnotations() bool } // featureGate implements FeatureGate as well as pflag.Value for flag parsing. @@ -137,10 +100,21 @@ func setUnsetAlphaGates(f *featureGate, val bool) { // Set, String, and Type implement pflag.Value var _ pflag.Value = &featureGate{} +func NewFeatureGate() *featureGate { + f := &featureGate{ + known: map[Feature]FeatureSpec{}, + special: specialFeatures, + enabled: map[Feature]bool{}, + } + for k, v := range defaultFeatures { + f.known[k] = v + } + return f +} + // Set Parses a string of the form // "key1=value1,key2=value2,..." into a // map[string]bool of known keys or returns an error. func (f *featureGate) Set(value string) error { - f.enabled = make(map[Feature]bool) for _, s := range strings.Split(value, ",") { if len(s) == 0 { continue diff --git a/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go b/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go index 4fcf22d7ad..c4525ad0c4 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go +++ b/staging/src/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go @@ -119,9 +119,11 @@ func TestFeatureGateFlag(t *testing.T) { } for i, test := range tests { fs := pflag.NewFlagSet("testfeaturegateflag", pflag.ContinueOnError) - f := DefaultFeatureGate - f.known[testAlphaGate] = FeatureSpec{Default: false, PreRelease: Alpha} - f.known[testBetaGate] = FeatureSpec{Default: false, PreRelease: Beta} + f := NewFeatureGate() + f.Add(map[Feature]FeatureSpec{ + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: false, PreRelease: Beta}, + }) f.AddFlag(fs) err := fs.Parse([]string{fmt.Sprintf("--%s=%s", flagName, test.arg)}) @@ -140,15 +142,45 @@ func TestFeatureGateFlag(t *testing.T) { } } +func TestFeatureGateOverride(t *testing.T) { + const testAlphaGate Feature = "TestAlpha" + const testBetaGate Feature = "TestBeta" + + // Don't parse the flag, assert defaults are used. + var f FeatureGate = NewFeatureGate() + f.Add(map[Feature]FeatureSpec{ + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: false, PreRelease: Beta}, + }) + + f.Set("TestAlpha=true,TestBeta=true") + if f.Enabled(testAlphaGate) != true { + t.Errorf("Expected true") + } + if f.Enabled(testBetaGate) != true { + t.Errorf("Expected true") + } + + f.Set("TestAlpha=false") + if f.Enabled(testAlphaGate) != false { + t.Errorf("Expected false") + } + if f.Enabled(testBetaGate) != true { + t.Errorf("Expected true") + } +} + func TestFeatureGateFlagDefaults(t *testing.T) { // gates for testing const testAlphaGate Feature = "TestAlpha" const testBetaGate Feature = "TestBeta" // Don't parse the flag, assert defaults are used. - f := DefaultFeatureGate - f.known[testAlphaGate] = FeatureSpec{Default: false, PreRelease: Alpha} - f.known[testBetaGate] = FeatureSpec{Default: true, PreRelease: Beta} + var f FeatureGate = NewFeatureGate() + f.Add(map[Feature]FeatureSpec{ + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: true, PreRelease: Beta}, + }) if f.Enabled(testAlphaGate) != false { t.Errorf("Expected false")