mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 14:07:14 +00:00
Merge pull request #24787 from nikhiljindal/storageVersion
Automatic merge from submit-queue Moving StorageFactory building logic to genericapiserver Adding a DefaultStorageFactoryBuilder which builds the required StorageFactory. This allows us to remove the duplicated code between `cmd/kube-apiserver` and `federation/cmd/federated-apiserver` cc @deads2k @lavalamp @jianhuiz
This commit is contained in:
commit
bbdbfc8940
@ -23,10 +23,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
|
||||||
apiutil "k8s.io/kubernetes/pkg/api/util"
|
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
||||||
@ -46,7 +43,6 @@ type APIServer struct {
|
|||||||
BasicAuthFile string
|
BasicAuthFile string
|
||||||
DefaultStorageMediaType string
|
DefaultStorageMediaType string
|
||||||
DeleteCollectionWorkers int
|
DeleteCollectionWorkers int
|
||||||
DeprecatedStorageVersion string
|
|
||||||
EtcdServersOverrides []string
|
EtcdServersOverrides []string
|
||||||
EventTTL time.Duration
|
EventTTL time.Duration
|
||||||
KeystoneURL string
|
KeystoneURL string
|
||||||
@ -62,13 +58,8 @@ type APIServer struct {
|
|||||||
SSHUser string
|
SSHUser string
|
||||||
ServiceAccountKeyFile string
|
ServiceAccountKeyFile string
|
||||||
ServiceAccountLookup bool
|
ServiceAccountLookup bool
|
||||||
StorageVersions string
|
TokenAuthFile string
|
||||||
// The default values for StorageVersions. StorageVersions overrides
|
WatchCacheSizes []string
|
||||||
// these; you can change this if you want to change the defaults (e.g.,
|
|
||||||
// for testing). This is not actually exposed as a flag.
|
|
||||||
DefaultStorageVersions string
|
|
||||||
TokenAuthFile string
|
|
||||||
WatchCacheSizes []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAPIServer creates a new APIServer object with default parameters
|
// NewAPIServer creates a new APIServer object with default parameters
|
||||||
@ -81,8 +72,6 @@ func NewAPIServer() *APIServer {
|
|||||||
DeleteCollectionWorkers: 1,
|
DeleteCollectionWorkers: 1,
|
||||||
EventTTL: 1 * time.Hour,
|
EventTTL: 1 * time.Hour,
|
||||||
MasterServiceNamespace: api.NamespaceDefault,
|
MasterServiceNamespace: api.NamespaceDefault,
|
||||||
StorageVersions: registered.AllPreferredGroupVersions(),
|
|
||||||
DefaultStorageVersions: registered.AllPreferredGroupVersions(),
|
|
||||||
KubeletConfig: kubeletclient.KubeletClientConfig{
|
KubeletConfig: kubeletclient.KubeletClientConfig{
|
||||||
Port: ports.KubeletPort,
|
Port: ports.KubeletPort,
|
||||||
EnableHttps: true,
|
EnableHttps: true,
|
||||||
@ -92,69 +81,12 @@ func NewAPIServer() *APIServer {
|
|||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
|
|
||||||
// dest must be a map of group to groupVersion.
|
|
||||||
func mergeGroupVersionIntoMap(gvList string, dest map[string]unversioned.GroupVersion) error {
|
|
||||||
for _, gvString := range strings.Split(gvList, ",") {
|
|
||||||
if gvString == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// We accept two formats. "group/version" OR
|
|
||||||
// "group=group/version". The latter is used when types
|
|
||||||
// move between groups.
|
|
||||||
if !strings.Contains(gvString, "=") {
|
|
||||||
gv, err := unversioned.ParseGroupVersion(gvString)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dest[gv.Group] = gv
|
|
||||||
|
|
||||||
} else {
|
|
||||||
parts := strings.SplitN(gvString, "=", 2)
|
|
||||||
gv, err := unversioned.ParseGroupVersion(parts[1])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dest[parts[0]] = gv
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StorageGroupsToEncodingVersion returns a map from group name to group version,
|
|
||||||
// computed from the s.DeprecatedStorageVersion and s.StorageVersions flags.
|
|
||||||
// TODO: can we move the whole storage version concept to the generic apiserver?
|
|
||||||
func (s *APIServer) StorageGroupsToEncodingVersion() (map[string]unversioned.GroupVersion, error) {
|
|
||||||
storageVersionMap := map[string]unversioned.GroupVersion{}
|
|
||||||
if s.DeprecatedStorageVersion != "" {
|
|
||||||
storageVersionMap[""] = unversioned.GroupVersion{Group: apiutil.GetGroup(s.DeprecatedStorageVersion), Version: apiutil.GetVersion(s.DeprecatedStorageVersion)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// First, get the defaults.
|
|
||||||
if err := mergeGroupVersionIntoMap(s.DefaultStorageVersions, storageVersionMap); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Override any defaults with the user settings.
|
|
||||||
if err := mergeGroupVersionIntoMap(s.StorageVersions, storageVersionMap); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return storageVersionMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFlags adds flags for a specific APIServer to the specified FlagSet
|
// AddFlags adds flags for a specific APIServer to the specified FlagSet
|
||||||
func (s *APIServer) AddFlags(fs *pflag.FlagSet) {
|
func (s *APIServer) AddFlags(fs *pflag.FlagSet) {
|
||||||
// Add the generic flags.
|
// Add the generic flags.
|
||||||
s.ServerRunOptions.AddFlags(fs)
|
s.ServerRunOptions.AddFlags(fs)
|
||||||
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
||||||
// arrange these text blocks sensibly. Grrr.
|
// arrange these text blocks sensibly. Grrr.
|
||||||
fs.StringVar(&s.DeprecatedStorageVersion, "storage-version", s.DeprecatedStorageVersion, "The version to store the legacy v1 resources with. Defaults to server preferred")
|
|
||||||
fs.MarkDeprecated("storage-version", "--storage-version is deprecated and will be removed when the v1 API is retired. See --storage-versions instead.")
|
|
||||||
fs.StringVar(&s.StorageVersions, "storage-versions", s.StorageVersions, "The per-group version to store resources in. "+
|
|
||||||
"Specified in the format \"group1/version1,group2/version2,...\". "+
|
|
||||||
"In the case where objects are moved from one group to the other, you may specify the format \"group1=group2/v1beta1,group3/v1beta1,...\". "+
|
|
||||||
"You only need to pass the groups you wish to change from the defaults. "+
|
|
||||||
"It defaults to a list of preferred versions of all registered groups, which is derived from the KUBE_API_VERSIONS environment variable.")
|
|
||||||
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, "The media type to use to store objects in storage. Defaults to application/json. Some resources may only support a specific media type and will ignore this setting.")
|
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, "The media type to use to store objects in storage. Defaults to application/json. Some resources may only support a specific media type and will ignore this setting.")
|
||||||
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL, "Amount of time to retain events. Default 1 hour.")
|
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL, "Amount of time to retain events. Default 1 hour.")
|
||||||
fs.StringVar(&s.BasicAuthFile, "basic-auth-file", s.BasicAuthFile, "If set, the file that will be used to admit requests to the secure port of the API server via http basic authentication.")
|
fs.StringVar(&s.BasicAuthFile, "basic-auth-file", s.BasicAuthFile, "If set, the file that will be used to admit requests to the secure port of the API server via http basic authentication.")
|
||||||
|
@ -17,72 +17,11 @@ limitations under the License.
|
|||||||
package options
|
package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenerateStorageVersionMap(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
legacyVersion string
|
|
||||||
storageVersions string
|
|
||||||
defaultVersions string
|
|
||||||
expectedMap map[string]unversioned.GroupVersion
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
legacyVersion: "v1",
|
|
||||||
storageVersions: "v1,extensions/v1beta1",
|
|
||||||
expectedMap: map[string]unversioned.GroupVersion{
|
|
||||||
api.GroupName: {Version: "v1"},
|
|
||||||
extensions.GroupName: {Group: "extensions", Version: "v1beta1"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
legacyVersion: "",
|
|
||||||
storageVersions: "extensions/v1beta1,v1",
|
|
||||||
expectedMap: map[string]unversioned.GroupVersion{
|
|
||||||
api.GroupName: {Version: "v1"},
|
|
||||||
extensions.GroupName: {Group: "extensions", Version: "v1beta1"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
legacyVersion: "",
|
|
||||||
storageVersions: "autoscaling=extensions/v1beta1,v1",
|
|
||||||
defaultVersions: "extensions/v1beta1,v1,autoscaling/v1",
|
|
||||||
expectedMap: map[string]unversioned.GroupVersion{
|
|
||||||
api.GroupName: {Version: "v1"},
|
|
||||||
autoscaling.GroupName: {Group: "extensions", Version: "v1beta1"},
|
|
||||||
extensions.GroupName: {Group: "extensions", Version: "v1beta1"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
legacyVersion: "",
|
|
||||||
storageVersions: "",
|
|
||||||
expectedMap: map[string]unversioned.GroupVersion{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i, test := range testCases {
|
|
||||||
s := APIServer{
|
|
||||||
DeprecatedStorageVersion: test.legacyVersion,
|
|
||||||
StorageVersions: test.storageVersions,
|
|
||||||
DefaultStorageVersions: test.defaultVersions,
|
|
||||||
}
|
|
||||||
output, err := s.StorageGroupsToEncodingVersion()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v: unexpected error: %v", i, err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(test.expectedMap, output) {
|
|
||||||
t.Errorf("%v: unexpected error. expect: %v, got: %v", i, test.expectedMap, output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddFlagsFlag(t *testing.T) {
|
func TestAddFlagsFlag(t *testing.T) {
|
||||||
// TODO: This only tests the enable-swagger-ui flag for now.
|
// TODO: This only tests the enable-swagger-ui flag for now.
|
||||||
// Expand the test to include other flags as well.
|
// Expand the test to include other flags as well.
|
||||||
|
@ -21,7 +21,6 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -35,26 +34,18 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
|
||||||
appsapi "k8s.io/kubernetes/pkg/apis/apps/v1alpha1"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/batch"
|
"k8s.io/kubernetes/pkg/apis/batch"
|
||||||
batchapiv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/pkg/apiserver/authenticator"
|
"k8s.io/kubernetes/pkg/apiserver/authenticator"
|
||||||
"k8s.io/kubernetes/pkg/capabilities"
|
"k8s.io/kubernetes/pkg/capabilities"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
||||||
"k8s.io/kubernetes/pkg/master"
|
"k8s.io/kubernetes/pkg/master"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
|
||||||
"k8s.io/kubernetes/pkg/serviceaccount"
|
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -132,44 +123,17 @@ func Run(s *options.APIServer) error {
|
|||||||
glog.Fatalf("Failure to start kubelet client: %v", err)
|
glog.Fatalf("Failure to start kubelet client: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
apiResourceConfigSource, err := parseRuntimeConfig(s)
|
storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("error in parsing runtime-config: %s", err)
|
glog.Fatalf("error generating storage version map: %s", err)
|
||||||
}
|
}
|
||||||
|
storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
|
||||||
clientConfig := &restclient.Config{
|
s.StorageConfig, s.DefaultStorageMediaType, api.Codecs,
|
||||||
Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)),
|
genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
|
||||||
// Increase QPS limits. The client is currently passed to all admission plugins,
|
master.DefaultAPIResourceConfigSource(), s.RuntimeConfig)
|
||||||
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
|
||||||
// for more details. Once #22422 is fixed, we may want to remove it.
|
|
||||||
QPS: 50,
|
|
||||||
Burst: 100,
|
|
||||||
}
|
|
||||||
if len(s.DeprecatedStorageVersion) != 0 {
|
|
||||||
gv, err := unversioned.ParseGroupVersion(s.DeprecatedStorageVersion)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("error in parsing group version: %s", err)
|
|
||||||
}
|
|
||||||
clientConfig.GroupVersion = &gv
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := clientset.NewForConfig(clientConfig)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to create clientset: %v", err)
|
glog.Fatalf("error in initializing storage factory: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceEncoding := genericapiserver.NewDefaultResourceEncodingConfig()
|
|
||||||
groupToEncoding, err := s.StorageGroupsToEncodingVersion()
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("error getting group encoding: %s", err)
|
|
||||||
}
|
|
||||||
for group, storageEncodingVersion := range groupToEncoding {
|
|
||||||
resourceEncoding.SetVersionEncoding(group, storageEncodingVersion, unversioned.GroupVersion{Group: group, Version: runtime.APIVersionInternal})
|
|
||||||
}
|
|
||||||
|
|
||||||
storageFactory := genericapiserver.NewDefaultStorageFactory(s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, resourceEncoding, apiResourceConfigSource)
|
|
||||||
// third party resources are always serialized to storage using JSON
|
|
||||||
storageFactory.SetSerializer(extensions.Resource("thirdpartyresources"), "application/json", nil)
|
|
||||||
storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs"))
|
storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs"))
|
||||||
storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers"))
|
storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers"))
|
||||||
for _, override := range s.EtcdServersOverrides {
|
for _, override := range s.EtcdServersOverrides {
|
||||||
@ -238,6 +202,10 @@ func Run(s *options.APIServer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
admissionControlPluginNames := strings.Split(s.AdmissionControl, ",")
|
admissionControlPluginNames := strings.Split(s.AdmissionControl, ",")
|
||||||
|
client, err := s.NewSelfClient()
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("Failed to create clientset: %v", err)
|
||||||
|
}
|
||||||
admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile)
|
admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile)
|
||||||
|
|
||||||
genericConfig := genericapiserver.NewConfig(s.ServerRunOptions)
|
genericConfig := genericapiserver.NewConfig(s.ServerRunOptions)
|
||||||
@ -247,7 +215,7 @@ func Run(s *options.APIServer) error {
|
|||||||
genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0
|
genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0
|
||||||
genericConfig.Authorizer = authorizer
|
genericConfig.Authorizer = authorizer
|
||||||
genericConfig.AdmissionControl = admissionController
|
genericConfig.AdmissionControl = admissionController
|
||||||
genericConfig.APIResourceConfigSource = apiResourceConfigSource
|
genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource
|
||||||
genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
|
genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
|
||||||
genericConfig.ProxyDialer = proxyDialerFn
|
genericConfig.ProxyDialer = proxyDialerFn
|
||||||
genericConfig.ProxyTLSClientConfig = proxyTLSClientConfig
|
genericConfig.ProxyTLSClientConfig = proxyTLSClientConfig
|
||||||
@ -275,85 +243,3 @@ func Run(s *options.APIServer) error {
|
|||||||
m.Run(s.ServerRunOptions)
|
m.Run(s.ServerRunOptions)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRuntimeConfigValue(s *options.APIServer, apiKey string, defaultValue bool) bool {
|
|
||||||
flagValue, ok := s.RuntimeConfig[apiKey]
|
|
||||||
if ok {
|
|
||||||
if flagValue == "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
boolValue, err := strconv.ParseBool(flagValue)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("Invalid value of %s: %s, err: %v", apiKey, flagValue, err)
|
|
||||||
}
|
|
||||||
return boolValue
|
|
||||||
}
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses the given runtime-config and formats it into genericapiserver.APIResourceConfigSource
|
|
||||||
func parseRuntimeConfig(s *options.APIServer) (genericapiserver.APIResourceConfigSource, error) {
|
|
||||||
v1GroupVersionString := "api/v1"
|
|
||||||
extensionsGroupVersionString := extensionsapiv1beta1.SchemeGroupVersion.String()
|
|
||||||
versionToResourceSpecifier := map[unversioned.GroupVersion]string{
|
|
||||||
apiv1.SchemeGroupVersion: v1GroupVersionString,
|
|
||||||
extensionsapiv1beta1.SchemeGroupVersion: extensionsGroupVersionString,
|
|
||||||
batchapiv1.SchemeGroupVersion: batchapiv1.SchemeGroupVersion.String(),
|
|
||||||
autoscalingapiv1.SchemeGroupVersion: autoscalingapiv1.SchemeGroupVersion.String(),
|
|
||||||
appsapi.SchemeGroupVersion: appsapi.SchemeGroupVersion.String(),
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceConfig := master.DefaultAPIResourceConfigSource()
|
|
||||||
|
|
||||||
// "api/all=false" allows users to selectively enable specific api versions.
|
|
||||||
enableAPIByDefault := true
|
|
||||||
allAPIFlagValue, ok := s.RuntimeConfig["api/all"]
|
|
||||||
if ok && allAPIFlagValue == "false" {
|
|
||||||
enableAPIByDefault = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// "api/legacy=false" allows users to disable legacy api versions.
|
|
||||||
disableLegacyAPIs := false
|
|
||||||
legacyAPIFlagValue, ok := s.RuntimeConfig["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.
|
|
||||||
for version, resourceSpecifier := range versionToResourceSpecifier {
|
|
||||||
enableVersion := getRuntimeConfigValue(s, resourceSpecifier, enableAPIByDefault)
|
|
||||||
if enableVersion {
|
|
||||||
resourceConfig.EnableVersions(version)
|
|
||||||
} else {
|
|
||||||
resourceConfig.DisableVersions(version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key := range s.RuntimeConfig {
|
|
||||||
tokens := strings.Split(key, "/")
|
|
||||||
if len(tokens) != 3 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(key, extensionsGroupVersionString+"/"):
|
|
||||||
if !resourceConfig.AnyResourcesForVersionEnabled(extensionsapiv1beta1.SchemeGroupVersion) {
|
|
||||||
return nil, fmt.Errorf("%v is disabled, you cannot configure its resources individually", extensionsapiv1beta1.SchemeGroupVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
resource := strings.TrimPrefix(key, extensionsGroupVersionString+"/")
|
|
||||||
if getRuntimeConfigValue(s, key, false) {
|
|
||||||
resourceConfig.EnableResources(extensionsapiv1beta1.SchemeGroupVersion.WithResource(resource))
|
|
||||||
} else {
|
|
||||||
resourceConfig.DisableResources(extensionsapiv1beta1.SchemeGroupVersion.WithResource(resource))
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
// TODO enable individual resource capability for all GroupVersionResources
|
|
||||||
return nil, fmt.Errorf("%v resources cannot be enabled/disabled individually", key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resourceConfig, nil
|
|
||||||
}
|
|
||||||
|
@ -17,14 +17,10 @@ limitations under the License.
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
|
||||||
"k8s.io/kubernetes/pkg/master"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLongRunningRequestRegexp(t *testing.T) {
|
func TestLongRunningRequestRegexp(t *testing.T) {
|
||||||
@ -67,99 +63,3 @@ func TestLongRunningRequestRegexp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseRuntimeConfig(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
runtimeConfig map[string]string
|
|
||||||
expectedAPIConfig func() *genericapiserver.ResourceConfig
|
|
||||||
err bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
runtimeConfig: map[string]string{},
|
|
||||||
expectedAPIConfig: func() *genericapiserver.ResourceConfig {
|
|
||||||
return master.DefaultAPIResourceConfigSource()
|
|
||||||
},
|
|
||||||
err: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Cannot override v1 resources.
|
|
||||||
runtimeConfig: map[string]string{
|
|
||||||
"api/v1/pods": "false",
|
|
||||||
},
|
|
||||||
expectedAPIConfig: func() *genericapiserver.ResourceConfig {
|
|
||||||
return master.DefaultAPIResourceConfigSource()
|
|
||||||
},
|
|
||||||
err: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Disable v1.
|
|
||||||
runtimeConfig: map[string]string{
|
|
||||||
"api/v1": "false",
|
|
||||||
},
|
|
||||||
expectedAPIConfig: func() *genericapiserver.ResourceConfig {
|
|
||||||
config := master.DefaultAPIResourceConfigSource()
|
|
||||||
config.DisableVersions(unversioned.GroupVersion{Group: "", Version: "v1"})
|
|
||||||
return config
|
|
||||||
},
|
|
||||||
err: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Disable extensions.
|
|
||||||
runtimeConfig: map[string]string{
|
|
||||||
"extensions/v1beta1": "false",
|
|
||||||
},
|
|
||||||
expectedAPIConfig: func() *genericapiserver.ResourceConfig {
|
|
||||||
config := master.DefaultAPIResourceConfigSource()
|
|
||||||
config.DisableVersions(unversioned.GroupVersion{Group: "extensions", Version: "v1beta1"})
|
|
||||||
return config
|
|
||||||
},
|
|
||||||
err: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Disable deployments.
|
|
||||||
runtimeConfig: map[string]string{
|
|
||||||
"extensions/v1beta1/deployments": "false",
|
|
||||||
},
|
|
||||||
expectedAPIConfig: func() *genericapiserver.ResourceConfig {
|
|
||||||
config := master.DefaultAPIResourceConfigSource()
|
|
||||||
config.DisableResources(unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"})
|
|
||||||
return config
|
|
||||||
},
|
|
||||||
err: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Enable deployments and disable jobs.
|
|
||||||
runtimeConfig: map[string]string{
|
|
||||||
"extensions/v1beta1/anything": "true",
|
|
||||||
"extensions/v1beta1/jobs": "false",
|
|
||||||
},
|
|
||||||
expectedAPIConfig: func() *genericapiserver.ResourceConfig {
|
|
||||||
config := master.DefaultAPIResourceConfigSource()
|
|
||||||
config.DisableResources(unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "jobs"})
|
|
||||||
config.EnableResources(unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "anything"})
|
|
||||||
return config
|
|
||||||
},
|
|
||||||
err: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range testCases {
|
|
||||||
s := &options.APIServer{
|
|
||||||
ServerRunOptions: &genericapiserver.ServerRunOptions{
|
|
||||||
RuntimeConfig: test.runtimeConfig,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
actualDisablers, err := parseRuntimeConfig(s)
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -119,7 +119,7 @@ kube-apiserver
|
|||||||
--watch-cache-sizes=[]: List of watch cache sizes for every resource (pods, nodes, etc.), comma separated. The individual override format: resource#size, where size is a number. It takes effect when watch-cache is enabled.
|
--watch-cache-sizes=[]: List of watch cache sizes for every resource (pods, nodes, etc.), comma separated. The individual override format: resource#size, where size is a number. It takes effect when watch-cache is enabled.
|
||||||
```
|
```
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 8-May-2016
|
###### Auto generated by spf13/cobra on 9-May-2016
|
||||||
|
|
||||||
|
|
||||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||||
|
@ -23,8 +23,6 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
|
||||||
apiutil "k8s.io/kubernetes/pkg/api/util"
|
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
@ -92,69 +90,12 @@ func NewAPIServer() *APIServer {
|
|||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
|
|
||||||
// dest must be a map of group to groupVersion.
|
|
||||||
func mergeGroupVersionIntoMap(gvList string, dest map[string]unversioned.GroupVersion) error {
|
|
||||||
for _, gvString := range strings.Split(gvList, ",") {
|
|
||||||
if gvString == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// We accept two formats. "group/version" OR
|
|
||||||
// "group=group/version". The latter is used when types
|
|
||||||
// move between groups.
|
|
||||||
if !strings.Contains(gvString, "=") {
|
|
||||||
gv, err := unversioned.ParseGroupVersion(gvString)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dest[gv.Group] = gv
|
|
||||||
|
|
||||||
} else {
|
|
||||||
parts := strings.SplitN(gvString, "=", 2)
|
|
||||||
gv, err := unversioned.ParseGroupVersion(parts[1])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dest[parts[0]] = gv
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StorageGroupsToEncodingVersion returns a map from group name to group version,
|
|
||||||
// computed from the s.DeprecatedStorageVersion and s.StorageVersions flags.
|
|
||||||
// TODO: can we move the whole storage version concept to the generic apiserver?
|
|
||||||
func (s *APIServer) StorageGroupsToEncodingVersion() (map[string]unversioned.GroupVersion, error) {
|
|
||||||
storageVersionMap := map[string]unversioned.GroupVersion{}
|
|
||||||
if s.DeprecatedStorageVersion != "" {
|
|
||||||
storageVersionMap[""] = unversioned.GroupVersion{Group: apiutil.GetGroup(s.DeprecatedStorageVersion), Version: apiutil.GetVersion(s.DeprecatedStorageVersion)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// First, get the defaults.
|
|
||||||
if err := mergeGroupVersionIntoMap(s.DefaultStorageVersions, storageVersionMap); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Override any defaults with the user settings.
|
|
||||||
if err := mergeGroupVersionIntoMap(s.StorageVersions, storageVersionMap); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return storageVersionMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFlags adds flags for a specific APIServer to the specified FlagSet
|
// AddFlags adds flags for a specific APIServer to the specified FlagSet
|
||||||
func (s *APIServer) AddFlags(fs *pflag.FlagSet) {
|
func (s *APIServer) AddFlags(fs *pflag.FlagSet) {
|
||||||
// Add the generic flags.
|
// Add the generic flags.
|
||||||
s.ServerRunOptions.AddFlags(fs)
|
s.ServerRunOptions.AddFlags(fs)
|
||||||
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
||||||
// arrange these text blocks sensibly. Grrr.
|
// arrange these text blocks sensibly. Grrr.
|
||||||
fs.StringVar(&s.DeprecatedStorageVersion, "storage-version", s.DeprecatedStorageVersion, "The version to store the legacy v1 resources with. Defaults to server preferred")
|
|
||||||
fs.MarkDeprecated("storage-version", "--storage-version is deprecated and will be removed when the v1 API is retired. See --storage-versions instead.")
|
|
||||||
fs.StringVar(&s.StorageVersions, "storage-versions", s.StorageVersions, "The per-group version to store resources in. "+
|
|
||||||
"Specified in the format \"group1/version1,group2/version2,...\". "+
|
|
||||||
"In the case where objects are moved from one group to the other, you may specify the format \"group1=group2/v1beta1,group3/v1beta1,...\". "+
|
|
||||||
"You only need to pass the groups you wish to change from the defaults. "+
|
|
||||||
"It defaults to a list of preferred versions of all registered groups, which is derived from the KUBE_API_VERSIONS environment variable.")
|
|
||||||
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, "The media type to use to store objects in storage. Defaults to application/json. Some resources may only support a specific media type and will ignore this setting.")
|
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, "The media type to use to store objects in storage. Defaults to application/json. Some resources may only support a specific media type and will ignore this setting.")
|
||||||
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL, "Amount of time to retain events. Default 1 hour.")
|
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL, "Amount of time to retain events. Default 1 hour.")
|
||||||
fs.StringVar(&s.BasicAuthFile, "basic-auth-file", s.BasicAuthFile, "If set, the file that will be used to admit requests to the secure port of the API server via http basic authentication.")
|
fs.StringVar(&s.BasicAuthFile, "basic-auth-file", s.BasicAuthFile, "If set, the file that will be used to admit requests to the secure port of the API server via http basic authentication.")
|
||||||
|
@ -17,72 +17,11 @@ limitations under the License.
|
|||||||
package options
|
package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenerateStorageVersionMap(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
legacyVersion string
|
|
||||||
storageVersions string
|
|
||||||
defaultVersions string
|
|
||||||
expectedMap map[string]unversioned.GroupVersion
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
legacyVersion: "v1",
|
|
||||||
storageVersions: "v1,extensions/v1beta1",
|
|
||||||
expectedMap: map[string]unversioned.GroupVersion{
|
|
||||||
api.GroupName: {Version: "v1"},
|
|
||||||
extensions.GroupName: {Group: "extensions", Version: "v1beta1"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
legacyVersion: "",
|
|
||||||
storageVersions: "extensions/v1beta1,v1",
|
|
||||||
expectedMap: map[string]unversioned.GroupVersion{
|
|
||||||
api.GroupName: {Version: "v1"},
|
|
||||||
extensions.GroupName: {Group: "extensions", Version: "v1beta1"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
legacyVersion: "",
|
|
||||||
storageVersions: "autoscaling=extensions/v1beta1,v1",
|
|
||||||
defaultVersions: "extensions/v1beta1,v1,autoscaling/v1",
|
|
||||||
expectedMap: map[string]unversioned.GroupVersion{
|
|
||||||
api.GroupName: {Version: "v1"},
|
|
||||||
autoscaling.GroupName: {Group: "extensions", Version: "v1beta1"},
|
|
||||||
extensions.GroupName: {Group: "extensions", Version: "v1beta1"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
legacyVersion: "",
|
|
||||||
storageVersions: "",
|
|
||||||
expectedMap: map[string]unversioned.GroupVersion{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i, test := range testCases {
|
|
||||||
s := APIServer{
|
|
||||||
DeprecatedStorageVersion: test.legacyVersion,
|
|
||||||
StorageVersions: test.storageVersions,
|
|
||||||
DefaultStorageVersions: test.defaultVersions,
|
|
||||||
}
|
|
||||||
output, err := s.StorageGroupsToEncodingVersion()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v: unexpected error: %v", i, err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(test.expectedMap, output) {
|
|
||||||
t.Errorf("%v: unexpected error. expect: %v, got: %v", i, test.expectedMap, output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddFlagsFlag(t *testing.T) {
|
func TestAddFlagsFlag(t *testing.T) {
|
||||||
// TODO: This only tests the enable-swagger-ui flag for now.
|
// TODO: This only tests the enable-swagger-ui flag for now.
|
||||||
// Expand the test to include other flags as well.
|
// Expand the test to include other flags as well.
|
||||||
|
@ -20,8 +20,6 @@ limitations under the License.
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@ -34,11 +32,8 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/pkg/apiserver/authenticator"
|
"k8s.io/kubernetes/pkg/apiserver/authenticator"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewAPIServerCommand creates a *cobra.Command object with default parameters
|
// NewAPIServerCommand creates a *cobra.Command object with default parameters
|
||||||
@ -62,21 +57,21 @@ cluster's shared state through which all other components interact.`,
|
|||||||
func Run(s *options.APIServer) error {
|
func Run(s *options.APIServer) error {
|
||||||
genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions)
|
genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions)
|
||||||
|
|
||||||
apiResourceConfigSource, err := parseRuntimeConfig(s)
|
// TODO: register cluster federation resources here.
|
||||||
|
resourceConfig := genericapiserver.NewResourceConfig()
|
||||||
|
|
||||||
|
storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("error in parsing runtime-config: %s", err)
|
glog.Fatalf("error generating storage version map: %s", err)
|
||||||
|
}
|
||||||
|
storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
|
||||||
|
s.StorageConfig, s.DefaultStorageMediaType, api.Codecs,
|
||||||
|
genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
|
||||||
|
resourceConfig, s.RuntimeConfig)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("error in initializing storage factory: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceEncoding := genericapiserver.NewDefaultResourceEncodingConfig()
|
|
||||||
groupToEncoding, err := s.StorageGroupsToEncodingVersion()
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("error getting group encoding: %s", err)
|
|
||||||
}
|
|
||||||
for group, storageEncodingVersion := range groupToEncoding {
|
|
||||||
resourceEncoding.SetVersionEncoding(group, storageEncodingVersion, unversioned.GroupVersion{Group: group, Version: runtime.APIVersionInternal})
|
|
||||||
}
|
|
||||||
|
|
||||||
storageFactory := genericapiserver.NewDefaultStorageFactory(s.StorageConfig, s.DefaultStorageMediaType, api.Codecs, resourceEncoding, apiResourceConfigSource)
|
|
||||||
for _, override := range s.EtcdServersOverrides {
|
for _, override := range s.EtcdServersOverrides {
|
||||||
tokens := strings.Split(override, "#")
|
tokens := strings.Split(override, "#")
|
||||||
if len(tokens) != 2 {
|
if len(tokens) != 2 {
|
||||||
@ -119,27 +114,10 @@ func Run(s *options.APIServer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
admissionControlPluginNames := strings.Split(s.AdmissionControl, ",")
|
admissionControlPluginNames := strings.Split(s.AdmissionControl, ",")
|
||||||
clientConfig := &restclient.Config{
|
client, err := s.NewSelfClient()
|
||||||
Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)),
|
|
||||||
// Increase QPS limits. The client is currently passed to all admission plugins,
|
|
||||||
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
|
||||||
// for more details. Once #22422 is fixed, we may want to remove it.
|
|
||||||
QPS: 50,
|
|
||||||
Burst: 100,
|
|
||||||
}
|
|
||||||
if len(s.DeprecatedStorageVersion) != 0 {
|
|
||||||
gv, err := unversioned.ParseGroupVersion(s.DeprecatedStorageVersion)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("error in parsing group version: %s", err)
|
|
||||||
}
|
|
||||||
clientConfig.GroupVersion = &gv
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := clientset.NewForConfig(clientConfig)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to create clientset: %v", err)
|
glog.Errorf("Failed to create clientset: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile)
|
admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile)
|
||||||
|
|
||||||
genericConfig := genericapiserver.NewConfig(s.ServerRunOptions)
|
genericConfig := genericapiserver.NewConfig(s.ServerRunOptions)
|
||||||
@ -149,7 +127,7 @@ func Run(s *options.APIServer) error {
|
|||||||
genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0
|
genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0
|
||||||
genericConfig.Authorizer = authorizer
|
genericConfig.Authorizer = authorizer
|
||||||
genericConfig.AdmissionControl = admissionController
|
genericConfig.AdmissionControl = admissionController
|
||||||
genericConfig.APIResourceConfigSource = apiResourceConfigSource
|
genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource
|
||||||
genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
|
genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
|
||||||
genericConfig.Serializer = api.Codecs
|
genericConfig.Serializer = api.Codecs
|
||||||
|
|
||||||
@ -168,25 +146,3 @@ func Run(s *options.APIServer) error {
|
|||||||
m.Run(s.ServerRunOptions)
|
m.Run(s.ServerRunOptions)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRuntimeConfigValue(s *options.APIServer, apiKey string, defaultValue bool) bool {
|
|
||||||
flagValue, ok := s.RuntimeConfig[apiKey]
|
|
||||||
if ok {
|
|
||||||
if flagValue == "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
boolValue, err := strconv.ParseBool(flagValue)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("Invalid value of %s: %s, err: %v", apiKey, flagValue, err)
|
|
||||||
}
|
|
||||||
return boolValue
|
|
||||||
}
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses the given runtime-config and formats it into genericapiserver.APIResourceConfigSource
|
|
||||||
func parseRuntimeConfig(s *options.APIServer) (genericapiserver.APIResourceConfigSource, error) {
|
|
||||||
// TODO: parse the relevant group version when we add any.
|
|
||||||
resourceConfig := genericapiserver.NewResourceConfig()
|
|
||||||
return resourceConfig, nil
|
|
||||||
}
|
|
||||||
|
@ -168,6 +168,15 @@ func IsRegisteredVersion(v unversioned.GroupVersion) bool {
|
|||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisteredGroupVersions returns all registered group versions.
|
||||||
|
func RegisteredGroupVersions() []unversioned.GroupVersion {
|
||||||
|
ret := []unversioned.GroupVersion{}
|
||||||
|
for groupVersion := range registeredVersions {
|
||||||
|
ret = append(ret, groupVersion)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
// IsThirdPartyAPIGroupVersion returns true if the api version is a user-registered group/version.
|
// IsThirdPartyAPIGroupVersion returns true if the api version is a user-registered group/version.
|
||||||
func IsThirdPartyAPIGroupVersion(gv unversioned.GroupVersion) bool {
|
func IsThirdPartyAPIGroupVersion(gv unversioned.GroupVersion) bool {
|
||||||
for ix := range thirdPartyGroupVersions {
|
for ix := range thirdPartyGroupVersions {
|
||||||
|
167
pkg/genericapiserver/default_storage_factory_builder.go
Normal file
167
pkg/genericapiserver/default_storage_factory_builder.go
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package genericapiserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/storage/storagebackend"
|
||||||
|
"k8s.io/kubernetes/pkg/util/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Builds the DefaultStorageFactory.
|
||||||
|
// Merges defaultResourceConfig with the user specified overrides and merges
|
||||||
|
// defaultAPIResourceConfig with the corresponding user specified overrides as well.
|
||||||
|
func BuildDefaultStorageFactory(storageConfig storagebackend.Config, defaultMediaType string, serializer runtime.StorageSerializer,
|
||||||
|
defaultResourceEncoding *DefaultResourceEncodingConfig, storageEncodingOverrides map[string]unversioned.GroupVersion, defaultAPIResourceConfig *ResourceConfig, resourceConfigOverrides config.ConfigurationMap) (*DefaultStorageFactory, error) {
|
||||||
|
|
||||||
|
resourceEncodingConfig := mergeResourceEncodingConfigs(defaultResourceEncoding, storageEncodingOverrides)
|
||||||
|
apiResourceConfig, err := mergeAPIResourceConfigs(defaultAPIResourceConfig, resourceConfigOverrides)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewDefaultStorageFactory(storageConfig, defaultMediaType, serializer, resourceEncodingConfig, apiResourceConfig), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merges the given defaultAPIResourceConfig with the given storageEncodingOverrides.
|
||||||
|
func mergeResourceEncodingConfigs(defaultResourceEncoding *DefaultResourceEncodingConfig, storageEncodingOverrides map[string]unversioned.GroupVersion) *DefaultResourceEncodingConfig {
|
||||||
|
resourceEncodingConfig := defaultResourceEncoding
|
||||||
|
for group, storageEncodingVersion := range storageEncodingOverrides {
|
||||||
|
resourceEncodingConfig.SetVersionEncoding(group, storageEncodingVersion, unversioned.GroupVersion{Group: group, Version: runtime.APIVersionInternal})
|
||||||
|
}
|
||||||
|
return resourceEncodingConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRuntimeConfigValue(overrides config.ConfigurationMap, apiKey string, defaultValue bool) (bool, error) {
|
||||||
|
flagValue, ok := overrides[apiKey]
|
||||||
|
if ok {
|
||||||
|
if flagValue == "" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
boolValue, err := strconv.ParseBool(flagValue)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("invalid value of %s: %s, err: %v", apiKey, flagValue, err)
|
||||||
|
}
|
||||||
|
return boolValue, nil
|
||||||
|
}
|
||||||
|
return defaultValue, nil
|
||||||
|
}
|
177
pkg/genericapiserver/default_storage_factory_builder_test.go
Normal file
177
pkg/genericapiserver/default_storage_factory_builder_test.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package genericapiserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
|
)
|
||||||
|
|
||||||
|
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(unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"})
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
err: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,11 +18,19 @@ package genericapiserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
apiutil "k8s.io/kubernetes/pkg/api/util"
|
||||||
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||||
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
"k8s.io/kubernetes/pkg/storage/storagebackend"
|
"k8s.io/kubernetes/pkg/storage/storagebackend"
|
||||||
"k8s.io/kubernetes/pkg/util/config"
|
"k8s.io/kubernetes/pkg/util/config"
|
||||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,15 +41,17 @@ const (
|
|||||||
|
|
||||||
// ServerRunOptions contains the options while running a generic api server.
|
// ServerRunOptions contains the options while running a generic api server.
|
||||||
type ServerRunOptions struct {
|
type ServerRunOptions struct {
|
||||||
APIGroupPrefix string
|
APIGroupPrefix string
|
||||||
APIPrefix string
|
APIPrefix string
|
||||||
AdvertiseAddress net.IP
|
AdvertiseAddress net.IP
|
||||||
BindAddress net.IP
|
BindAddress net.IP
|
||||||
CertDirectory string
|
CertDirectory string
|
||||||
ClientCAFile string
|
ClientCAFile string
|
||||||
CloudConfigFile string
|
CloudConfigFile string
|
||||||
CloudProvider string
|
CloudProvider string
|
||||||
CorsAllowedOriginList []string
|
CorsAllowedOriginList []string
|
||||||
|
// Used to specify the storage version that should be used for the legacy v1 api group.
|
||||||
|
DeprecatedStorageVersion string
|
||||||
EnableLogsSupport bool
|
EnableLogsSupport bool
|
||||||
EnableProfiling bool
|
EnableProfiling bool
|
||||||
EnableSwaggerUI bool
|
EnableSwaggerUI bool
|
||||||
@ -59,16 +69,22 @@ type ServerRunOptions struct {
|
|||||||
SecurePort int
|
SecurePort int
|
||||||
ServiceClusterIPRange net.IPNet // TODO: make this a list
|
ServiceClusterIPRange net.IPNet // TODO: make this a list
|
||||||
ServiceNodePortRange utilnet.PortRange
|
ServiceNodePortRange utilnet.PortRange
|
||||||
TLSCertFile string
|
StorageVersions string
|
||||||
TLSPrivateKeyFile string
|
// The default values for StorageVersions. StorageVersions overrides
|
||||||
|
// these; you can change this if you want to change the defaults (e.g.,
|
||||||
|
// for testing). This is not actually exposed as a flag.
|
||||||
|
DefaultStorageVersions string
|
||||||
|
TLSCertFile string
|
||||||
|
TLSPrivateKeyFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerRunOptions() *ServerRunOptions {
|
func NewServerRunOptions() *ServerRunOptions {
|
||||||
return &ServerRunOptions{
|
return &ServerRunOptions{
|
||||||
APIGroupPrefix: "/apis",
|
APIGroupPrefix: "/apis",
|
||||||
APIPrefix: "/api",
|
APIPrefix: "/api",
|
||||||
BindAddress: net.ParseIP("0.0.0.0"),
|
BindAddress: net.ParseIP("0.0.0.0"),
|
||||||
CertDirectory: "/var/run/kubernetes",
|
CertDirectory: "/var/run/kubernetes",
|
||||||
|
DefaultStorageVersions: registered.AllPreferredGroupVersions(),
|
||||||
StorageConfig: storagebackend.Config{
|
StorageConfig: storagebackend.Config{
|
||||||
Prefix: DefaultEtcdPathPrefix,
|
Prefix: DefaultEtcdPathPrefix,
|
||||||
DeserializationCacheSize: DefaultDeserializationCacheSize,
|
DeserializationCacheSize: DefaultDeserializationCacheSize,
|
||||||
@ -84,9 +100,80 @@ func NewServerRunOptions() *ServerRunOptions {
|
|||||||
MinRequestTimeout: 1800,
|
MinRequestTimeout: 1800,
|
||||||
RuntimeConfig: make(config.ConfigurationMap),
|
RuntimeConfig: make(config.ConfigurationMap),
|
||||||
SecurePort: 6443,
|
SecurePort: 6443,
|
||||||
|
StorageVersions: registered.AllPreferredGroupVersions(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StorageGroupsToEncodingVersion returns a map from group name to group version,
|
||||||
|
// computed from the s.DeprecatedStorageVersion and s.StorageVersions flags.
|
||||||
|
func (s *ServerRunOptions) StorageGroupsToEncodingVersion() (map[string]unversioned.GroupVersion, error) {
|
||||||
|
storageVersionMap := map[string]unversioned.GroupVersion{}
|
||||||
|
if s.DeprecatedStorageVersion != "" {
|
||||||
|
storageVersionMap[""] = unversioned.GroupVersion{Group: apiutil.GetGroup(s.DeprecatedStorageVersion), Version: apiutil.GetVersion(s.DeprecatedStorageVersion)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, get the defaults.
|
||||||
|
if err := mergeGroupVersionIntoMap(s.DefaultStorageVersions, storageVersionMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Override any defaults with the user settings.
|
||||||
|
if err := mergeGroupVersionIntoMap(s.StorageVersions, storageVersionMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return storageVersionMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dest must be a map of group to groupVersion.
|
||||||
|
func mergeGroupVersionIntoMap(gvList string, dest map[string]unversioned.GroupVersion) error {
|
||||||
|
for _, gvString := range strings.Split(gvList, ",") {
|
||||||
|
if gvString == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// We accept two formats. "group/version" OR
|
||||||
|
// "group=group/version". The latter is used when types
|
||||||
|
// move between groups.
|
||||||
|
if !strings.Contains(gvString, "=") {
|
||||||
|
gv, err := unversioned.ParseGroupVersion(gvString)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dest[gv.Group] = gv
|
||||||
|
|
||||||
|
} else {
|
||||||
|
parts := strings.SplitN(gvString, "=", 2)
|
||||||
|
gv, err := unversioned.ParseGroupVersion(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dest[parts[0]] = gv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a clientset which can be used to talk to this apiserver.
|
||||||
|
func (s *ServerRunOptions) NewSelfClient() (clientset.Interface, error) {
|
||||||
|
clientConfig := &restclient.Config{
|
||||||
|
Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)),
|
||||||
|
// Increase QPS limits. The client is currently passed to all admission plugins,
|
||||||
|
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
||||||
|
// for more details. Once #22422 is fixed, we may want to remove it.
|
||||||
|
QPS: 50,
|
||||||
|
Burst: 100,
|
||||||
|
}
|
||||||
|
if len(s.DeprecatedStorageVersion) != 0 {
|
||||||
|
gv, err := unversioned.ParseGroupVersion(s.DeprecatedStorageVersion)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("error in parsing group version: %s", err)
|
||||||
|
}
|
||||||
|
clientConfig.GroupVersion = &gv
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientset.NewForConfig(clientConfig)
|
||||||
|
}
|
||||||
|
|
||||||
// AddFlags adds flags for a specific APIServer to the specified FlagSet
|
// AddFlags adds flags for a specific APIServer to the specified FlagSet
|
||||||
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
|
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
||||||
@ -171,6 +258,14 @@ func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
|
|||||||
fs.Var(&s.ServiceNodePortRange, "service-node-ports", "Deprecated: see --service-node-port-range instead.")
|
fs.Var(&s.ServiceNodePortRange, "service-node-ports", "Deprecated: see --service-node-port-range instead.")
|
||||||
fs.MarkDeprecated("service-node-ports", "see --service-node-port-range instead.")
|
fs.MarkDeprecated("service-node-ports", "see --service-node-port-range instead.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.DeprecatedStorageVersion, "storage-version", s.DeprecatedStorageVersion, "The version to store the legacy v1 resources with. Defaults to server preferred")
|
||||||
|
fs.MarkDeprecated("storage-version", "--storage-version is deprecated and will be removed when the v1 API is retired. See --storage-versions instead.")
|
||||||
|
fs.StringVar(&s.StorageVersions, "storage-versions", s.StorageVersions, "The per-group version to store resources in. "+
|
||||||
|
"Specified in the format \"group1/version1,group2/version2,...\". "+
|
||||||
|
"In the case where objects are moved from one group to the other, you may specify the format \"group1=group2/v1beta1,group3/v1beta1,...\". "+
|
||||||
|
"You only need to pass the groups you wish to change from the defaults. "+
|
||||||
|
"It defaults to a list of preferred versions of all registered groups, which is derived from the KUBE_API_VERSIONS environment variable.")
|
||||||
|
|
||||||
fs.StringVar(&s.TLSCertFile, "tls-cert-file", s.TLSCertFile, ""+
|
fs.StringVar(&s.TLSCertFile, "tls-cert-file", s.TLSCertFile, ""+
|
||||||
"File containing x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert). "+
|
"File containing x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert). "+
|
||||||
"If HTTPS serving is enabled, and --tls-cert-file and --tls-private-key-file are not provided, "+
|
"If HTTPS serving is enabled, and --tls-cert-file and --tls-private-key-file are not provided, "+
|
||||||
|
82
pkg/genericapiserver/server_run_options_test.go
Normal file
82
pkg/genericapiserver/server_run_options_test.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package genericapiserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateStorageVersionMap(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
legacyVersion string
|
||||||
|
storageVersions string
|
||||||
|
defaultVersions string
|
||||||
|
expectedMap map[string]unversioned.GroupVersion
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
legacyVersion: "v1",
|
||||||
|
storageVersions: "v1,extensions/v1beta1",
|
||||||
|
expectedMap: map[string]unversioned.GroupVersion{
|
||||||
|
api.GroupName: {Version: "v1"},
|
||||||
|
extensions.GroupName: {Group: "extensions", Version: "v1beta1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
legacyVersion: "",
|
||||||
|
storageVersions: "extensions/v1beta1,v1",
|
||||||
|
expectedMap: map[string]unversioned.GroupVersion{
|
||||||
|
api.GroupName: {Version: "v1"},
|
||||||
|
extensions.GroupName: {Group: "extensions", Version: "v1beta1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
legacyVersion: "",
|
||||||
|
storageVersions: "autoscaling=extensions/v1beta1,v1",
|
||||||
|
defaultVersions: "extensions/v1beta1,v1,autoscaling/v1",
|
||||||
|
expectedMap: map[string]unversioned.GroupVersion{
|
||||||
|
api.GroupName: {Version: "v1"},
|
||||||
|
autoscaling.GroupName: {Group: "extensions", Version: "v1beta1"},
|
||||||
|
extensions.GroupName: {Group: "extensions", Version: "v1beta1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
legacyVersion: "",
|
||||||
|
storageVersions: "",
|
||||||
|
expectedMap: map[string]unversioned.GroupVersion{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, test := range testCases {
|
||||||
|
s := ServerRunOptions{
|
||||||
|
DeprecatedStorageVersion: test.legacyVersion,
|
||||||
|
StorageVersions: test.storageVersions,
|
||||||
|
DefaultStorageVersions: test.defaultVersions,
|
||||||
|
}
|
||||||
|
output, err := s.StorageGroupsToEncodingVersion()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v: unexpected error: %v", i, err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(test.expectedMap, output) {
|
||||||
|
t.Errorf("%v: unexpected error. expect: %v, got: %v", i, test.expectedMap, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user