mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #42648 from sttts/sttts-multiple-feature-gate-calls
Automatic merge from submit-queue (batch tested with PRs 42637, 42648) Support multiple --feature-gates flags in the command line Fixes the issue in https://github.com/kubernetes/kubernetes/pull/42647. Before this change the whole set of gates was replaced with new values. Now values are overridden one by one.
This commit is contained in:
		@@ -50,10 +50,7 @@ var (
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// DefaultFeatureGate is a shared global FeatureGate.
 | 
						// DefaultFeatureGate is a shared global FeatureGate.
 | 
				
			||||||
	DefaultFeatureGate = &featureGate{
 | 
						DefaultFeatureGate FeatureGate = NewFeatureGate()
 | 
				
			||||||
		known:   defaultFeatures,
 | 
					 | 
				
			||||||
		special: specialFeatures,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type FeatureSpec struct {
 | 
					type FeatureSpec struct {
 | 
				
			||||||
@@ -75,43 +72,9 @@ const (
 | 
				
			|||||||
type FeatureGate interface {
 | 
					type FeatureGate interface {
 | 
				
			||||||
	AddFlag(fs *pflag.FlagSet)
 | 
						AddFlag(fs *pflag.FlagSet)
 | 
				
			||||||
	Set(value string) error
 | 
						Set(value string) error
 | 
				
			||||||
	Add(features map[Feature]FeatureSpec)
 | 
						Enabled(key Feature) bool
 | 
				
			||||||
 | 
						Add(features map[Feature]FeatureSpec) error
 | 
				
			||||||
	KnownFeatures() []string
 | 
						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.
 | 
					// 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
 | 
					// Set, String, and Type implement pflag.Value
 | 
				
			||||||
var _ pflag.Value = &featureGate{}
 | 
					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
 | 
					// Set Parses a string of the form // "key1=value1,key2=value2,..." into a
 | 
				
			||||||
// map[string]bool of known keys or returns an error.
 | 
					// map[string]bool of known keys or returns an error.
 | 
				
			||||||
func (f *featureGate) Set(value string) error {
 | 
					func (f *featureGate) Set(value string) error {
 | 
				
			||||||
	f.enabled = make(map[Feature]bool)
 | 
					 | 
				
			||||||
	for _, s := range strings.Split(value, ",") {
 | 
						for _, s := range strings.Split(value, ",") {
 | 
				
			||||||
		if len(s) == 0 {
 | 
							if len(s) == 0 {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -119,9 +119,11 @@ func TestFeatureGateFlag(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	for i, test := range tests {
 | 
						for i, test := range tests {
 | 
				
			||||||
		fs := pflag.NewFlagSet("testfeaturegateflag", pflag.ContinueOnError)
 | 
							fs := pflag.NewFlagSet("testfeaturegateflag", pflag.ContinueOnError)
 | 
				
			||||||
		f := DefaultFeatureGate
 | 
							f := NewFeatureGate()
 | 
				
			||||||
		f.known[testAlphaGate] = FeatureSpec{Default: false, PreRelease: Alpha}
 | 
							f.Add(map[Feature]FeatureSpec{
 | 
				
			||||||
		f.known[testBetaGate] = FeatureSpec{Default: false, PreRelease: Beta}
 | 
								testAlphaGate: {Default: false, PreRelease: Alpha},
 | 
				
			||||||
 | 
								testBetaGate:  {Default: false, PreRelease: Beta},
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
		f.AddFlag(fs)
 | 
							f.AddFlag(fs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err := fs.Parse([]string{fmt.Sprintf("--%s=%s", flagName, test.arg)})
 | 
							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) {
 | 
					func TestFeatureGateFlagDefaults(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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Don't parse the flag, assert defaults are used.
 | 
						// Don't parse the flag, assert defaults are used.
 | 
				
			||||||
	f := DefaultFeatureGate
 | 
						var f FeatureGate = NewFeatureGate()
 | 
				
			||||||
	f.known[testAlphaGate] = FeatureSpec{Default: false, PreRelease: Alpha}
 | 
						f.Add(map[Feature]FeatureSpec{
 | 
				
			||||||
	f.known[testBetaGate] = FeatureSpec{Default: true, PreRelease: Beta}
 | 
							testAlphaGate: {Default: false, PreRelease: Alpha},
 | 
				
			||||||
 | 
							testBetaGate:  {Default: true, PreRelease: Beta},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if f.Enabled(testAlphaGate) != false {
 | 
						if f.Enabled(testAlphaGate) != false {
 | 
				
			||||||
		t.Errorf("Expected false")
 | 
							t.Errorf("Expected false")
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user