Skip to content

Commit f1e912c

Browse files
authored
Merge pull request kubernetes#84304 from liggitt/all-beta
Add support for --runtime-config=api/beta=false, --feature-gates=AllBeta=false
2 parents b9fa6e0 + a5760de commit f1e912c

File tree

7 files changed

+205
-36
lines changed

7 files changed

+205
-36
lines changed

cmd/kube-apiserver/app/options/options.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) {
142142
s.Authentication.AddFlags(fss.FlagSet("authentication"))
143143
s.Authorization.AddFlags(fss.FlagSet("authorization"))
144144
s.CloudProvider.AddFlags(fss.FlagSet("cloud provider"))
145-
s.APIEnablement.AddFlags(fss.FlagSet("api enablement"))
145+
s.APIEnablement.AddFlags(fss.FlagSet("API enablement"))
146146
s.EgressSelector.AddFlags(fss.FlagSet("egress selector"))
147147
s.Admission.AddFlags(fss.FlagSet("admission"))
148148

staging/src/k8s.io/apiserver/pkg/server/options/api_enablement.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,14 @@ func NewAPIEnablementOptions() *APIEnablementOptions {
4343
// AddFlags adds flags for a specific APIServer to the specified FlagSet
4444
func (s *APIEnablementOptions) AddFlags(fs *pflag.FlagSet) {
4545
fs.Var(&s.RuntimeConfig, "runtime-config", ""+
46-
"A set of key=value pairs that describe runtime configuration that may be passed "+
47-
"to apiserver. <group>/<version> (or <version> for the core group) key can be used to "+
48-
"turn on/off specific api versions. api/all is special key to control all api versions, "+
49-
"be careful setting it false, unless you know what you do. api/legacy is deprecated, "+
50-
"we will remove it in the future, so stop using it.")
46+
"A set of key=value pairs that enable or disable built-in APIs. Supported options are:\n"+
47+
"v1=true|false for the core API group\n"+
48+
"<group>/<version>=true|false for a specific API group and version (e.g. apps/v1=true)\n"+
49+
"api/all=true|false controls all API versions\n"+
50+
"api/ga=true|false controls all API versions of the form v[0-9]+\n"+
51+
"api/beta=true|false controls all API versions of the form v[0-9]+beta[0-9]+\n"+
52+
"api/alpha=true|false controls all API versions of the form v[0-9]+alpha[0-9]+\n"+
53+
"api/legacy is deprecated, and will be removed in a future version")
5154
}
5255

5356
// Validate validates RuntimeConfig with a list of registries.
@@ -61,9 +64,9 @@ func (s *APIEnablementOptions) Validate(registries ...GroupRegisty) []error {
6164
}
6265

6366
errors := []error{}
64-
if s.RuntimeConfig["api/all"] == "false" && len(s.RuntimeConfig) == 1 {
67+
if s.RuntimeConfig[resourceconfig.APIAll] == "false" && len(s.RuntimeConfig) == 1 {
6568
// Do not allow only set api/all=false, in such case apiserver startup has no meaning.
66-
return append(errors, fmt.Errorf("invalid key with only api/all=false"))
69+
return append(errors, fmt.Errorf("invalid key with only %v=false", resourceconfig.APIAll))
6770
}
6871

6972
groups, err := resourceconfig.ParseGroups(s.RuntimeConfig)

staging/src/k8s.io/apiserver/pkg/server/resourceconfig/helpers.go

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package resourceconfig
1818

1919
import (
2020
"fmt"
21+
"regexp"
2122
"strconv"
2223
"strings"
2324

@@ -51,6 +52,33 @@ func MergeResourceEncodingConfigs(
5152
return resourceEncodingConfig
5253
}
5354

55+
// Recognized values for the --runtime-config parameter to enable/disable groups of APIs
56+
const (
57+
APIAll = "api/all"
58+
APIGA = "api/ga"
59+
APIBeta = "api/beta"
60+
APIAlpha = "api/alpha"
61+
)
62+
63+
var (
64+
gaPattern = regexp.MustCompile(`^v\d+$`)
65+
betaPattern = regexp.MustCompile(`^v\d+beta\d+$`)
66+
alphaPattern = regexp.MustCompile(`^v\d+alpha\d+$`)
67+
68+
matchers = map[string]func(gv schema.GroupVersion) bool{
69+
// allows users to address all api versions
70+
APIAll: func(gv schema.GroupVersion) bool { return true },
71+
// allows users to address all api versions in the form v[0-9]+
72+
APIGA: func(gv schema.GroupVersion) bool { return gaPattern.MatchString(gv.Version) },
73+
// allows users to address all beta api versions
74+
APIBeta: func(gv schema.GroupVersion) bool { return betaPattern.MatchString(gv.Version) },
75+
// allows users to address all alpha api versions
76+
APIAlpha: func(gv schema.GroupVersion) bool { return alphaPattern.MatchString(gv.Version) },
77+
}
78+
79+
matcherOrder = []string{APIAll, APIGA, APIBeta, APIAlpha}
80+
)
81+
5482
// MergeAPIResourceConfigs merges the given defaultAPIResourceConfig with the given resourceConfigOverrides.
5583
// Exclude the groups not registered in registry, and check if version is
5684
// not registered in group, then it will fail.
@@ -62,14 +90,15 @@ func MergeAPIResourceConfigs(
6290
resourceConfig := defaultAPIResourceConfig
6391
overrides := resourceConfigOverrides
6492

65-
// "api/all=false" allows users to selectively enable specific api versions.
66-
allAPIFlagValue, ok := overrides["api/all"]
67-
if ok {
68-
if allAPIFlagValue == "false" {
69-
// Disable all group versions.
70-
resourceConfig.DisableAll()
71-
} else if allAPIFlagValue == "true" {
72-
resourceConfig.EnableAll()
93+
for _, flag := range matcherOrder {
94+
if value, ok := overrides[flag]; ok {
95+
if value == "false" {
96+
resourceConfig.DisableMatchingVersions(matchers[flag])
97+
} else if value == "true" {
98+
resourceConfig.EnableMatchingVersions(matchers[flag])
99+
} else {
100+
return nil, fmt.Errorf("invalid value %v=%v", flag, value)
101+
}
73102
}
74103
}
75104

@@ -78,7 +107,7 @@ func MergeAPIResourceConfigs(
78107
// Iterate through all group/version overrides specified in runtimeConfig.
79108
for key := range overrides {
80109
// Have already handled them above. Can skip them here.
81-
if key == "api/all" {
110+
if _, ok := matchers[key]; ok {
82111
continue
83112
}
84113

@@ -153,7 +182,7 @@ func getRuntimeConfigValue(overrides cliflag.ConfigurationMap, apiKey string, de
153182
func ParseGroups(resourceConfig cliflag.ConfigurationMap) ([]string, error) {
154183
groups := []string{}
155184
for key := range resourceConfig {
156-
if key == "api/all" {
185+
if _, ok := matchers[key]; ok {
157186
continue
158187
}
159188
tokens := strings.Split(key, "/")

staging/src/k8s.io/apiserver/pkg/server/resourceconfig/helpers_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,21 @@ func TestParseRuntimeConfig(t *testing.T) {
195195
},
196196
err: false, // no error for backwards compatibility
197197
},
198+
{
199+
// disable all beta resources
200+
runtimeConfig: map[string]string{
201+
"api/beta": "false",
202+
},
203+
defaultResourceConfig: func() *serverstore.ResourceConfig {
204+
return newFakeAPIResourceConfigSource()
205+
},
206+
expectedAPIConfig: func() *serverstore.ResourceConfig {
207+
config := newFakeAPIResourceConfigSource()
208+
config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion)
209+
return config
210+
},
211+
err: false, // no error for backwards compatibility
212+
},
198213
}
199214
for index, test := range testCases {
200215
t.Log(scheme.PrioritizedVersionsAllGroups())

staging/src/k8s.io/apiserver/pkg/server/storage/resource_config.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,24 @@ func (o *ResourceConfig) EnableAll() {
5252
}
5353
}
5454

55+
// DisableMatchingVersions disables all group/versions for which the matcher function returns true. It does not modify individual resource enablement/disablement.
56+
func (o *ResourceConfig) DisableMatchingVersions(matcher func(gv schema.GroupVersion) bool) {
57+
for k := range o.GroupVersionConfigs {
58+
if matcher(k) {
59+
o.GroupVersionConfigs[k] = false
60+
}
61+
}
62+
}
63+
64+
// EnableMatchingVersions enables all group/versions for which the matcher function returns true. It does not modify individual resource enablement/disablement.
65+
func (o *ResourceConfig) EnableMatchingVersions(matcher func(gv schema.GroupVersion) bool) {
66+
for k := range o.GroupVersionConfigs {
67+
if matcher(k) {
68+
o.GroupVersionConfigs[k] = true
69+
}
70+
}
71+
}
72+
5573
// DisableVersions disables the versions entirely.
5674
func (o *ResourceConfig) DisableVersions(versions ...schema.GroupVersion) {
5775
for _, version := range versions {

staging/src/k8s.io/component-base/featuregate/feature_gate.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,25 @@ const (
4040
// AllAlpha=false,NewFeature=true will result in newFeature=true
4141
// AllAlpha=true,NewFeature=false will result in newFeature=false
4242
allAlphaGate Feature = "AllAlpha"
43+
44+
// allBetaGate is a global toggle for beta features. Per-feature key
45+
// values override the default set by allBetaGate. Examples:
46+
// AllBeta=false,NewFeature=true will result in NewFeature=true
47+
// AllBeta=true,NewFeature=false will result in NewFeature=false
48+
allBetaGate Feature = "AllBeta"
4349
)
4450

4551
var (
4652
// The generic features.
4753
defaultFeatures = map[Feature]FeatureSpec{
4854
allAlphaGate: {Default: false, PreRelease: Alpha},
55+
allBetaGate: {Default: false, PreRelease: Beta},
4956
}
5057

5158
// Special handling for a few gates.
5259
specialFeatures = map[Feature]func(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool){
5360
allAlphaGate: setUnsetAlphaGates,
61+
allBetaGate: setUnsetBetaGates,
5462
}
5563
)
5664

@@ -129,6 +137,16 @@ func setUnsetAlphaGates(known map[Feature]FeatureSpec, enabled map[Feature]bool,
129137
}
130138
}
131139

140+
func setUnsetBetaGates(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool) {
141+
for k, v := range known {
142+
if v.PreRelease == Beta {
143+
if _, found := enabled[k]; !found {
144+
enabled[k] = val
145+
}
146+
}
147+
}
148+
}
149+
132150
// Set, String, and Type implement pflag.Value
133151
var _ pflag.Value = &featureGate{}
134152

0 commit comments

Comments
 (0)