From c449baea469ac1884261b5a9b9c773b849c968ac Mon Sep 17 00:00:00 2001 From: Chao Xu Date: Mon, 21 Sep 2015 15:57:05 -0700 Subject: [PATCH] Remove ExpStorageVersion and Add StorageVersions to APIServer struct --- cmd/kube-apiserver/app/server.go | 53 ++++++++++++++++-------- cmd/kube-apiserver/app/server_test.go | 37 +++++++++++++++++ hack/verify-flags/known-flags.txt | 1 + pkg/api/latest/latest.go | 19 +++++++++ pkg/api/latest/latest_test.go | 59 +++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 16 deletions(-) create mode 100644 pkg/api/latest/latest_test.go diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 66f4491b218..454ec6837e5 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -36,6 +36,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/latest" "k8s.io/kubernetes/pkg/api/meta" + apiutil "k8s.io/kubernetes/pkg/api/util" "k8s.io/kubernetes/pkg/apiserver" "k8s.io/kubernetes/pkg/capabilities" client "k8s.io/kubernetes/pkg/client/unversioned" @@ -73,8 +74,8 @@ type APIServer struct { CertDirectory string APIPrefix string APIGroupPrefix string - StorageVersion string - ExpStorageVersion string + DeprecatedStorageVersion string + StorageVersions string CloudProvider string CloudConfigFile string EventTTL time.Duration @@ -131,6 +132,7 @@ func NewAPIServer() *APIServer { MasterServiceNamespace: api.NamespaceDefault, ClusterName: "kubernetes", CertDirectory: "/var/run/kubernetes", + StorageVersions: latest.AllPreferredGroupVersions(), RuntimeConfig: make(util.ConfigurationMap), KubeletConfig: client.KubeletConfig{ @@ -181,8 +183,13 @@ func (s *APIServer) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.CertDirectory, "cert-dir", s.CertDirectory, "The directory where the TLS certs are located (by default /var/run/kubernetes). "+ "If --tls-cert-file and --tls-private-key-file are provided, this flag will be ignored.") fs.StringVar(&s.APIPrefix, "api-prefix", s.APIPrefix, "The prefix for API requests on the server. Default '/api'.") - fs.MarkDeprecated("api-prefix", "--api-prefix is deprecated and will be removed when the v1 API is retired") - fs.StringVar(&s.StorageVersion, "storage-version", s.StorageVersion, "The version to store resources with. Defaults to server preferred") + fs.MarkDeprecated("api-prefix", "--api-prefix is deprecated and will be removed when the v1 API is retired.") + 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 versions to store resources with. "+ + "Different groups may be stored in different versions. Specified in the format \"group1/version1,group2/version2...\". "+ + "This flag expects a complete list of storage versions of ALL groups registered in the server. "+ + "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.CloudProvider, "cloud-provider", s.CloudProvider, "The provider for cloud services. Empty string for no provider.") fs.StringVar(&s.CloudConfigFile, "cloud-config", s.CloudConfigFile, "The path to the cloud provider configuration file. Empty string for no configuration file.") fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL, "Amount of time to retain events. Default 1 hour.") @@ -272,6 +279,21 @@ func newEtcd(etcdConfigFile string, etcdServerList []string, interfacesFunc meta return etcdStorage, err } +// convert to a map between group and groupVersions. +func generateStorageVersionMap(legacyVersion string, storageVersions string) map[string]string { + storageVersionMap := map[string]string{} + if legacyVersion != "" { + storageVersionMap[""] = legacyVersion + } + if storageVersions != "" { + groupVersions := strings.Split(storageVersions, ",") + for _, gv := range groupVersions { + storageVersionMap[apiutil.GetGroup(gv)] = gv + } + } + return storageVersionMap +} + // Run runs the specified APIServer. This should never exit. func (s *APIServer) Run(_ []string) error { s.verifyClusterIPFlags() @@ -335,41 +357,40 @@ func (s *APIServer) Run(_ []string) error { clientConfig := &client.Config{ Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)), - Version: s.StorageVersion, + Version: s.DeprecatedStorageVersion, } client, err := client.New(clientConfig) if err != nil { glog.Fatalf("Invalid server address: %v", err) } - g, err := latest.Group("") + legacyV1Group, err := latest.Group("") if err != nil { return err } - storageVersions := make(map[string]string) - if s.StorageVersion == "" { - s.StorageVersion = g.Version + + storageVersions := generateStorageVersionMap(s.DeprecatedStorageVersion, s.StorageVersions) + if _, found := storageVersions[legacyV1Group.Group]; !found { + glog.Fatalf("Couldn't find the storage version for group: %q in storageVersions: %v", legacyV1Group.Group, storageVersions) } - etcdStorage, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, g.InterfacesFor, s.StorageVersion, s.EtcdPathPrefix) - storageVersions[""] = s.StorageVersion + etcdStorage, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, legacyV1Group.InterfacesFor, storageVersions[legacyV1Group.Group], s.EtcdPathPrefix) if err != nil { glog.Fatalf("Invalid storage version or misconfigured etcd: %v", err) } var expEtcdStorage storage.Interface if enableExp { - g, err := latest.Group("experimental") + expGroup, err := latest.Group("experimental") if err != nil { glog.Fatalf("experimental API is enabled in runtime config, but not enabled in the environment variable KUBE_API_VERSIONS. Error: %v", err) } - if s.ExpStorageVersion == "" { - s.ExpStorageVersion = g.GroupVersion + if _, found := storageVersions[expGroup.Group]; !found { + glog.Fatalf("Couldn't find the storage version for group: %q in storageVersions: %v", expGroup.Group, storageVersions) } - expEtcdStorage, err = newEtcd(s.EtcdConfigFile, s.EtcdServerList, g.InterfacesFor, s.ExpStorageVersion, s.EtcdPathPrefix) + expEtcdStorage, err = newEtcd(s.EtcdConfigFile, s.EtcdServerList, expGroup.InterfacesFor, storageVersions[expGroup.Group], s.EtcdPathPrefix) if err != nil { glog.Fatalf("Invalid experimental storage version or misconfigured etcd: %v", err) } - storageVersions["experimental"] = s.StorageVersion } n := s.ServiceClusterIPRange diff --git a/cmd/kube-apiserver/app/server_test.go b/cmd/kube-apiserver/app/server_test.go index c6bca513293..6299892620f 100644 --- a/cmd/kube-apiserver/app/server_test.go +++ b/cmd/kube-apiserver/app/server_test.go @@ -17,6 +17,7 @@ limitations under the License. package app import ( + "reflect" "regexp" "testing" ) @@ -61,3 +62,39 @@ func TestLongRunningRequestRegexp(t *testing.T) { } } } + +func TestGenerateStorageVersionMap(t *testing.T) { + testCases := []struct { + legacyVersion string + storageVersions string + expectedMap map[string]string + }{ + { + legacyVersion: "v1", + storageVersions: "v1,experimental/v1alpha1", + expectedMap: map[string]string{ + "": "v1", + "experimental": "experimental/v1alpha1", + }, + }, + { + legacyVersion: "", + storageVersions: "experimental/v1alpha1,v1", + expectedMap: map[string]string{ + "": "v1", + "experimental": "experimental/v1alpha1", + }, + }, + { + legacyVersion: "", + storageVersions: "", + expectedMap: map[string]string{}, + }, + } + for _, test := range testCases { + output := generateStorageVersionMap(test.legacyVersion, test.storageVersions) + if !reflect.DeepEqual(test.expectedMap, output) { + t.Errorf("unexpected error. expect: %v, got: %v", test.expectedMap, output) + } + } +} diff --git a/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt index a2f83ae1d69..93047167c13 100644 --- a/hack/verify-flags/known-flags.txt +++ b/hack/verify-flags/known-flags.txt @@ -268,6 +268,7 @@ ssh-user static-pods-config stats-port storage-version +storage-versions streaming-connection-idle-timeout suicide-timeout sync-frequency diff --git a/pkg/api/latest/latest.go b/pkg/api/latest/latest.go index 6ab3f0b6bae..c7e1cf7cde6 100644 --- a/pkg/api/latest/latest.go +++ b/pkg/api/latest/latest.go @@ -18,6 +18,8 @@ package latest import ( "fmt" + "sort" + "strings" "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/registered" @@ -32,6 +34,9 @@ var ( RegisterGroup = allGroups.RegisterGroup // GroupOrDie is a shortcut to allGroups.GroupOrDie. GroupOrDie = allGroups.GroupOrDie + // AllPreferredGroupVersions returns the preferred versions of all + // registered groups in the form of "group1/version1,group2/version2,..." + AllPreferredGroupVersions = allGroups.AllPreferredGroupVersions ) // GroupMetaMap is a map between group names and their metadata. @@ -76,6 +81,20 @@ func (g GroupMetaMap) GroupOrDie(group string) *GroupMeta { return groupMeta } +// AllPreferredGroupVersions returns the preferred versions of all registered +// groups in the form of "group1/version1,group2/version2,..." +func (g GroupMetaMap) AllPreferredGroupVersions() string { + if len(g) == 0 { + return "" + } + var defaults []string + for _, groupMeta := range g { + defaults = append(defaults, groupMeta.GroupVersion) + } + sort.Strings(defaults) + return strings.Join(defaults, ",") +} + // GroupMeta stores the metadata of a group, such as the latest supported version. type GroupMeta struct { // GroupVersion represents the current external default version of the group. It diff --git a/pkg/api/latest/latest_test.go b/pkg/api/latest/latest_test.go new file mode 100644 index 00000000000..4b3e0c91a54 --- /dev/null +++ b/pkg/api/latest/latest_test.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 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 latest + +import "testing" + +func TestAllPreferredGroupVersions(t *testing.T) { + testCases := []struct { + groupMetaMap GroupMetaMap + expect string + }{ + { + groupMetaMap: GroupMetaMap{ + "group1": &GroupMeta{ + GroupVersion: "group1/v1", + }, + "group2": &GroupMeta{ + GroupVersion: "group2/v2", + }, + "": &GroupMeta{ + GroupVersion: "v1", + }, + }, + expect: "group1/v1,group2/v2,v1", + }, + { + groupMetaMap: GroupMetaMap{ + "": &GroupMeta{ + GroupVersion: "v1", + }, + }, + expect: "v1", + }, + { + groupMetaMap: GroupMetaMap{}, + expect: "", + }, + } + for _, testCase := range testCases { + output := testCase.groupMetaMap.AllPreferredGroupVersions() + if testCase.expect != output { + t.Errorf("Error. expect: %s, got: %s", testCase.expect, output) + } + } +}