func TestGroupVersions(t *testing.T) { // legacyUnsuffixedGroups contains the groups released prior to deciding that kubernetes API groups should be dns-suffixed // new groups should be suffixed with ".k8s.io" (https://github.com/kubernetes/kubernetes/pull/31887#issuecomment-244462396) legacyUnsuffixedGroups := sets.NewString( "", "apps", "autoscaling", "batch", "componentconfig", "extensions", "federation", "policy", ) // No new groups should be added to the legacyUnsuffixedGroups exclusion list if len(legacyUnsuffixedGroups) != 8 { t.Errorf("No additional unnamespaced groups should be created") } for _, gv := range registered.RegisteredGroupVersions() { if !strings.HasSuffix(gv.Group, ".k8s.io") && !legacyUnsuffixedGroups.Has(gv.Group) { t.Errorf("Group %s does not have the standard kubernetes API group suffix of .k8s.io", gv.Group) } } }
func TestDescriptions(t *testing.T) { for _, version := range registered.RegisteredGroupVersions() { seen := map[reflect.Type]bool{} for _, apiType := range kapi.Scheme.KnownTypes(version) { checkDescriptions(apiType, &seen, t) } } }
func TestExternalJsonTags(t *testing.T) { seen := map[reflect.Type]bool{} for _, version := range registered.RegisteredGroupVersions() { for _, apiType := range kapi.Scheme.KnownTypes(version) { checkExternalJsonTags(apiType, &seen, t) } } for _, apiType := range configapi.Scheme.KnownTypes(configapiv1.SchemeGroupVersion) { checkExternalJsonTags(apiType, &seen, t) } }
func TestInternalJsonTags(t *testing.T) { seen := map[reflect.Type]bool{} seenGroups := sets.String{} for _, version := range registered.RegisteredGroupVersions() { if seenGroups.Has(version.Group) { continue } seenGroups.Insert(version.Group) internalVersion := unversioned.GroupVersion{Group: version.Group, Version: runtime.APIVersionInternal} for _, apiType := range kapi.Scheme.KnownTypes(internalVersion) { checkInternalJsonTags(apiType, &seen, t) } } for _, apiType := range configapi.Scheme.KnownTypes(configapi.SchemeGroupVersion) { checkInternalJsonTags(apiType, &seen, t) } }
func TestParseRuntimeConfig(t *testing.T) { extensionsGroupVersion := extensionsapiv1beta1.SchemeGroupVersion apiv1GroupVersion := apiv1.SchemeGroupVersion testCases := []struct { runtimeConfig map[string]string defaultResourceConfig func() *ResourceConfig expectedAPIConfig func() *ResourceConfig err bool }{ { // everything default value. runtimeConfig: map[string]string{}, defaultResourceConfig: func() *ResourceConfig { return NewResourceConfig() }, expectedAPIConfig: func() *ResourceConfig { return NewResourceConfig() }, err: false, }, { // no runtimeConfig override. runtimeConfig: map[string]string{}, defaultResourceConfig: func() *ResourceConfig { config := NewResourceConfig() config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion) return config }, expectedAPIConfig: func() *ResourceConfig { config := NewResourceConfig() config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion) return config }, err: false, }, { // version enabled by runtimeConfig override. runtimeConfig: map[string]string{ "extensions/v1beta1": "", }, defaultResourceConfig: func() *ResourceConfig { config := NewResourceConfig() config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion) return config }, expectedAPIConfig: func() *ResourceConfig { config := NewResourceConfig() config.EnableVersions(extensionsapiv1beta1.SchemeGroupVersion) return config }, err: false, }, { // disable resource runtimeConfig: map[string]string{ "api/v1/pods": "false", }, defaultResourceConfig: func() *ResourceConfig { config := NewResourceConfig() config.EnableVersions(apiv1GroupVersion) return config }, expectedAPIConfig: func() *ResourceConfig { config := NewResourceConfig() config.EnableVersions(apiv1GroupVersion) config.DisableResources(apiv1GroupVersion.WithResource("pods")) return config }, err: false, }, { // Disable v1. runtimeConfig: map[string]string{ "api/v1": "false", }, defaultResourceConfig: func() *ResourceConfig { return NewResourceConfig() }, expectedAPIConfig: func() *ResourceConfig { config := NewResourceConfig() config.DisableVersions(apiv1GroupVersion) return config }, err: false, }, { // Enable deployments and disable jobs. runtimeConfig: map[string]string{ "extensions/v1beta1/anything": "true", "extensions/v1beta1/jobs": "false", }, defaultResourceConfig: func() *ResourceConfig { config := NewResourceConfig() config.EnableVersions(extensionsGroupVersion) return config }, expectedAPIConfig: func() *ResourceConfig { config := NewResourceConfig() config.EnableVersions(extensionsGroupVersion) config.DisableResources(extensionsGroupVersion.WithResource("jobs")) config.EnableResources(extensionsGroupVersion.WithResource("anything")) return config }, err: false, }, { // invalid runtime config runtimeConfig: map[string]string{ "invalidgroup/version": "false", }, defaultResourceConfig: func() *ResourceConfig { return NewResourceConfig() }, expectedAPIConfig: func() *ResourceConfig { return NewResourceConfig() }, err: true, }, { // cannot disable individual resource when version is not enabled. runtimeConfig: map[string]string{ "api/v1/pods": "false", }, defaultResourceConfig: func() *ResourceConfig { return NewResourceConfig() }, expectedAPIConfig: func() *ResourceConfig { config := NewResourceConfig() config.DisableResources(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}) return config }, err: true, }, { // enable all runtimeConfig: map[string]string{ "api/all": "true", }, defaultResourceConfig: func() *ResourceConfig { return NewResourceConfig() }, expectedAPIConfig: func() *ResourceConfig { config := NewResourceConfig() config.EnableVersions(registered.RegisteredGroupVersions()...) return config }, err: false, }, { // disable all runtimeConfig: map[string]string{ "api/all": "false", }, defaultResourceConfig: func() *ResourceConfig { return NewResourceConfig() }, expectedAPIConfig: func() *ResourceConfig { config := NewResourceConfig() config.DisableVersions(registered.RegisteredGroupVersions()...) return config }, err: false, }, } for _, test := range testCases { actualDisablers, err := mergeAPIResourceConfigs(test.defaultResourceConfig(), test.runtimeConfig) if err == nil && test.err { t.Fatalf("expected error for test: %v", test) } else if err != nil && !test.err { t.Fatalf("unexpected error: %s, for test: %v", err, test) } expectedConfig := test.expectedAPIConfig() if err == nil && !reflect.DeepEqual(actualDisablers, expectedConfig) { t.Fatalf("%v: unexpected apiResourceDisablers. Actual: %v\n expected: %v", test.runtimeConfig, actualDisablers, expectedConfig) } } }
// Merges the given defaultAPIResourceConfig with the given resourceConfigOverrides. func mergeAPIResourceConfigs(defaultAPIResourceConfig *ResourceConfig, resourceConfigOverrides config.ConfigurationMap) (*ResourceConfig, error) { resourceConfig := defaultAPIResourceConfig overrides := resourceConfigOverrides // "api/all=false" allows users to selectively enable specific api versions. allAPIFlagValue, ok := overrides["api/all"] if ok && allAPIFlagValue == "false" { // Disable all group versions. for _, groupVersion := range registered.RegisteredGroupVersions() { if resourceConfig.AnyResourcesForVersionEnabled(groupVersion) { resourceConfig.DisableVersions(groupVersion) } } } // "api/legacy=false" allows users to disable legacy api versions. disableLegacyAPIs := false legacyAPIFlagValue, ok := overrides["api/legacy"] if ok && legacyAPIFlagValue == "false" { disableLegacyAPIs = true } _ = disableLegacyAPIs // hush the compiler while we don't have legacy APIs to disable. // "<resourceSpecifier>={true|false} allows users to enable/disable API. // This takes preference over api/all and api/legacy, if specified. // Iterate through all group/version overrides specified in runtimeConfig. for key := range overrides { if key == "api/all" || key == "api/legacy" { // Have already handled them above. Can skip them here. continue } tokens := strings.Split(key, "/") if len(tokens) != 2 { continue } groupVersionString := tokens[0] + "/" + tokens[1] // HACK: Hack for "v1" legacy group version. // Remove when we stop supporting the legacy group version. if groupVersionString == "api/v1" { groupVersionString = "v1" } groupVersion, err := unversioned.ParseGroupVersion(groupVersionString) if err != nil { return nil, fmt.Errorf("invalid key %s", key) } // Verify that the groupVersion is registered. if !registered.IsRegisteredVersion(groupVersion) { return nil, fmt.Errorf("group version %s that has not been registered", groupVersion.String()) } enabled, err := getRuntimeConfigValue(overrides, key, false) if err != nil { return nil, err } if enabled { resourceConfig.EnableVersions(groupVersion) } else { resourceConfig.DisableVersions(groupVersion) } } // Iterate through all group/version/resource overrides specified in runtimeConfig. for key := range overrides { tokens := strings.Split(key, "/") if len(tokens) != 3 { continue } groupVersionString := tokens[0] + "/" + tokens[1] // HACK: Hack for "v1" legacy group version. // Remove when we stop supporting the legacy group version. if groupVersionString == "api/v1" { groupVersionString = "v1" } groupVersion, err := unversioned.ParseGroupVersion(groupVersionString) if err != nil { return nil, fmt.Errorf("invalid key %s", key) } resource := tokens[2] // Verify that the groupVersion is registered. if !registered.IsRegisteredVersion(groupVersion) { return nil, fmt.Errorf("group version %s that has not been registered", groupVersion.String()) } if !resourceConfig.AnyResourcesForVersionEnabled(groupVersion) { return nil, fmt.Errorf("%v is disabled, you cannot configure its resources individually", groupVersion) } enabled, err := getRuntimeConfigValue(overrides, key, false) if err != nil { return nil, err } if enabled { resourceConfig.EnableResources(groupVersion.WithResource(resource)) } else { resourceConfig.DisableResources(groupVersion.WithResource(resource)) } } return resourceConfig, nil }