diff --git a/pkg/server/options/api_enablement.go b/pkg/server/options/api_enablement.go index 65f143bf0..794e89ded 100644 --- a/pkg/server/options/api_enablement.go +++ b/pkg/server/options/api_enablement.go @@ -43,11 +43,14 @@ func NewAPIEnablementOptions() *APIEnablementOptions { // AddFlags adds flags for a specific APIServer to the specified FlagSet func (s *APIEnablementOptions) AddFlags(fs *pflag.FlagSet) { fs.Var(&s.RuntimeConfig, "runtime-config", ""+ - "A set of key=value pairs that describe runtime configuration that may be passed "+ - "to apiserver. / (or for the core group) key can be used to "+ - "turn on/off specific api versions. api/all is special key to control all api versions, "+ - "be careful setting it false, unless you know what you do. api/legacy is deprecated, "+ - "we will remove it in the future, so stop using it.") + "A set of key=value pairs that enable or disable built-in APIs. Supported options are:\n"+ + "v1=true|false for the core API group\n"+ + "/=true|false for a specific API group and version (e.g. apps/v1=true)\n"+ + "api/all=true|false controls all API versions\n"+ + "api/ga=true|false controls all API versions of the form v[0-9]+\n"+ + "api/beta=true|false controls all API versions of the form v[0-9]+beta[0-9]+\n"+ + "api/alpha=true|false controls all API versions of the form v[0-9]+alpha[0-9]+\n"+ + "api/legacy is deprecated, and will be removed in a future version") } // Validate validates RuntimeConfig with a list of registries. @@ -61,9 +64,9 @@ func (s *APIEnablementOptions) Validate(registries ...GroupRegisty) []error { } errors := []error{} - if s.RuntimeConfig["api/all"] == "false" && len(s.RuntimeConfig) == 1 { + if s.RuntimeConfig[resourceconfig.APIAll] == "false" && len(s.RuntimeConfig) == 1 { // Do not allow only set api/all=false, in such case apiserver startup has no meaning. - return append(errors, fmt.Errorf("invalid key with only api/all=false")) + return append(errors, fmt.Errorf("invalid key with only %v=false", resourceconfig.APIAll)) } groups, err := resourceconfig.ParseGroups(s.RuntimeConfig) diff --git a/pkg/server/resourceconfig/helpers.go b/pkg/server/resourceconfig/helpers.go index 09047cfe9..85e5e1c46 100644 --- a/pkg/server/resourceconfig/helpers.go +++ b/pkg/server/resourceconfig/helpers.go @@ -18,6 +18,7 @@ package resourceconfig import ( "fmt" + "regexp" "strconv" "strings" @@ -51,6 +52,33 @@ func MergeResourceEncodingConfigs( return resourceEncodingConfig } +// Recognized values for the --runtime-config parameter to enable/disable groups of APIs +const ( + APIAll = "api/all" + APIGA = "api/ga" + APIBeta = "api/beta" + APIAlpha = "api/alpha" +) + +var ( + gaPattern = regexp.MustCompile(`^v\d+$`) + betaPattern = regexp.MustCompile(`^v\d+beta\d+$`) + alphaPattern = regexp.MustCompile(`^v\d+alpha\d+$`) + + matchers = map[string]func(gv schema.GroupVersion) bool{ + // allows users to address all api versions + APIAll: func(gv schema.GroupVersion) bool { return true }, + // allows users to address all api versions in the form v[0-9]+ + APIGA: func(gv schema.GroupVersion) bool { return gaPattern.MatchString(gv.Version) }, + // allows users to address all beta api versions + APIBeta: func(gv schema.GroupVersion) bool { return betaPattern.MatchString(gv.Version) }, + // allows users to address all alpha api versions + APIAlpha: func(gv schema.GroupVersion) bool { return alphaPattern.MatchString(gv.Version) }, + } + + matcherOrder = []string{APIAll, APIGA, APIBeta, APIAlpha} +) + // MergeAPIResourceConfigs merges the given defaultAPIResourceConfig with the given resourceConfigOverrides. // Exclude the groups not registered in registry, and check if version is // not registered in group, then it will fail. @@ -62,14 +90,15 @@ func MergeAPIResourceConfigs( resourceConfig := defaultAPIResourceConfig overrides := resourceConfigOverrides - // "api/all=false" allows users to selectively enable specific api versions. - allAPIFlagValue, ok := overrides["api/all"] - if ok { - if allAPIFlagValue == "false" { - // Disable all group versions. - resourceConfig.DisableAll() - } else if allAPIFlagValue == "true" { - resourceConfig.EnableAll() + for _, flag := range matcherOrder { + if value, ok := overrides[flag]; ok { + if value == "false" { + resourceConfig.DisableMatchingVersions(matchers[flag]) + } else if value == "true" { + resourceConfig.EnableMatchingVersions(matchers[flag]) + } else { + return nil, fmt.Errorf("invalid value %v=%v", flag, value) + } } } @@ -78,7 +107,7 @@ func MergeAPIResourceConfigs( // Iterate through all group/version overrides specified in runtimeConfig. for key := range overrides { // Have already handled them above. Can skip them here. - if key == "api/all" { + if _, ok := matchers[key]; ok { continue } @@ -153,7 +182,7 @@ func getRuntimeConfigValue(overrides cliflag.ConfigurationMap, apiKey string, de func ParseGroups(resourceConfig cliflag.ConfigurationMap) ([]string, error) { groups := []string{} for key := range resourceConfig { - if key == "api/all" { + if _, ok := matchers[key]; ok { continue } tokens := strings.Split(key, "/") diff --git a/pkg/server/resourceconfig/helpers_test.go b/pkg/server/resourceconfig/helpers_test.go index 9f905941b..f78550d52 100644 --- a/pkg/server/resourceconfig/helpers_test.go +++ b/pkg/server/resourceconfig/helpers_test.go @@ -195,6 +195,21 @@ func TestParseRuntimeConfig(t *testing.T) { }, err: false, // no error for backwards compatibility }, + { + // disable all beta resources + runtimeConfig: map[string]string{ + "api/beta": "false", + }, + defaultResourceConfig: func() *serverstore.ResourceConfig { + return newFakeAPIResourceConfigSource() + }, + expectedAPIConfig: func() *serverstore.ResourceConfig { + config := newFakeAPIResourceConfigSource() + config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion) + return config + }, + err: false, // no error for backwards compatibility + }, } for index, test := range testCases { t.Log(scheme.PrioritizedVersionsAllGroups()) diff --git a/pkg/server/storage/resource_config.go b/pkg/server/storage/resource_config.go index eb892b5a5..0f2d45c9e 100644 --- a/pkg/server/storage/resource_config.go +++ b/pkg/server/storage/resource_config.go @@ -52,6 +52,24 @@ func (o *ResourceConfig) EnableAll() { } } +// DisableMatchingVersions disables all group/versions for which the matcher function returns true. It does not modify individual resource enablement/disablement. +func (o *ResourceConfig) DisableMatchingVersions(matcher func(gv schema.GroupVersion) bool) { + for k := range o.GroupVersionConfigs { + if matcher(k) { + o.GroupVersionConfigs[k] = false + } + } +} + +// EnableMatchingVersions enables all group/versions for which the matcher function returns true. It does not modify individual resource enablement/disablement. +func (o *ResourceConfig) EnableMatchingVersions(matcher func(gv schema.GroupVersion) bool) { + for k := range o.GroupVersionConfigs { + if matcher(k) { + o.GroupVersionConfigs[k] = true + } + } +} + // DisableVersions disables the versions entirely. func (o *ResourceConfig) DisableVersions(versions ...schema.GroupVersion) { for _, version := range versions {