diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index e7f459d105..4d89e9de20 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -315,16 +315,19 @@ func Run(s *options.ServerRunOptions) error { sets.NewString("watch", "proxy"), sets.NewString("attach", "exec", "proxy", "log", "portforward"), ) + genericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{ + StorageFactory: storageFactory, + EnableWatchCache: s.Etcd.EnableWatchCache, + EnableGarbageCollection: s.Etcd.EnableGarbageCollection, + DeleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, + } config := &master.Config{ GenericConfig: genericConfig, APIResourceConfigSource: storageFactory.APIResourceConfigSource, StorageFactory: storageFactory, - EnableGarbageCollection: s.Etcd.EnableGarbageCollection, - EnableWatchCache: s.Etcd.EnableWatchCache, EnableCoreControllers: true, - DeleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, EventTTL: s.EventTTL, KubeletClientConfig: s.KubeletConfig, EnableUISupport: true, diff --git a/examples/apiserver/apiserver.go b/examples/apiserver/apiserver.go index 0e30e54d88..28eb576ad5 100644 --- a/examples/apiserver/apiserver.go +++ b/examples/apiserver/apiserver.go @@ -47,7 +47,7 @@ const ( func newStorageFactory() genericapiserver.StorageFactory { config := storagebackend.Config{ - Prefix: genericoptions.DefaultEtcdPathPrefix, + Prefix: kubeoptions.DefaultEtcdPathPrefix, ServerList: []string{"http://127.0.0.1:2379"}, Copier: api.Scheme, } diff --git a/federation/cmd/federation-apiserver/app/BUILD b/federation/cmd/federation-apiserver/app/BUILD index b6037f76f0..3d438db596 100644 --- a/federation/cmd/federation-apiserver/app/BUILD +++ b/federation/cmd/federation-apiserver/app/BUILD @@ -71,7 +71,6 @@ go_library( "//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/registry/generic", - "//vendor:k8s.io/apiserver/pkg/registry/generic/registry", "//vendor:k8s.io/apiserver/pkg/registry/rest", "//vendor:k8s.io/apiserver/pkg/server", "//vendor:k8s.io/apiserver/pkg/server/filters", diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 6049edab71..874d699695 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -36,8 +36,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/registry/generic" - genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/filters" "k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options" @@ -196,6 +194,12 @@ func Run(s *options.ServerRunOptions) error { sets.NewString("watch", "proxy"), sets.NewString("attach", "exec", "proxy", "log", "portforward"), ) + genericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{ + StorageFactory: storageFactory, + EnableWatchCache: s.Etcd.EnableWatchCache, + EnableGarbageCollection: s.Etcd.EnableGarbageCollection, + DeleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, + } // TODO: Move this to generic api server (Need to move the command line flag). if s.Etcd.EnableWatchCache { @@ -211,51 +215,17 @@ func Run(s *options.ServerRunOptions) error { routes.UIRedirect{}.Install(m.HandlerContainer) routes.Logs{}.Install(m.HandlerContainer) - // TODO: Refactor this code to share it with kube-apiserver rather than duplicating it here. - restOptionsFactory := &restOptionsFactory{ - storageFactory: storageFactory, - enableGarbageCollection: s.Etcd.EnableGarbageCollection, - deleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, - } - if s.Etcd.EnableWatchCache { - restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher - } else { - restOptionsFactory.storageDecorator = generic.UndecoratedStorage - } - genericConfig.RESTOptionsGetter = restOptionsFactory - - installFederationAPIs(m, restOptionsFactory) - installCoreAPIs(s, m, restOptionsFactory) - installExtensionsAPIs(m, restOptionsFactory) - installBatchAPIs(m, restOptionsFactory) - installAutoscalingAPIs(m, restOptionsFactory) + installFederationAPIs(m, genericConfig.RESTOptionsGetter) + installCoreAPIs(s, m, genericConfig.RESTOptionsGetter) + installExtensionsAPIs(m, genericConfig.RESTOptionsGetter) + installBatchAPIs(m, genericConfig.RESTOptionsGetter) + installAutoscalingAPIs(m, genericConfig.RESTOptionsGetter) sharedInformers.Start(wait.NeverStop) m.PrepareRun().Run(wait.NeverStop) return nil } -type restOptionsFactory struct { - storageFactory genericapiserver.StorageFactory - storageDecorator generic.StorageDecorator - deleteCollectionWorkers int - enableGarbageCollection bool -} - -func (f *restOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) { - config, err := f.storageFactory.NewConfig(resource) - if err != nil { - return generic.RESTOptions{}, fmt.Errorf("Unable to find storage config for %v, due to %v", resource, err.Error()) - } - return generic.RESTOptions{ - StorageConfig: config, - Decorator: f.storageDecorator, - DeleteCollectionWorkers: f.deleteCollectionWorkers, - EnableGarbageCollection: f.enableGarbageCollection, - ResourcePrefix: f.storageFactory.ResourcePrefix(resource), - }, nil -} - // PostProcessSpec adds removed definitions for backward compatibility func postProcessOpenAPISpecForBackwardCompatibility(s *spec.Swagger) (*spec.Swagger, error) { compatibilityMap := map[string]string{ diff --git a/pkg/kubeapiserver/BUILD b/pkg/kubeapiserver/BUILD index f2fcd34356..f47d431619 100644 --- a/pkg/kubeapiserver/BUILD +++ b/pkg/kubeapiserver/BUILD @@ -13,12 +13,15 @@ go_library( srcs = [ "default_storage_factory_builder.go", "doc.go", + "rest.go", ], tags = ["automanaged"], deps = [ "//pkg/api:go_default_library", "//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime/schema", + "//vendor:k8s.io/apiserver/pkg/registry/generic", + "//vendor:k8s.io/apiserver/pkg/registry/generic/registry", "//vendor:k8s.io/apiserver/pkg/server", "//vendor:k8s.io/apiserver/pkg/storage/storagebackend", "//vendor:k8s.io/apiserver/pkg/util/flag", diff --git a/pkg/kubeapiserver/rest.go b/pkg/kubeapiserver/rest.go new file mode 100644 index 0000000000..c429239010 --- /dev/null +++ b/pkg/kubeapiserver/rest.go @@ -0,0 +1,54 @@ +/* +Copyright 2017 The Kubernetes Authors. + +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 kubeapiserver + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + genericapiserver "k8s.io/apiserver/pkg/server" +) + +// RESTOptionsFactory is a RESTOptionsGetter for kube apiservers since they do complicated stuff +type RESTOptionsFactory struct { + DeleteCollectionWorkers int + EnableGarbageCollection bool + EnableWatchCache bool + StorageFactory genericapiserver.StorageFactory +} + +func (f *RESTOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) { + storageConfig, err := f.StorageFactory.NewConfig(resource) + if err != nil { + return generic.RESTOptions{}, fmt.Errorf("Unable to find storage destination for %v, due to %v", resource, err.Error()) + } + + ret := generic.RESTOptions{ + StorageConfig: storageConfig, + Decorator: generic.UndecoratedStorage, + DeleteCollectionWorkers: f.DeleteCollectionWorkers, + EnableGarbageCollection: f.EnableGarbageCollection, + ResourcePrefix: f.StorageFactory.ResourcePrefix(resource), + } + if f.EnableWatchCache { + ret.Decorator = genericregistry.StorageWithCacher + } + + return ret, nil +} diff --git a/pkg/master/BUILD b/pkg/master/BUILD index b8aa8dcc54..d702f8cb64 100644 --- a/pkg/master/BUILD +++ b/pkg/master/BUILD @@ -75,13 +75,11 @@ go_library( "//vendor:github.com/prometheus/client_golang/prometheus", "//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", - "//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/util/intstr", "//vendor:k8s.io/apimachinery/pkg/util/net", "//vendor:k8s.io/apimachinery/pkg/util/runtime", "//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apiserver/pkg/registry/generic", - "//vendor:k8s.io/apiserver/pkg/registry/generic/registry", "//vendor:k8s.io/apiserver/pkg/server", "//vendor:k8s.io/apiserver/pkg/server/healthz", ], @@ -115,6 +113,7 @@ go_test( "//pkg/client/clientset_generated/clientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/generated/openapi:go_default_library", + "//pkg/kubeapiserver:go_default_library", "//pkg/kubelet/client:go_default_library", "//pkg/version:go_default_library", "//vendor:github.com/go-openapi/loads", diff --git a/pkg/master/master.go b/pkg/master/master.go index 9ebe00d463..c2ed608884 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -25,10 +25,8 @@ import ( "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/registry/generic" - genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/healthz" "k8s.io/kubernetes/cmd/kube-apiserver/app/options" @@ -82,11 +80,8 @@ type Config struct { APIResourceConfigSource genericapiserver.APIResourceConfigSource StorageFactory genericapiserver.StorageFactory - EnableGarbageCollection bool - EnableWatchCache bool EnableCoreControllers bool EndpointReconcilerConfig EndpointReconcilerConfig - DeleteCollectionWorkers int EventTTL time.Duration KubeletClientConfig kubeletclient.KubeletClientConfig @@ -222,18 +217,6 @@ func (c completedConfig) New() (*Master, error) { GenericAPIServer: s, } - restOptionsFactory := &restOptionsFactory{ - deleteCollectionWorkers: c.DeleteCollectionWorkers, - enableGarbageCollection: c.EnableGarbageCollection, - storageFactory: c.StorageFactory, - } - - if c.EnableWatchCache { - restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher - } else { - restOptionsFactory.storageDecorator = generic.UndecoratedStorage - } - // install legacy rest storage if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{ @@ -245,7 +228,7 @@ func (c completedConfig) New() (*Master, error) { ServiceNodePortRange: c.ServiceNodePortRange, LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig, } - m.InstallLegacyAPI(c.Config, restOptionsFactory, legacyRESTStorageProvider) + m.InstallLegacyAPI(c.Config, c.Config.GenericConfig.RESTOptionsGetter, legacyRESTStorageProvider) } restStorageProviders := []RESTStorageProvider{ @@ -260,7 +243,7 @@ func (c completedConfig) New() (*Master, error) { rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorizer}, storagerest.RESTStorageProvider{}, } - m.InstallAPIs(c.Config.APIResourceConfigSource, restOptionsFactory, restStorageProviders...) + m.InstallAPIs(c.Config.APIResourceConfigSource, c.Config.GenericConfig.RESTOptionsGetter, restStorageProviders...) if c.Tunneler != nil { m.installTunneler(c.Tunneler, corev1client.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig).Nodes()) @@ -340,28 +323,6 @@ func (m *Master) InstallAPIs(apiResourceConfigSource genericapiserver.APIResourc } } -type restOptionsFactory struct { - deleteCollectionWorkers int - enableGarbageCollection bool - storageFactory genericapiserver.StorageFactory - storageDecorator generic.StorageDecorator -} - -func (f *restOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) { - storageConfig, err := f.storageFactory.NewConfig(resource) - if err != nil { - return generic.RESTOptions{}, fmt.Errorf("Unable to find storage destination for %v, due to %v", resource, err.Error()) - } - - return generic.RESTOptions{ - StorageConfig: storageConfig, - Decorator: f.storageDecorator, - DeleteCollectionWorkers: f.deleteCollectionWorkers, - EnableGarbageCollection: f.enableGarbageCollection, - ResourcePrefix: f.storageFactory.ResourcePrefix(resource), - }, nil -} - type nodeAddressProvider struct { nodeClient corev1client.NodeInterface } diff --git a/pkg/master/master_test.go b/pkg/master/master_test.go index 1531260326..5f290ff499 100644 --- a/pkg/master/master_test.go +++ b/pkg/master/master_test.go @@ -51,6 +51,7 @@ import ( extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" "k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" + "k8s.io/kubernetes/pkg/kubeapiserver" kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" kubeversion "k8s.io/kubernetes/pkg/version" @@ -87,6 +88,12 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert. config.GenericConfig.RequestContextMapper = genericapirequest.NewRequestContextMapper() config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}} config.GenericConfig.EnableMetrics = true + config.GenericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{ + StorageFactory: storageFactory, + EnableWatchCache: true, + EnableGarbageCollection: true, + DeleteCollectionWorkers: 1, + } config.EnableCoreControllers = false config.KubeletClientConfig = kubeletclient.KubeletClientConfig{Port: 10250} config.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{ diff --git a/test/integration/framework/BUILD b/test/integration/framework/BUILD index de29a4d9a4..7a21c2e41b 100644 --- a/test/integration/framework/BUILD +++ b/test/integration/framework/BUILD @@ -34,6 +34,7 @@ go_library( "//pkg/controller:go_default_library", "//pkg/controller/replication:go_default_library", "//pkg/generated/openapi:go_default_library", + "//pkg/kubeapiserver:go_default_library", "//pkg/kubectl:go_default_library", "//pkg/kubelet/client:go_default_library", "//pkg/master:go_default_library", diff --git a/test/integration/framework/master_utils.go b/test/integration/framework/master_utils.go index a684733b6d..fbe1b6b93b 100644 --- a/test/integration/framework/master_utils.go +++ b/test/integration/framework/master_utils.go @@ -61,6 +61,7 @@ import ( "k8s.io/kubernetes/pkg/controller" replicationcontroller "k8s.io/kubernetes/pkg/controller/replication" "k8s.io/kubernetes/pkg/generated/openapi" + "k8s.io/kubernetes/pkg/kubeapiserver" "k8s.io/kubernetes/pkg/kubectl" kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" "k8s.io/kubernetes/pkg/master" @@ -364,13 +365,18 @@ func NewMasterConfig() *master.Config { genericConfig.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer() genericConfig.AdmissionControl = admit.NewAlwaysAdmit() genericConfig.EnableMetrics = true + genericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{ + StorageFactory: storageFactory, + EnableWatchCache: true, + EnableGarbageCollection: true, + DeleteCollectionWorkers: 1, + } return &master.Config{ GenericConfig: genericConfig, APIResourceConfigSource: master.DefaultAPIResourceConfigSource(), StorageFactory: storageFactory, EnableCoreControllers: true, - EnableWatchCache: true, KubeletClientConfig: kubeletclient.KubeletClientConfig{Port: 10250}, APIServerServicePort: 443, MasterCount: 1, diff --git a/test/integration/garbagecollector/garbage_collector_test.go b/test/integration/garbagecollector/garbage_collector_test.go index 3963ca796b..5d337dddca 100644 --- a/test/integration/garbagecollector/garbage_collector_test.go +++ b/test/integration/garbagecollector/garbage_collector_test.go @@ -122,7 +122,6 @@ func newOwnerRC(name, namespace string) *v1.ReplicationController { func setup(t *testing.T) (*httptest.Server, *garbagecollector.GarbageCollector, clientset.Interface) { masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig.EnableCoreControllers = false - masterConfig.GenericConfig.EnableGarbageCollection = true _, s := framework.RunAMaster(masterConfig) clientSet, err := clientset.NewForConfig(&restclient.Config{Host: s.URL})