blob: cb1c54e3f0b468ae6ef5639cf18cc9e673d981c1 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Copyright 2017 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package resourceconfig
18
19import (
20 "fmt"
21 "strconv"
22 "strings"
23
24 "k8s.io/apimachinery/pkg/runtime"
25 "k8s.io/apimachinery/pkg/runtime/schema"
26 serverstore "k8s.io/apiserver/pkg/server/storage"
27 utilflag "k8s.io/apiserver/pkg/util/flag"
28)
29
30// GroupVersionRegistry provides access to registered group versions.
31type GroupVersionRegistry interface {
32 // IsGroupRegistered returns true if given group is registered.
33 IsGroupRegistered(group string) bool
34 // IsVersionRegistered returns true if given version is registered.
35 IsVersionRegistered(v schema.GroupVersion) bool
36 // PrioritizedVersionsAllGroups returns all registered group versions.
37 PrioritizedVersionsAllGroups() []schema.GroupVersion
38}
39
40// MergeResourceEncodingConfigs merges the given defaultResourceConfig with specific GroupVersionResource overrides.
41func MergeResourceEncodingConfigs(
42 defaultResourceEncoding *serverstore.DefaultResourceEncodingConfig,
43 resourceEncodingOverrides []schema.GroupVersionResource,
44) *serverstore.DefaultResourceEncodingConfig {
45 resourceEncodingConfig := defaultResourceEncoding
46 for _, gvr := range resourceEncodingOverrides {
47 resourceEncodingConfig.SetResourceEncoding(gvr.GroupResource(), gvr.GroupVersion(),
48 schema.GroupVersion{Group: gvr.Group, Version: runtime.APIVersionInternal})
49 }
50 return resourceEncodingConfig
51}
52
53// MergeGroupEncodingConfigs merges the given defaultResourceConfig with specific GroupVersion overrides.
54func MergeGroupEncodingConfigs(
55 defaultResourceEncoding *serverstore.DefaultResourceEncodingConfig,
56 storageEncodingOverrides map[string]schema.GroupVersion,
57) *serverstore.DefaultResourceEncodingConfig {
58 resourceEncodingConfig := defaultResourceEncoding
59 for group, storageEncodingVersion := range storageEncodingOverrides {
60 resourceEncodingConfig.SetVersionEncoding(group, storageEncodingVersion, schema.GroupVersion{Group: group, Version: runtime.APIVersionInternal})
61 }
62 return resourceEncodingConfig
63}
64
65// MergeAPIResourceConfigs merges the given defaultAPIResourceConfig with the given resourceConfigOverrides.
66// Exclude the groups not registered in registry, and check if version is
67// not registered in group, then it will fail.
68func MergeAPIResourceConfigs(
69 defaultAPIResourceConfig *serverstore.ResourceConfig,
70 resourceConfigOverrides utilflag.ConfigurationMap,
71 registry GroupVersionRegistry,
72) (*serverstore.ResourceConfig, error) {
73 resourceConfig := defaultAPIResourceConfig
74 overrides := resourceConfigOverrides
75
76 // "api/all=false" allows users to selectively enable specific api versions.
77 allAPIFlagValue, ok := overrides["api/all"]
78 if ok {
79 if allAPIFlagValue == "false" {
80 // Disable all group versions.
81 resourceConfig.DisableAll()
82 } else if allAPIFlagValue == "true" {
83 resourceConfig.EnableAll()
84 }
85 }
86
87 // "<resourceSpecifier>={true|false} allows users to enable/disable API.
88 // This takes preference over api/all, if specified.
89 // Iterate through all group/version overrides specified in runtimeConfig.
90 for key := range overrides {
91 // Have already handled them above. Can skip them here.
92 if key == "api/all" {
93 continue
94 }
95
96 tokens := strings.Split(key, "/")
97 if len(tokens) != 2 {
98 continue
99 }
100 groupVersionString := tokens[0] + "/" + tokens[1]
101 groupVersion, err := schema.ParseGroupVersion(groupVersionString)
102 if err != nil {
103 return nil, fmt.Errorf("invalid key %s", key)
104 }
105
106 // Exclude group not registered into the registry.
107 if !registry.IsGroupRegistered(groupVersion.Group) {
108 continue
109 }
110
111 // Verify that the groupVersion is registered into registry.
112 if !registry.IsVersionRegistered(groupVersion) {
113 return nil, fmt.Errorf("group version %s that has not been registered", groupVersion.String())
114 }
115 enabled, err := getRuntimeConfigValue(overrides, key, false)
116 if err != nil {
117 return nil, err
118 }
119 if enabled {
120 resourceConfig.EnableVersions(groupVersion)
121 } else {
122 resourceConfig.DisableVersions(groupVersion)
123 }
124 }
125
126 return resourceConfig, nil
127}
128
129func getRuntimeConfigValue(overrides utilflag.ConfigurationMap, apiKey string, defaultValue bool) (bool, error) {
130 flagValue, ok := overrides[apiKey]
131 if ok {
132 if flagValue == "" {
133 return true, nil
134 }
135 boolValue, err := strconv.ParseBool(flagValue)
136 if err != nil {
137 return false, fmt.Errorf("invalid value of %s: %s, err: %v", apiKey, flagValue, err)
138 }
139 return boolValue, nil
140 }
141 return defaultValue, nil
142}
143
144// ParseGroups takes in resourceConfig and returns parsed groups.
145func ParseGroups(resourceConfig utilflag.ConfigurationMap) ([]string, error) {
146 groups := []string{}
147 for key := range resourceConfig {
148 if key == "api/all" {
149 continue
150 }
151 tokens := strings.Split(key, "/")
152 if len(tokens) != 2 && len(tokens) != 3 {
153 return groups, fmt.Errorf("runtime-config invalid key %s", key)
154 }
155 groupVersionString := tokens[0] + "/" + tokens[1]
156 groupVersion, err := schema.ParseGroupVersion(groupVersionString)
157 if err != nil {
158 return nil, fmt.Errorf("runtime-config invalid key %s", key)
159 }
160 groups = append(groups, groupVersion.Group)
161 }
162
163 return groups, nil
164}