Merge pull request #41136 from deads2k/apiserver-10-example

Automatic merge from submit-queue (batch tested with PRs 41121, 40048, 40502, 41136, 40759)

add k8s.io/sample-apiserver to demonstrate how to build an aggregated API server

builds on https://github.com/kubernetes/kubernetes/pull/41093

This creates a sample API server is a separate staging repo to guarantee no cheating with `k8s.io/kubernetes` dependencies.  The sample is run during integration tests (simple tests on it so far) to ensure that it continues to run.

@sttts @kubernetes/sig-api-machinery-misc ptal
@pwittrock @pmorie @kris-nova an aggregated API server example that will stay up to date.
This commit is contained in:
Kubernetes Submit Queue 2017-02-09 14:27:48 -08:00 committed by GitHub
commit 75887829bc
53 changed files with 1571 additions and 223 deletions

View File

@ -68,7 +68,6 @@ go_library(
"//vendor:k8s.io/apiserver/pkg/endpoints/filters", "//vendor:k8s.io/apiserver/pkg/endpoints/filters",
"//vendor:k8s.io/apiserver/pkg/endpoints/handlers/responsewriters", "//vendor:k8s.io/apiserver/pkg/endpoints/handlers/responsewriters",
"//vendor:k8s.io/apiserver/pkg/endpoints/request", "//vendor:k8s.io/apiserver/pkg/endpoints/request",
"//vendor:k8s.io/apiserver/pkg/registry/generic",
"//vendor:k8s.io/apiserver/pkg/registry/generic/rest", "//vendor:k8s.io/apiserver/pkg/registry/generic/rest",
"//vendor:k8s.io/apiserver/pkg/registry/rest", "//vendor:k8s.io/apiserver/pkg/registry/rest",
"//vendor:k8s.io/apiserver/pkg/server", "//vendor:k8s.io/apiserver/pkg/server",

View File

@ -24,7 +24,6 @@ import (
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server" genericapiserver "k8s.io/apiserver/pkg/server"
genericfilters "k8s.io/apiserver/pkg/server/filters" genericfilters "k8s.io/apiserver/pkg/server/filters"
@ -54,9 +53,6 @@ type Config struct {
// this to confirm the proxy's identity // this to confirm the proxy's identity
ProxyClientCert []byte ProxyClientCert []byte
ProxyClientKey []byte ProxyClientKey []byte
// RESTOptionsGetter is used to construct storage for a particular resource
RESTOptionsGetter generic.RESTOptionsGetter
} }
// APIAggregator contains state for a Kubernetes cluster master/api server. // APIAggregator contains state for a Kubernetes cluster master/api server.
@ -144,7 +140,7 @@ func (c completedConfig) New() (*APIAggregator, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apiregistration.GroupName, api.Registry, api.Scheme, api.ParameterCodec, api.Codecs) apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apiregistration.GroupName, api.Registry, api.Scheme, api.ParameterCodec, api.Codecs)
apiGroupInfo.GroupMeta.GroupVersion = v1alpha1.SchemeGroupVersion apiGroupInfo.GroupMeta.GroupVersion = v1alpha1.SchemeGroupVersion
v1alpha1storage := map[string]rest.Storage{} v1alpha1storage := map[string]rest.Storage{}
v1alpha1storage["apiservices"] = apiservicestorage.NewREST(c.RESTOptionsGetter) v1alpha1storage["apiservices"] = apiservicestorage.NewREST(c.GenericConfig.RESTOptionsGetter)
apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage
if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil { if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil {

View File

@ -19,15 +19,11 @@ go_library(
"//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util:go_default_library",
"//vendor:github.com/pborman/uuid", "//vendor:github.com/pborman/uuid",
"//vendor:github.com/spf13/cobra", "//vendor:github.com/spf13/cobra",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/util/sets", "//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apimachinery/pkg/util/wait", "//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",
"//vendor:k8s.io/apiserver/pkg/server/filters", "//vendor:k8s.io/apiserver/pkg/server/filters",
"//vendor:k8s.io/apiserver/pkg/server/options", "//vendor:k8s.io/apiserver/pkg/server/options",
"//vendor:k8s.io/apiserver/pkg/storage/storagebackend",
"//vendor:k8s.io/client-go/rest", "//vendor:k8s.io/client-go/rest",
], ],
) )

View File

@ -24,15 +24,11 @@ import (
"github.com/pborman/uuid" "github.com/pborman/uuid"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/generic/registry"
genericapiserver "k8s.io/apiserver/pkg/server" genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/filters" "k8s.io/apiserver/pkg/server/filters"
genericoptions "k8s.io/apiserver/pkg/server/options" genericoptions "k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/pkg/storage/storagebackend"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/cmd/kube-aggregator/pkg/apiserver" "k8s.io/kubernetes/cmd/kube-aggregator/pkg/apiserver"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
@ -59,14 +55,11 @@ type AggregatorOptions struct {
// NewCommandStartMaster provides a CLI handler for 'start master' command // NewCommandStartMaster provides a CLI handler for 'start master' command
func NewCommandStartAggregator(out, err io.Writer) *cobra.Command { func NewCommandStartAggregator(out, err io.Writer) *cobra.Command {
o := &AggregatorOptions{ o := &AggregatorOptions{
RecommendedOptions: genericoptions.NewRecommendedOptions(api.Scheme), RecommendedOptions: genericoptions.NewRecommendedOptions(defaultEtcdPathPrefix, api.Scheme, api.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion)),
StdOut: out, StdOut: out,
StdErr: err, StdErr: err,
} }
o.RecommendedOptions.Etcd.StorageConfig.Type = storagebackend.StorageTypeETCD3
o.RecommendedOptions.Etcd.StorageConfig.Prefix = defaultEtcdPathPrefix
o.RecommendedOptions.Etcd.StorageConfig.Codec = api.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion)
o.RecommendedOptions.SecureServing.ServingOptions.BindPort = 443 o.RecommendedOptions.SecureServing.ServingOptions.BindPort = 443
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -129,7 +122,6 @@ func (o AggregatorOptions) RunAggregator() error {
config := apiserver.Config{ config := apiserver.Config{
GenericConfig: serverConfig, GenericConfig: serverConfig,
RESTOptionsGetter: &restOptionsFactory{storageConfig: &o.RecommendedOptions.Etcd.StorageConfig},
CoreAPIServerClient: coreAPIServerClient, CoreAPIServerClient: coreAPIServerClient,
} }
@ -150,17 +142,3 @@ func (o AggregatorOptions) RunAggregator() error {
return nil return nil
} }
type restOptionsFactory struct {
storageConfig *storagebackend.Config
}
func (f *restOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) {
return generic.RESTOptions{
StorageConfig: f.storageConfig,
Decorator: registry.StorageWithCacher,
DeleteCollectionWorkers: 1,
EnableGarbageCollection: false,
ResourcePrefix: f.storageConfig.Prefix + "/" + resource.Group + "/" + resource.Resource,
}, nil
}

View File

@ -68,7 +68,7 @@ type ServerRunOptions struct {
func NewServerRunOptions() *ServerRunOptions { func NewServerRunOptions() *ServerRunOptions {
s := ServerRunOptions{ s := ServerRunOptions{
GenericServerRunOptions: genericoptions.NewServerRunOptions(), GenericServerRunOptions: genericoptions.NewServerRunOptions(),
Etcd: genericoptions.NewEtcdOptions(api.Scheme), Etcd: genericoptions.NewEtcdOptions(kubeoptions.DefaultEtcdPathPrefix, api.Scheme, nil),
SecureServing: genericoptions.NewSecureServingOptions(), SecureServing: genericoptions.NewSecureServingOptions(),
InsecureServing: genericoptions.NewInsecureServingOptions(), InsecureServing: genericoptions.NewInsecureServingOptions(),
Audit: genericoptions.NewAuditLogOptions(), Audit: genericoptions.NewAuditLogOptions(),

View File

@ -315,15 +315,19 @@ func Run(s *options.ServerRunOptions) error {
sets.NewString("watch", "proxy"), sets.NewString("watch", "proxy"),
sets.NewString("attach", "exec", "proxy", "log", "portforward"), 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{ config := &master.Config{
GenericConfig: genericConfig, GenericConfig: genericConfig,
APIResourceConfigSource: storageFactory.APIResourceConfigSource, APIResourceConfigSource: storageFactory.APIResourceConfigSource,
StorageFactory: storageFactory, StorageFactory: storageFactory,
EnableWatchCache: s.GenericServerRunOptions.EnableWatchCache,
EnableCoreControllers: true, EnableCoreControllers: true,
DeleteCollectionWorkers: s.GenericServerRunOptions.DeleteCollectionWorkers,
EventTTL: s.EventTTL, EventTTL: s.EventTTL,
KubeletClientConfig: s.KubeletConfig, KubeletClientConfig: s.KubeletConfig,
EnableUISupport: true, EnableUISupport: true,
@ -342,7 +346,7 @@ func Run(s *options.ServerRunOptions) error {
MasterCount: s.MasterCount, MasterCount: s.MasterCount,
} }
if s.GenericServerRunOptions.EnableWatchCache { if s.Etcd.EnableWatchCache {
glog.V(2).Infof("Initializing cache sizes based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB) glog.V(2).Infof("Initializing cache sizes based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB)
cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB) cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB)
cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes) cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes)

View File

@ -47,7 +47,7 @@ const (
func newStorageFactory() genericapiserver.StorageFactory { func newStorageFactory() genericapiserver.StorageFactory {
config := storagebackend.Config{ config := storagebackend.Config{
Prefix: genericoptions.DefaultEtcdPathPrefix, Prefix: kubeoptions.DefaultEtcdPathPrefix,
ServerList: []string{"http://127.0.0.1:2379"}, ServerList: []string{"http://127.0.0.1:2379"},
Copier: api.Scheme, Copier: api.Scheme,
} }
@ -68,7 +68,7 @@ type ServerRunOptions struct {
func NewServerRunOptions() *ServerRunOptions { func NewServerRunOptions() *ServerRunOptions {
s := ServerRunOptions{ s := ServerRunOptions{
GenericServerRunOptions: genericoptions.NewServerRunOptions(), GenericServerRunOptions: genericoptions.NewServerRunOptions(),
Etcd: genericoptions.NewEtcdOptions(api.Scheme), Etcd: genericoptions.NewEtcdOptions(kubeoptions.DefaultEtcdPathPrefix, api.Scheme, nil),
SecureServing: genericoptions.NewSecureServingOptions(), SecureServing: genericoptions.NewSecureServingOptions(),
InsecureServing: genericoptions.NewInsecureServingOptions(), InsecureServing: genericoptions.NewInsecureServingOptions(),
Authentication: kubeoptions.NewBuiltInAuthenticationOptions().WithAll(), Authentication: kubeoptions.NewBuiltInAuthenticationOptions().WithAll(),

View File

@ -71,7 +71,6 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apimachinery/pkg/util/wait",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/apiserver/pkg/registry/generic", "//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/registry/rest",
"//vendor:k8s.io/apiserver/pkg/server", "//vendor:k8s.io/apiserver/pkg/server",
"//vendor:k8s.io/apiserver/pkg/server/filters", "//vendor:k8s.io/apiserver/pkg/server/filters",

View File

@ -51,7 +51,7 @@ type ServerRunOptions struct {
func NewServerRunOptions() *ServerRunOptions { func NewServerRunOptions() *ServerRunOptions {
s := ServerRunOptions{ s := ServerRunOptions{
GenericServerRunOptions: genericoptions.NewServerRunOptions(), GenericServerRunOptions: genericoptions.NewServerRunOptions(),
Etcd: genericoptions.NewEtcdOptions(api.Scheme), Etcd: genericoptions.NewEtcdOptions(kubeoptions.DefaultEtcdPathPrefix, api.Scheme, nil),
SecureServing: genericoptions.NewSecureServingOptions(), SecureServing: genericoptions.NewSecureServingOptions(),
InsecureServing: genericoptions.NewInsecureServingOptions(), InsecureServing: genericoptions.NewInsecureServingOptions(),
Audit: genericoptions.NewAuditLogOptions(), Audit: genericoptions.NewAuditLogOptions(),

View File

@ -36,8 +36,6 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/admission" "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" genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/filters" "k8s.io/apiserver/pkg/server/filters"
"k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options" "k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options"
@ -196,9 +194,15 @@ func Run(s *options.ServerRunOptions) error {
sets.NewString("watch", "proxy"), sets.NewString("watch", "proxy"),
sets.NewString("attach", "exec", "proxy", "log", "portforward"), 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). // TODO: Move this to generic api server (Need to move the command line flag).
if s.GenericServerRunOptions.EnableWatchCache { if s.Etcd.EnableWatchCache {
cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB) cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB)
cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes) cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes)
} }
@ -211,50 +215,17 @@ func Run(s *options.ServerRunOptions) error {
routes.UIRedirect{}.Install(m.HandlerContainer) routes.UIRedirect{}.Install(m.HandlerContainer)
routes.Logs{}.Install(m.HandlerContainer) routes.Logs{}.Install(m.HandlerContainer)
// TODO: Refactor this code to share it with kube-apiserver rather than duplicating it here. installFederationAPIs(m, genericConfig.RESTOptionsGetter)
restOptionsFactory := &restOptionsFactory{ installCoreAPIs(s, m, genericConfig.RESTOptionsGetter)
storageFactory: storageFactory, installExtensionsAPIs(m, genericConfig.RESTOptionsGetter)
enableGarbageCollection: s.Features.EnableGarbageCollection, installBatchAPIs(m, genericConfig.RESTOptionsGetter)
deleteCollectionWorkers: s.GenericServerRunOptions.DeleteCollectionWorkers, installAutoscalingAPIs(m, genericConfig.RESTOptionsGetter)
}
if s.GenericServerRunOptions.EnableWatchCache {
restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher
} else {
restOptionsFactory.storageDecorator = generic.UndecoratedStorage
}
installFederationAPIs(m, restOptionsFactory)
installCoreAPIs(s, m, restOptionsFactory)
installExtensionsAPIs(m, restOptionsFactory)
installBatchAPIs(m, restOptionsFactory)
installAutoscalingAPIs(m, restOptionsFactory)
sharedInformers.Start(wait.NeverStop) sharedInformers.Start(wait.NeverStop)
m.PrepareRun().Run(wait.NeverStop) m.PrepareRun().Run(wait.NeverStop)
return nil 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 // PostProcessSpec adds removed definitions for backward compatibility
func postProcessOpenAPISpecForBackwardCompatibility(s *spec.Swagger) (*spec.Swagger, error) { func postProcessOpenAPISpecForBackwardCompatibility(s *spec.Swagger) (*spec.Swagger, error) {
compatibilityMap := map[string]string{ compatibilityMap := map[string]string{

View File

@ -305,6 +305,8 @@ staging/src/k8s.io/client-go/tools/metrics
staging/src/k8s.io/client-go/util/cert staging/src/k8s.io/client-go/util/cert
staging/src/k8s.io/client-go/util/homedir staging/src/k8s.io/client-go/util/homedir
staging/src/k8s.io/client-go/util/workqueue staging/src/k8s.io/client-go/util/workqueue
staging/src/k8s.io/sample-apiserver
staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/install
test/e2e/perftype test/e2e/perftype
test/e2e_node/runner/local test/e2e_node/runner/local
test/images/clusterapi-tester test/images/clusterapi-tester

View File

@ -47,6 +47,9 @@ pushd "${KUBE_ROOT}" > /dev/null
if [ ! -e "vendor/k8s.io/apimachinery" ]; then if [ ! -e "vendor/k8s.io/apimachinery" ]; then
ln -s ../../staging/src/k8s.io/apimachinery vendor/k8s.io/apimachinery ln -s ../../staging/src/k8s.io/apimachinery vendor/k8s.io/apimachinery
fi fi
if [ ! -e "vendor/k8s.io/sample-apiserver" ]; then
ln -s ../../staging/src/k8s.io/sample-apiserver vendor/k8s.io/sample-apiserver
fi
popd > /dev/null popd > /dev/null
echo "Don't forget to run hack/update-godep-licenses.sh if you added or removed a dependency!" echo "Don't forget to run hack/update-godep-licenses.sh if you added or removed a dependency!"

View File

@ -53,6 +53,7 @@ RC=0
print_forbidden_imports apimachinery k8s.io/ || RC=1 print_forbidden_imports apimachinery k8s.io/ || RC=1
print_forbidden_imports apiserver k8s.io/kubernetes || RC=1 print_forbidden_imports apiserver k8s.io/kubernetes || RC=1
print_forbidden_imports client-go k8s.io/kubernetes k8s.io/apiserver || RC=1 print_forbidden_imports client-go k8s.io/kubernetes k8s.io/apiserver || RC=1
print_forbidden_imports sample-apiserver k8s.io/kubernetes || RC=1
if [ ${RC} != 0 ]; then if [ ${RC} != 0 ]; then
exit ${RC} exit ${RC}
fi fi

View File

@ -13,12 +13,15 @@ go_library(
srcs = [ srcs = [
"default_storage_factory_builder.go", "default_storage_factory_builder.go",
"doc.go", "doc.go",
"rest.go",
], ],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//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/server",
"//vendor:k8s.io/apiserver/pkg/storage/storagebackend", "//vendor:k8s.io/apiserver/pkg/storage/storagebackend",
"//vendor:k8s.io/apiserver/pkg/util/flag", "//vendor:k8s.io/apiserver/pkg/util/flag",

View File

@ -25,6 +25,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
const (
DefaultEtcdPathPrefix = "/registry"
)
// StorageSerializationOptions contains the options for encoding resources. // StorageSerializationOptions contains the options for encoding resources.
type StorageSerializationOptions struct { type StorageSerializationOptions struct {
StorageVersions string StorageVersions string

54
pkg/kubeapiserver/rest.go Normal file
View File

@ -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
}

View File

@ -75,13 +75,11 @@ go_library(
"//vendor:github.com/prometheus/client_golang/prometheus", "//vendor:github.com/prometheus/client_golang/prometheus",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//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/intstr",
"//vendor:k8s.io/apimachinery/pkg/util/net", "//vendor:k8s.io/apimachinery/pkg/util/net",
"//vendor:k8s.io/apimachinery/pkg/util/runtime", "//vendor:k8s.io/apimachinery/pkg/util/runtime",
"//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apimachinery/pkg/util/wait",
"//vendor:k8s.io/apiserver/pkg/registry/generic", "//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",
"//vendor:k8s.io/apiserver/pkg/server/healthz", "//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/clientset/fake:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/generated/openapi:go_default_library", "//pkg/generated/openapi:go_default_library",
"//pkg/kubeapiserver:go_default_library",
"//pkg/kubelet/client:go_default_library", "//pkg/kubelet/client:go_default_library",
"//pkg/version:go_default_library", "//pkg/version:go_default_library",
"//vendor:github.com/go-openapi/loads", "//vendor:github.com/go-openapi/loads",

View File

@ -25,10 +25,8 @@ import (
"time" "time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
utilnet "k8s.io/apimachinery/pkg/util/net" utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
genericapiserver "k8s.io/apiserver/pkg/server" genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/server/healthz"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options" "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
@ -82,10 +80,8 @@ type Config struct {
APIResourceConfigSource genericapiserver.APIResourceConfigSource APIResourceConfigSource genericapiserver.APIResourceConfigSource
StorageFactory genericapiserver.StorageFactory StorageFactory genericapiserver.StorageFactory
EnableWatchCache bool
EnableCoreControllers bool EnableCoreControllers bool
EndpointReconcilerConfig EndpointReconcilerConfig EndpointReconcilerConfig EndpointReconcilerConfig
DeleteCollectionWorkers int
EventTTL time.Duration EventTTL time.Duration
KubeletClientConfig kubeletclient.KubeletClientConfig KubeletClientConfig kubeletclient.KubeletClientConfig
@ -221,18 +217,6 @@ func (c completedConfig) New() (*Master, error) {
GenericAPIServer: s, GenericAPIServer: s,
} }
restOptionsFactory := &restOptionsFactory{
deleteCollectionWorkers: c.DeleteCollectionWorkers,
enableGarbageCollection: c.GenericConfig.EnableGarbageCollection,
storageFactory: c.StorageFactory,
}
if c.EnableWatchCache {
restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher
} else {
restOptionsFactory.storageDecorator = generic.UndecoratedStorage
}
// install legacy rest storage // install legacy rest storage
if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) {
legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{ legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{
@ -244,7 +228,7 @@ func (c completedConfig) New() (*Master, error) {
ServiceNodePortRange: c.ServiceNodePortRange, ServiceNodePortRange: c.ServiceNodePortRange,
LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig, LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig,
} }
m.InstallLegacyAPI(c.Config, restOptionsFactory, legacyRESTStorageProvider) m.InstallLegacyAPI(c.Config, c.Config.GenericConfig.RESTOptionsGetter, legacyRESTStorageProvider)
} }
restStorageProviders := []RESTStorageProvider{ restStorageProviders := []RESTStorageProvider{
@ -259,7 +243,7 @@ func (c completedConfig) New() (*Master, error) {
rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorizer}, rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorizer},
storagerest.RESTStorageProvider{}, storagerest.RESTStorageProvider{},
} }
m.InstallAPIs(c.Config.APIResourceConfigSource, restOptionsFactory, restStorageProviders...) m.InstallAPIs(c.Config.APIResourceConfigSource, c.Config.GenericConfig.RESTOptionsGetter, restStorageProviders...)
if c.Tunneler != nil { if c.Tunneler != nil {
m.installTunneler(c.Tunneler, corev1client.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig).Nodes()) m.installTunneler(c.Tunneler, corev1client.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig).Nodes())
@ -339,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 { type nodeAddressProvider struct {
nodeClient corev1client.NodeInterface nodeClient corev1client.NodeInterface
} }

View File

@ -51,6 +51,7 @@ import (
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
"k8s.io/kubernetes/pkg/kubeapiserver"
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
kubeversion "k8s.io/kubernetes/pkg/version" 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.RequestContextMapper = genericapirequest.NewRequestContextMapper()
config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}} config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}}
config.GenericConfig.EnableMetrics = true config.GenericConfig.EnableMetrics = true
config.GenericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{
StorageFactory: storageFactory,
EnableWatchCache: true,
EnableGarbageCollection: true,
DeleteCollectionWorkers: 1,
}
config.EnableCoreControllers = false config.EnableCoreControllers = false
config.KubeletClientConfig = kubeletclient.KubeletClientConfig{Port: 10250} config.KubeletClientConfig = kubeletclient.KubeletClientConfig{Port: 10250}
config.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{ config.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{

View File

@ -50,6 +50,7 @@ import (
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
apiopenapi "k8s.io/apiserver/pkg/endpoints/openapi" apiopenapi "k8s.io/apiserver/pkg/endpoints/openapi"
apirequest "k8s.io/apiserver/pkg/endpoints/request" apirequest "k8s.io/apiserver/pkg/endpoints/request"
genericregistry "k8s.io/apiserver/pkg/registry/generic"
genericfilters "k8s.io/apiserver/pkg/server/filters" genericfilters "k8s.io/apiserver/pkg/server/filters"
"k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/server/healthz"
"k8s.io/apiserver/pkg/server/mux" "k8s.io/apiserver/pkg/server/mux"
@ -92,7 +93,6 @@ type Config struct {
EnableProfiling bool EnableProfiling bool
// Requires generic profiling enabled // Requires generic profiling enabled
EnableContentionProfiling bool EnableContentionProfiling bool
EnableGarbageCollection bool
EnableMetrics bool EnableMetrics bool
// Version will enable the /version endpoint if non-nil // Version will enable the /version endpoint if non-nil
@ -131,6 +131,8 @@ type Config struct {
OpenAPIConfig *openapicommon.Config OpenAPIConfig *openapicommon.Config
// SwaggerConfig will be used in generating Swagger spec. This is nil by default. Use DefaultSwaggerConfig for "working" defaults. // SwaggerConfig will be used in generating Swagger spec. This is nil by default. Use DefaultSwaggerConfig for "working" defaults.
SwaggerConfig *swagger.Config SwaggerConfig *swagger.Config
// RESTOptionsGetter is used to construct "normal" RESTStorage types
RESTOptionsGetter genericregistry.RESTOptionsGetter
// If specified, requests will be allocated a random timeout between this value, and twice this value. // If specified, requests will be allocated a random timeout between this value, and twice this value.
// Note that it is up to the request handlers to ignore or honor this timeout. In seconds. // Note that it is up to the request handlers to ignore or honor this timeout. In seconds.
@ -196,7 +198,6 @@ func NewConfig() *Config {
LegacyAPIGroupPrefixes: sets.NewString(DefaultLegacyAPIPrefix), LegacyAPIGroupPrefixes: sets.NewString(DefaultLegacyAPIPrefix),
HealthzChecks: []healthz.HealthzChecker{healthz.PingHealthz}, HealthzChecks: []healthz.HealthzChecker{healthz.PingHealthz},
EnableIndex: true, EnableIndex: true,
EnableGarbageCollection: true,
EnableProfiling: true, EnableProfiling: true,
MaxRequestsInFlight: 400, MaxRequestsInFlight: 400,
MaxMutatingRequestsInFlight: 200, MaxMutatingRequestsInFlight: 200,

View File

@ -388,9 +388,10 @@ func NewDefaultAPIGroupInfo(group string, registry *registered.APIRegistrationMa
return APIGroupInfo{ return APIGroupInfo{
GroupMeta: *groupMeta, GroupMeta: *groupMeta,
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{}, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{},
OptionsExternalVersion: &registry.GroupOrDie("").GroupVersion, // TODO unhardcode this. It was hardcoded before, but we need to re-evaluate
Scheme: scheme, OptionsExternalVersion: &schema.GroupVersion{Version: "v1"},
ParameterCodec: parameterCodec, Scheme: scheme,
NegotiatedSerializer: codecs, ParameterCodec: parameterCodec,
NegotiatedSerializer: codecs,
} }
} }

View File

@ -60,7 +60,7 @@ func (s *RequestHeaderAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
// ToAuthenticationRequestHeaderConfig returns a RequestHeaderConfig config object for these options // ToAuthenticationRequestHeaderConfig returns a RequestHeaderConfig config object for these options
// if necessary, nil otherwise. // if necessary, nil otherwise.
func (s *RequestHeaderAuthenticationOptions) ToAuthenticationRequestHeaderConfig() *authenticatorfactory.RequestHeaderConfig { func (s *RequestHeaderAuthenticationOptions) ToAuthenticationRequestHeaderConfig() *authenticatorfactory.RequestHeaderConfig {
if len(s.UsernameHeaders) == 0 { if len(s.UsernameHeaders) == 0 || (len(s.UsernameHeaders) == 1 && len(s.UsernameHeaders[0]) == 0) {
return nil return nil
} }

View File

@ -22,13 +22,13 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/generic/registry"
"k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/storage/storagebackend" "k8s.io/apiserver/pkg/storage/storagebackend"
) )
const (
DefaultEtcdPathPrefix = "/registry"
)
type EtcdOptions struct { type EtcdOptions struct {
StorageConfig storagebackend.Config StorageConfig storagebackend.Config
@ -37,18 +37,25 @@ type EtcdOptions struct {
// To enable protobuf as storage format, it is enough // To enable protobuf as storage format, it is enough
// to set it to "application/vnd.kubernetes.protobuf". // to set it to "application/vnd.kubernetes.protobuf".
DefaultStorageMediaType string DefaultStorageMediaType string
DeleteCollectionWorkers int
EnableGarbageCollection bool
EnableWatchCache bool
} }
func NewEtcdOptions(scheme *runtime.Scheme) *EtcdOptions { func NewEtcdOptions(prefix string, copier runtime.ObjectCopier, codec runtime.Codec) *EtcdOptions {
return &EtcdOptions{ return &EtcdOptions{
StorageConfig: storagebackend.Config{ StorageConfig: storagebackend.Config{
Prefix: DefaultEtcdPathPrefix, Prefix: prefix,
// Default cache size to 0 - if unset, its size will be set based on target // Default cache size to 0 - if unset, its size will be set based on target
// memory usage. // memory usage.
DeserializationCacheSize: 0, DeserializationCacheSize: 0,
Copier: scheme, Copier: copier,
Codec: codec,
}, },
DefaultStorageMediaType: "application/json", DefaultStorageMediaType: "application/json",
DeleteCollectionWorkers: 1,
EnableGarbageCollection: true,
EnableWatchCache: true,
} }
} }
@ -70,6 +77,16 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+ fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+
"The media type to use to store objects in storage. Defaults to application/json. "+ "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.") "Some resources may only support a specific media type and will ignore this setting.")
fs.IntVar(&s.DeleteCollectionWorkers, "delete-collection-workers", s.DeleteCollectionWorkers,
"Number of workers spawned for DeleteCollection call. These are used to speed up namespace cleanup.")
fs.BoolVar(&s.EnableGarbageCollection, "enable-garbage-collector", s.EnableGarbageCollection, ""+
"Enables the generic garbage collector. MUST be synced with the corresponding flag "+
"of the kube-controller-manager.")
// TODO: enable cache in integration tests.
fs.BoolVar(&s.EnableWatchCache, "watch-cache", s.EnableWatchCache,
"Enable watch caching in the apiserver")
fs.StringVar(&s.StorageConfig.Type, "storage-backend", s.StorageConfig.Type, fs.StringVar(&s.StorageConfig.Type, "storage-backend", s.StorageConfig.Type,
"The storage backend for persistence. Options: 'etcd3' (default), 'etcd2'.") "The storage backend for persistence. Options: 'etcd3' (default), 'etcd2'.")
@ -95,3 +112,31 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&s.StorageConfig.Quorum, "etcd-quorum-read", s.StorageConfig.Quorum, fs.BoolVar(&s.StorageConfig.Quorum, "etcd-quorum-read", s.StorageConfig.Quorum,
"If true, enable quorum read.") "If true, enable quorum read.")
} }
func (s *EtcdOptions) ApplyTo(c *server.Config) error {
c.RESTOptionsGetter = &restOptionsFactory{options: s}
return nil
}
// restOptionsFactory is a default implementation of a RESTOptionsGetter
// This will work well for most aggregated API servers. The legacy kube server needs more customization
type restOptionsFactory struct {
options *EtcdOptions
}
func (f *restOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) {
ret := generic.RESTOptions{
StorageConfig: &f.options.StorageConfig,
Decorator: registry.StorageWithCacher,
DeleteCollectionWorkers: f.options.DeleteCollectionWorkers,
EnableGarbageCollection: f.options.EnableGarbageCollection,
ResourcePrefix: f.options.StorageConfig.Prefix + "/" + resource.Group + "/" + resource.Resource,
}
if !f.options.EnableWatchCache {
ret.Decorator = generic.UndecoratedStorage
}
return ret, nil
}

View File

@ -23,7 +23,6 @@ import (
) )
type FeatureOptions struct { type FeatureOptions struct {
EnableGarbageCollection bool
EnableProfiling bool EnableProfiling bool
EnableContentionProfiling bool EnableContentionProfiling bool
EnableSwaggerUI bool EnableSwaggerUI bool
@ -33,7 +32,6 @@ func NewFeatureOptions() *FeatureOptions {
defaults := server.NewConfig() defaults := server.NewConfig()
return &FeatureOptions{ return &FeatureOptions{
EnableGarbageCollection: defaults.EnableGarbageCollection,
EnableProfiling: defaults.EnableProfiling, EnableProfiling: defaults.EnableProfiling,
EnableContentionProfiling: defaults.EnableContentionProfiling, EnableContentionProfiling: defaults.EnableContentionProfiling,
EnableSwaggerUI: defaults.EnableSwaggerUI, EnableSwaggerUI: defaults.EnableSwaggerUI,
@ -41,9 +39,6 @@ func NewFeatureOptions() *FeatureOptions {
} }
func (o *FeatureOptions) AddFlags(fs *pflag.FlagSet) { func (o *FeatureOptions) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&o.EnableGarbageCollection, "enable-garbage-collector", o.EnableGarbageCollection, ""+
"Enables the generic garbage collector. MUST be synced with the corresponding flag "+
"of the kube-controller-manager.")
fs.BoolVar(&o.EnableProfiling, "profiling", o.EnableProfiling, fs.BoolVar(&o.EnableProfiling, "profiling", o.EnableProfiling,
"Enable profiling via web interface host:port/debug/pprof/") "Enable profiling via web interface host:port/debug/pprof/")
fs.BoolVar(&o.EnableContentionProfiling, "contention-profiling", o.EnableContentionProfiling, fs.BoolVar(&o.EnableContentionProfiling, "contention-profiling", o.EnableContentionProfiling,
@ -53,7 +48,6 @@ func (o *FeatureOptions) AddFlags(fs *pflag.FlagSet) {
} }
func (o *FeatureOptions) ApplyTo(c *server.Config) error { func (o *FeatureOptions) ApplyTo(c *server.Config) error {
c.EnableGarbageCollection = o.EnableGarbageCollection
c.EnableProfiling = o.EnableProfiling c.EnableProfiling = o.EnableProfiling
c.EnableContentionProfiling = o.EnableContentionProfiling c.EnableContentionProfiling = o.EnableContentionProfiling
c.EnableSwaggerUI = o.EnableSwaggerUI c.EnableSwaggerUI = o.EnableSwaggerUI

View File

@ -34,9 +34,9 @@ type RecommendedOptions struct {
Features *FeatureOptions Features *FeatureOptions
} }
func NewRecommendedOptions(scheme *runtime.Scheme) *RecommendedOptions { func NewRecommendedOptions(prefix string, copier runtime.ObjectCopier, codec runtime.Codec) *RecommendedOptions {
return &RecommendedOptions{ return &RecommendedOptions{
Etcd: NewEtcdOptions(scheme), Etcd: NewEtcdOptions(prefix, copier, codec),
SecureServing: NewSecureServingOptions(), SecureServing: NewSecureServingOptions(),
Authentication: NewDelegatingAuthenticationOptions(), Authentication: NewDelegatingAuthenticationOptions(),
Authorization: NewDelegatingAuthorizationOptions(), Authorization: NewDelegatingAuthorizationOptions(),
@ -55,6 +55,9 @@ func (o *RecommendedOptions) AddFlags(fs *pflag.FlagSet) {
} }
func (o *RecommendedOptions) ApplyTo(config *server.Config) error { func (o *RecommendedOptions) ApplyTo(config *server.Config) error {
if err := o.Etcd.ApplyTo(config); err != nil {
return err
}
if err := o.SecureServing.ApplyTo(config); err != nil { if err := o.SecureServing.ApplyTo(config); err != nil {
return err return err
} }

View File

@ -39,8 +39,6 @@ type ServerRunOptions struct {
AdvertiseAddress net.IP AdvertiseAddress net.IP
CorsAllowedOriginList []string CorsAllowedOriginList []string
DeleteCollectionWorkers int
EnableWatchCache bool
ExternalHost string ExternalHost string
MaxRequestsInFlight int MaxRequestsInFlight int
MaxMutatingRequestsInFlight int MaxMutatingRequestsInFlight int
@ -54,8 +52,6 @@ func NewServerRunOptions() *ServerRunOptions {
return &ServerRunOptions{ return &ServerRunOptions{
AdmissionControl: "AlwaysAdmit", AdmissionControl: "AlwaysAdmit",
DeleteCollectionWorkers: 1,
EnableWatchCache: true,
MaxRequestsInFlight: defaults.MaxRequestsInFlight, MaxRequestsInFlight: defaults.MaxRequestsInFlight,
MaxMutatingRequestsInFlight: defaults.MaxMutatingRequestsInFlight, MaxMutatingRequestsInFlight: defaults.MaxMutatingRequestsInFlight,
MinRequestTimeout: defaults.MinRequestTimeout, MinRequestTimeout: defaults.MinRequestTimeout,
@ -124,13 +120,6 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
"List of allowed origins for CORS, comma separated. An allowed origin can be a regular "+ "List of allowed origins for CORS, comma separated. An allowed origin can be a regular "+
"expression to support subdomain matching. If this list is empty CORS will not be enabled.") "expression to support subdomain matching. If this list is empty CORS will not be enabled.")
fs.IntVar(&s.DeleteCollectionWorkers, "delete-collection-workers", s.DeleteCollectionWorkers,
"Number of workers spawned for DeleteCollection call. These are used to speed up namespace cleanup.")
// TODO: enable cache in integration tests.
fs.BoolVar(&s.EnableWatchCache, "watch-cache", s.EnableWatchCache,
"Enable watch caching in the apiserver")
fs.IntVar(&s.TargetRAMMB, "target-ram-mb", s.TargetRAMMB, fs.IntVar(&s.TargetRAMMB, "target-ram-mb", s.TargetRAMMB,
"Memory limit for apiserver in MB (used to configure sizes of caches, etc.)") "Memory limit for apiserver in MB (used to configure sizes of caches, etc.)")

View File

@ -0,0 +1,7 @@
apiVersion: serviceinjection.k8s.io/v1alpha1
kind: ServiceInjection
metadata:
name: injector
namespace: kube-system
labels:
sample-label: foo

View File

@ -0,0 +1,17 @@
# 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.
FROM fedora
ADD kube-service-injection /
ENTRYPOINT ["/kube-service-injection"]

View File

@ -0,0 +1,33 @@
apiVersion: v1
kind: Pod
metadata:
name: kube-service-injection
namespace: kube-system
spec:
hostNetwork: true
containers:
- name: kube-service-injection
image: kube-service-injection
imagePullPolicy: Never
args:
- "--secure-port=9443"
- "--authentication-kubeconfig=/all-certs/admin.kubeconfig"
- "--authorization-kubeconfig=/all-certs/admin.kubeconfig"
- "--tls-ca-file=/all-certs/apiserver.crt"
- "--client-ca-file=/all-certs/client-ca.crt"
- "--requestheader-username-headers=X-Remote-User"
- "--requestheader-group-headers=X-Remote-Group"
- "--requestheader-extra-headers-prefix=X-Remote-Extra-"
- "--requestheader-client-ca-file=/all-certs/request-header-ca.crt"
- "--etcd-servers=http://127.0.0.1:2379"
ports:
- containerPort: 9443
hostPort: 9443
volumeMounts:
- name: all-certs
mountPath: /all-certs
readOnly: true
volumes:
- name: all-certs
hostPath:
path: /var/run/kubernetes/

View File

@ -0,0 +1,28 @@
#!/bin/bash
# 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.
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../../..
source "${KUBE_ROOT}/hack/lib/util.sh"
# Register function to be called on EXIT to remove generated binary.
function cleanup {
rm "${KUBE_ROOT}/cmd/kube-sample-apiserver/artifacts/simple-image/kube-sample-apiserver"
}
trap cleanup EXIT
cp -v ${KUBE_ROOT}/_output/local/bin/linux/amd64/kube-sample-apiserver "${KUBE_ROOT}/cmd/kube-sample-apiserver/artifacts/simple-image/kube-sample-apiserver"
docker build -t kube-sample-apiserver:latest ${KUBE_ROOT}/cmd/kube-sample-apiserver/artifacts/simple-image

View File

@ -0,0 +1,69 @@
#!/bin/bash
# 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.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../../..
APIFEDERATOR_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
# Register function to be called on EXIT to remove generated binary.
function cleanup {
rm -f "${CLIENTGEN:-}"
rm -f "${listergen:-}"
rm -f "${informergen:-}"
}
trap cleanup EXIT
echo "Building client-gen"
CLIENTGEN="${PWD}/client-gen-binary"
go build -o "${CLIENTGEN}" ./cmd/libs/go2idl/client-gen
PREFIX=k8s.io/sample-apiserver/pkg/apis
INPUT_BASE="--input-base ${PREFIX}"
INPUT_APIS=(
wardle/
wardle/v1alpha1
)
INPUT="--input ${INPUT_APIS[@]}"
CLIENTSET_PATH="--clientset-path k8s.io/sample-apiserver/pkg/client/clientset_generated"
${CLIENTGEN} ${INPUT_BASE} ${INPUT} ${CLIENTSET_PATH}
${CLIENTGEN} --clientset-name="clientset" ${INPUT_BASE} --input wardle/v1alpha1 ${CLIENTSET_PATH}
echo "Building lister-gen"
listergen="${PWD}/lister-gen"
go build -o "${listergen}" ./cmd/libs/go2idl/lister-gen
LISTER_INPUT="--input-dirs k8s.io/sample-apiserver/pkg/apis/wardle --input-dirs k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
LISTER_PATH="--output-package k8s.io/sample-apiserver/pkg/client/listers"
${listergen} ${LISTER_INPUT} ${LISTER_PATH}
echo "Building informer-gen"
informergen="${PWD}/informer-gen"
go build -o "${informergen}" ./cmd/libs/go2idl/informer-gen
${informergen} \
--input-dirs k8s.io/sample-apiserver/pkg/apis/wardle --input-dirs k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1 \
--versioned-clientset-package k8s.io/sample-apiserver/pkg/client/clientset_generated/clientset \
--internal-clientset-package k8s.io/sample-apiserver/pkg/client/clientset_generated/internalclientset \
--listers-package k8s.io/sample-apiserver/pkg/client/listers \
--output-package k8s.io/sample-apiserver/pkg/client/informers
"$@"

View File

@ -0,0 +1,43 @@
/*
Copyright 2016 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 main
import (
"flag"
"os"
"runtime"
"k8s.io/apimachinery/pkg/util/wait"
// "k8s.io/kubernetes/pkg/util/logs"
"k8s.io/sample-apiserver/pkg/cmd/server"
)
func main() {
// TODO move package and restore
// logs.InitLogs()
// defer logs.FlushLogs()
if len(os.Getenv("GOMAXPROCS")) == 0 {
runtime.GOMAXPROCS(runtime.NumCPU())
}
cmd := server.NewCommandStartWardleServer(os.Stdout, os.Stderr, wait.NeverStop)
cmd.Flags().AddGoFlagSet(flag.CommandLine)
if err := cmd.Execute(); err != nil {
panic(err)
}
}

View File

@ -0,0 +1,21 @@
/*
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.
*/
// +k8s:deepcopy-gen=package,register
// Package api is the internal version of the API.
// +groupName=wardle.k8s.io
package wardle

View File

@ -0,0 +1,44 @@
/*
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 install
import (
"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/sample-apiserver/pkg/apis/wardle"
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
)
// Install registers the API group and adds types to a scheme
func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) {
if err := announced.NewGroupMetaFactory(
&announced.GroupMetaFactoryArgs{
GroupName: wardle.GroupName,
RootScopedKinds: sets.NewString("APIService"),
VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version},
ImportPrefix: "k8s.io/sample-apiserver/pkg/apis/wardle",
AddInternalObjectsToScheme: wardle.AddToScheme,
},
announced.VersionToSchemeFunc{
v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme,
},
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
panic(err)
}
}

View File

@ -0,0 +1,53 @@
/*
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 wardle
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
const GroupName = "wardle.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns back a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Flunder{},
&FlunderList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}

View File

@ -0,0 +1,43 @@
/*
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 wardle
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// FlunderList is a list of Flunder objects.
type FlunderList struct {
metav1.TypeMeta
metav1.ListMeta
Items []Flunder
}
type FlunderSpec struct {
}
type FlunderStatus struct {
}
// +genclient=true
type Flunder struct {
metav1.TypeMeta
metav1.ObjectMeta
Spec FlunderSpec
Status FlunderStatus
}

View File

@ -0,0 +1,22 @@
/*
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.
*/
// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=k8s.io/sample-apiserver/pkg/apis/wardle
// Package v1alpha1 is the v1alpha1 version of the API.
// +groupName=wardle.k8s.io
package v1alpha1

View File

@ -0,0 +1,43 @@
/*
Copyright 2016 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 v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
const GroupName = "wardle.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Flunder{},
&FlunderList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}

View File

@ -0,0 +1,43 @@
/*
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 v1alpha1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// FlunderList is a list of Flunder objects.
type FlunderList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Items []Flunder `json:"items" protobuf:"bytes,2,rep,name=items"`
}
type FlunderSpec struct {
}
type FlunderStatus struct {
}
// +genclient=true
type Flunder struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Spec FlunderSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
Status FlunderStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

View File

@ -0,0 +1,129 @@
// +build !ignore_autogenerated
/*
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.
*/
// This file was autogenerated by conversion-gen. Do not edit it manually!
package v1alpha1
import (
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
wardle "k8s.io/sample-apiserver/pkg/apis/wardle"
unsafe "unsafe"
)
func init() {
SchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1alpha1_Flunder_To_wardle_Flunder,
Convert_wardle_Flunder_To_v1alpha1_Flunder,
Convert_v1alpha1_FlunderList_To_wardle_FlunderList,
Convert_wardle_FlunderList_To_v1alpha1_FlunderList,
Convert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec,
Convert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec,
Convert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus,
Convert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus,
)
}
func autoConvert_v1alpha1_Flunder_To_wardle_Flunder(in *Flunder, out *wardle.Flunder, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_v1alpha1_Flunder_To_wardle_Flunder(in *Flunder, out *wardle.Flunder, s conversion.Scope) error {
return autoConvert_v1alpha1_Flunder_To_wardle_Flunder(in, out, s)
}
func autoConvert_wardle_Flunder_To_v1alpha1_Flunder(in *wardle.Flunder, out *Flunder, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_wardle_Flunder_To_v1alpha1_Flunder(in *wardle.Flunder, out *Flunder, s conversion.Scope) error {
return autoConvert_wardle_Flunder_To_v1alpha1_Flunder(in, out, s)
}
func autoConvert_v1alpha1_FlunderList_To_wardle_FlunderList(in *FlunderList, out *wardle.FlunderList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
out.Items = *(*[]wardle.Flunder)(unsafe.Pointer(&in.Items))
return nil
}
func Convert_v1alpha1_FlunderList_To_wardle_FlunderList(in *FlunderList, out *wardle.FlunderList, s conversion.Scope) error {
return autoConvert_v1alpha1_FlunderList_To_wardle_FlunderList(in, out, s)
}
func autoConvert_wardle_FlunderList_To_v1alpha1_FlunderList(in *wardle.FlunderList, out *FlunderList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
out.Items = *(*[]Flunder)(unsafe.Pointer(&in.Items))
return nil
}
func Convert_wardle_FlunderList_To_v1alpha1_FlunderList(in *wardle.FlunderList, out *FlunderList, s conversion.Scope) error {
return autoConvert_wardle_FlunderList_To_v1alpha1_FlunderList(in, out, s)
}
func autoConvert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec(in *FlunderSpec, out *wardle.FlunderSpec, s conversion.Scope) error {
return nil
}
func Convert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec(in *FlunderSpec, out *wardle.FlunderSpec, s conversion.Scope) error {
return autoConvert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec(in, out, s)
}
func autoConvert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec(in *wardle.FlunderSpec, out *FlunderSpec, s conversion.Scope) error {
return nil
}
func Convert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec(in *wardle.FlunderSpec, out *FlunderSpec, s conversion.Scope) error {
return autoConvert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec(in, out, s)
}
func autoConvert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus(in *FlunderStatus, out *wardle.FlunderStatus, s conversion.Scope) error {
return nil
}
func Convert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus(in *FlunderStatus, out *wardle.FlunderStatus, s conversion.Scope) error {
return autoConvert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus(in, out, s)
}
func autoConvert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus(in *wardle.FlunderStatus, out *FlunderStatus, s conversion.Scope) error {
return nil
}
func Convert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus(in *wardle.FlunderStatus, out *FlunderStatus, s conversion.Scope) error {
return autoConvert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus(in, out, s)
}

View File

@ -0,0 +1,93 @@
// +build !ignore_autogenerated
/*
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.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package v1alpha1
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
reflect "reflect"
)
func init() {
SchemeBuilder.Register(RegisterDeepCopies)
}
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
// to allow building arbitrary schemes.
func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_Flunder, InType: reflect.TypeOf(&Flunder{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_FlunderList, InType: reflect.TypeOf(&FlunderList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_FlunderSpec, InType: reflect.TypeOf(&FlunderSpec{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_FlunderStatus, InType: reflect.TypeOf(&FlunderStatus{})},
)
}
func DeepCopy_v1alpha1_Flunder(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*Flunder)
out := out.(*Flunder)
*out = *in
if newVal, err := c.DeepCopy(&in.ObjectMeta); err != nil {
return err
} else {
out.ObjectMeta = *newVal.(*v1.ObjectMeta)
}
return nil
}
}
func DeepCopy_v1alpha1_FlunderList(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*FlunderList)
out := out.(*FlunderList)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Flunder, len(*in))
for i := range *in {
if err := DeepCopy_v1alpha1_Flunder(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
return nil
}
}
func DeepCopy_v1alpha1_FlunderSpec(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*FlunderSpec)
out := out.(*FlunderSpec)
*out = *in
return nil
}
}
func DeepCopy_v1alpha1_FlunderStatus(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*FlunderStatus)
out := out.(*FlunderStatus)
*out = *in
return nil
}
}

View File

@ -0,0 +1,93 @@
// +build !ignore_autogenerated
/*
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.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
package wardle
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
reflect "reflect"
)
func init() {
SchemeBuilder.Register(RegisterDeepCopies)
}
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
// to allow building arbitrary schemes.
func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_Flunder, InType: reflect.TypeOf(&Flunder{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_FlunderList, InType: reflect.TypeOf(&FlunderList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_FlunderSpec, InType: reflect.TypeOf(&FlunderSpec{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_FlunderStatus, InType: reflect.TypeOf(&FlunderStatus{})},
)
}
func DeepCopy_wardle_Flunder(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*Flunder)
out := out.(*Flunder)
*out = *in
if newVal, err := c.DeepCopy(&in.ObjectMeta); err != nil {
return err
} else {
out.ObjectMeta = *newVal.(*v1.ObjectMeta)
}
return nil
}
}
func DeepCopy_wardle_FlunderList(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*FlunderList)
out := out.(*FlunderList)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Flunder, len(*in))
for i := range *in {
if err := DeepCopy_wardle_Flunder(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
return nil
}
}
func DeepCopy_wardle_FlunderSpec(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*FlunderSpec)
out := out.(*FlunderSpec)
*out = *in
return nil
}
}
func DeepCopy_wardle_FlunderStatus(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*FlunderStatus)
out := out.(*FlunderStatus)
*out = *in
return nil
}
}

View File

@ -0,0 +1,113 @@
/*
Copyright 2016 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 apiserver
import (
"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/version"
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/sample-apiserver/pkg/apis/wardle"
"k8s.io/sample-apiserver/pkg/apis/wardle/install"
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
wardlestorage "k8s.io/sample-apiserver/pkg/registry/wardle"
)
var (
groupFactoryRegistry = make(announced.APIGroupFactoryRegistry)
registry = registered.NewOrDie("")
Scheme = runtime.NewScheme()
Codecs = serializer.NewCodecFactory(Scheme)
)
func init() {
install.Install(groupFactoryRegistry, registry, Scheme)
// we need to add the options to empty v1
// TODO fix the server code to avoid this
metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
// TODO: keep the generic API server from wanting this
unversioned := schema.GroupVersion{Group: "", Version: "v1"}
Scheme.AddUnversionedTypes(unversioned,
&metav1.Status{},
&metav1.APIVersions{},
&metav1.APIGroupList{},
&metav1.APIGroup{},
&metav1.APIResourceList{},
)
}
type Config struct {
GenericConfig *genericapiserver.Config
}
// WardleServer contains state for a Kubernetes cluster master/api server.
type WardleServer struct {
GenericAPIServer *genericapiserver.GenericAPIServer
}
type completedConfig struct {
*Config
}
// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver.
func (c *Config) Complete() completedConfig {
c.GenericConfig.Complete()
c.GenericConfig.Version = &version.Info{
Major: "1",
Minor: "0",
}
return completedConfig{c}
}
// SkipComplete provides a way to construct a server instance without config completion.
func (c *Config) SkipComplete() completedConfig {
return completedConfig{c}
}
// New returns a new instance of WardleServer from the given config.
func (c completedConfig) New() (*WardleServer, error) {
genericServer, err := c.Config.GenericConfig.SkipComplete().New() // completion is done in Complete, no need for a second time
if err != nil {
return nil, err
}
s := &WardleServer{
GenericAPIServer: genericServer,
}
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(wardle.GroupName, registry, Scheme, metav1.ParameterCodec, Codecs)
apiGroupInfo.GroupMeta.GroupVersion = v1alpha1.SchemeGroupVersion
v1alpha1storage := map[string]rest.Storage{}
v1alpha1storage["flunders"] = wardlestorage.NewREST(Scheme, c.GenericConfig.RESTOptionsGetter)
apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage
if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil {
return nil, err
}
return s, nil
}

View File

@ -0,0 +1,124 @@
/*
Copyright 2016 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 server
import (
"fmt"
"io"
"github.com/pborman/uuid"
"github.com/spf13/cobra"
genericapiserver "k8s.io/apiserver/pkg/server"
genericoptions "k8s.io/apiserver/pkg/server/options"
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
"k8s.io/sample-apiserver/pkg/apiserver"
)
const defaultEtcdPathPrefix = "/registry/wardle.kubernetes.io"
type WardleServerOptions struct {
RecommendedOptions *genericoptions.RecommendedOptions
StdOut io.Writer
StdErr io.Writer
}
func NewWardleServerOptions(out, errOut io.Writer) *WardleServerOptions {
o := &WardleServerOptions{
RecommendedOptions: genericoptions.NewRecommendedOptions(defaultEtcdPathPrefix, apiserver.Scheme, apiserver.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion)),
StdOut: out,
StdErr: errOut,
}
o.RecommendedOptions.SecureServing.ServingOptions.BindPort = 443
return o
}
// NewCommandStartMaster provides a CLI handler for 'start master' command
func NewCommandStartWardleServer(out, errOut io.Writer, stopCh <-chan struct{}) *cobra.Command {
o := NewWardleServerOptions(out, errOut)
cmd := &cobra.Command{
Short: "Launch a wardle API server",
Long: "Launch a wardle API server",
RunE: func(c *cobra.Command, args []string) error {
if err := o.Complete(); err != nil {
return err
}
if err := o.Validate(args); err != nil {
return err
}
if err := o.RunWardleServer(stopCh); err != nil {
return err
}
return nil
},
}
flags := cmd.Flags()
o.RecommendedOptions.AddFlags(flags)
return cmd
}
func (o WardleServerOptions) Validate(args []string) error {
return nil
}
func (o *WardleServerOptions) Complete() error {
return nil
}
func (o WardleServerOptions) Config() (*apiserver.Config, error) {
// TODO have a "real" external address
if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost"); err != nil {
return nil, fmt.Errorf("error creating self-signed certificates: %v", err)
}
serverConfig := genericapiserver.NewConfig().WithSerializer(apiserver.Codecs)
if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
return nil, err
}
var err error
privilegedLoopbackToken := uuid.NewRandom().String()
if serverConfig.LoopbackClientConfig, err = serverConfig.SecureServingInfo.NewSelfClientConfig(privilegedLoopbackToken); err != nil {
return nil, err
}
config := &apiserver.Config{
GenericConfig: serverConfig,
}
return config, nil
}
func (o WardleServerOptions) RunWardleServer(stopCh <-chan struct{}) error {
config, err := o.Config()
if err != nil {
return err
}
server, err := config.Complete().New()
if err != nil {
return err
}
server.GenericAPIServer.PrepareRun().Run(stopCh)
return nil
}

View File

@ -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 wardle
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/generic"
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
"k8s.io/sample-apiserver/pkg/apis/wardle"
)
// rest implements a RESTStorage for API services against etcd
type REST struct {
*genericregistry.Store
}
// NewREST returns a RESTStorage object that will work against API services.
func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST {
strategy := NewStrategy(scheme)
store := &genericregistry.Store{
Copier: scheme,
NewFunc: func() runtime.Object { return &wardle.Flunder{} },
NewListFunc: func() runtime.Object { return &wardle.FlunderList{} },
ObjectNameFunc: func(obj runtime.Object) (string, error) {
return obj.(*wardle.Flunder).Name, nil
},
PredicateFunc: MatchFlunder,
QualifiedResource: wardle.Resource("flunders"),
CreateStrategy: strategy,
UpdateStrategy: strategy,
DeleteStrategy: strategy,
}
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: GetAttrs}
if err := store.CompleteWithOptions(options); err != nil {
panic(err) // TODO: Propagate error up
}
return &REST{store}
}

View File

@ -0,0 +1,95 @@
/*
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 wardle
import (
"fmt"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/storage"
"k8s.io/apiserver/pkg/storage/names"
"k8s.io/sample-apiserver/pkg/apis/wardle"
)
type apiServerStrategy struct {
runtime.ObjectTyper
names.NameGenerator
}
func NewStrategy(typer runtime.ObjectTyper) apiServerStrategy {
return apiServerStrategy{typer, names.SimpleNameGenerator}
}
func (apiServerStrategy) NamespaceScoped() bool {
return false
}
func (apiServerStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) {
}
func (apiServerStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) {
}
func (apiServerStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList {
return field.ErrorList{}
// return validation.ValidateFlunder(obj.(*wardle.Flunder))
}
func (apiServerStrategy) AllowCreateOnUpdate() bool {
return false
}
func (apiServerStrategy) AllowUnconditionalUpdate() bool {
return false
}
func (apiServerStrategy) Canonicalize(obj runtime.Object) {
}
func (apiServerStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList {
return field.ErrorList{}
// return validation.ValidateFlunderUpdate(obj.(*wardle.Flunder), old.(*wardle.Flunder))
}
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
apiserver, ok := obj.(*wardle.Flunder)
if !ok {
return nil, nil, fmt.Errorf("given object is not a Flunder.")
}
return labels.Set(apiserver.ObjectMeta.Labels), FlunderToSelectableFields(apiserver), nil
}
// MatchFlunder is the filter used by the generic etcd backend to watch events
// from etcd to clients of the apiserver only interested in specific labels/fields.
func MatchFlunder(label labels.Selector, field fields.Selector) storage.SelectionPredicate {
return storage.SelectionPredicate{
Label: label,
Field: field,
GetAttrs: GetAttrs,
}
}
// FlunderToSelectableFields returns a field set that represents the object.
func FlunderToSelectableFields(obj *wardle.Flunder) fields.Set {
return generic.ObjectMetaFieldsSet(&obj.ObjectMeta, true)
}

View File

@ -12,11 +12,15 @@ go_test(
srcs = ["apiserver_test.go"], srcs = ["apiserver_test.go"],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//cmd/libs/go2idl/client-gen/test_apis/testgroup/v1:go_default_library", "//test/integration/framework:go_default_library",
"//examples/apiserver:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:github.com/stretchr/testify/assert", "//vendor:github.com/stretchr/testify/assert",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/client-go/rest",
"//vendor:k8s.io/client-go/tools/clientcmd",
"//vendor:k8s.io/client-go/tools/clientcmd/api",
"//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1",
"//vendor:k8s.io/sample-apiserver/pkg/cmd/server",
], ],
) )

View File

@ -22,18 +22,25 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os"
"testing" "testing"
"time" "time"
"k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup/v1"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/examples/apiserver" "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/test/integration/framework"
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
"k8s.io/sample-apiserver/pkg/cmd/server"
) )
var groupVersion = v1.SchemeGroupVersion const securePort = "6444"
var groupVersion = v1alpha1.SchemeGroupVersion
var groupVersionForDiscovery = metav1.GroupVersionForDiscovery{ var groupVersionForDiscovery = metav1.GroupVersionForDiscovery{
GroupVersion: groupVersion.String(), GroupVersion: groupVersion.String(),
@ -41,52 +48,85 @@ var groupVersionForDiscovery = metav1.GroupVersionForDiscovery{
} }
func TestRunServer(t *testing.T) { func TestRunServer(t *testing.T) {
serverIP := fmt.Sprintf("http://localhost:%d", apiserver.InsecurePort) masterConfig := framework.NewIntegrationTestMasterConfig()
_, s := framework.RunAMaster(masterConfig)
defer s.Close()
adminKubeConfig := createKubeConfig(masterConfig.GenericConfig.LoopbackClientConfig)
kubeconfigFile, _ := ioutil.TempFile("", "")
defer os.Remove(kubeconfigFile.Name())
clientcmd.WriteToFile(*adminKubeConfig, kubeconfigFile.Name())
stopCh := make(chan struct{}) stopCh := make(chan struct{})
go func() {
if err := apiserver.NewServerRunOptions().Run(stopCh); err != nil {
t.Fatalf("Error in bringing up the server: %v", err)
}
}()
defer close(stopCh) defer close(stopCh)
if err := waitForApiserverUp(serverIP); err != nil { cmd := server.NewCommandStartWardleServer(os.Stdout, os.Stderr, stopCh)
cmd.SetArgs([]string{
"--secure-port", securePort,
"--requestheader-username-headers", "",
"--authentication-kubeconfig", kubeconfigFile.Name(),
"--authorization-kubeconfig", kubeconfigFile.Name(),
"--etcd-servers", framework.GetEtcdURLFromEnv(),
})
go cmd.Execute()
serverLocation := fmt.Sprintf("https://localhost:%s", securePort)
if err := waitForApiserverUp(serverLocation); err != nil {
t.Fatalf("%v", err) t.Fatalf("%v", err)
} }
testSwaggerSpec(t, serverIP)
testAPIGroupList(t, serverIP) testAPIGroupList(t, serverLocation)
testAPIGroup(t, serverIP) testAPIGroup(t, serverLocation)
testAPIResourceList(t, serverIP) testAPIResourceList(t, serverLocation)
} }
func TestRunSecureServer(t *testing.T) { func createKubeConfig(clientCfg *rest.Config) *clientcmdapi.Config {
serverIP := fmt.Sprintf("https://localhost:%d", apiserver.SecurePort) clusterNick := "cluster"
stopCh := make(chan struct{}) userNick := "user"
go func() { contextNick := "context"
options := apiserver.NewServerRunOptions()
options.InsecureServing.BindPort = 0 config := clientcmdapi.NewConfig()
options.SecureServing.ServingOptions.BindPort = apiserver.SecurePort
if err := options.Run(stopCh); err != nil { credentials := clientcmdapi.NewAuthInfo()
t.Fatalf("Error in bringing up the server: %v", err) credentials.Token = clientCfg.BearerToken
} credentials.ClientCertificate = clientCfg.TLSClientConfig.CertFile
}() if len(credentials.ClientCertificate) == 0 {
defer close(stopCh) credentials.ClientCertificateData = clientCfg.TLSClientConfig.CertData
if err := waitForApiserverUp(serverIP); err != nil {
t.Fatalf("%v", err)
} }
testSwaggerSpec(t, serverIP) credentials.ClientKey = clientCfg.TLSClientConfig.KeyFile
testAPIGroupList(t, serverIP) if len(credentials.ClientKey) == 0 {
testAPIGroup(t, serverIP) credentials.ClientKeyData = clientCfg.TLSClientConfig.KeyData
testAPIResourceList(t, serverIP) }
config.AuthInfos[userNick] = credentials
cluster := clientcmdapi.NewCluster()
cluster.Server = clientCfg.Host
cluster.CertificateAuthority = clientCfg.CAFile
if len(cluster.CertificateAuthority) == 0 {
cluster.CertificateAuthorityData = clientCfg.CAData
}
cluster.InsecureSkipTLSVerify = clientCfg.Insecure
if clientCfg.GroupVersion != nil {
cluster.APIVersion = clientCfg.GroupVersion.String()
}
config.Clusters[clusterNick] = cluster
context := clientcmdapi.NewContext()
context.Cluster = clusterNick
context.AuthInfo = userNick
config.Contexts[contextNick] = context
config.CurrentContext = contextNick
return config
} }
func waitForApiserverUp(serverIP string) error { func waitForApiserverUp(serverLocation string) error {
for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(5 * time.Second) { for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(5 * time.Second) {
glog.Errorf("Waiting for : %#v", serverIP) glog.Errorf("Waiting for : %#v", serverLocation)
tr := &http.Transport{ tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
} }
client := &http.Client{Transport: tr} client := &http.Client{Transport: tr}
_, err := client.Get(serverIP) _, err := client.Get(serverLocation)
if err == nil { if err == nil {
return nil return nil
} }
@ -116,65 +156,58 @@ func readResponse(serverURL string) ([]byte, error) {
return contents, nil return contents, nil
} }
func testSwaggerSpec(t *testing.T, serverIP string) { func testAPIGroupList(t *testing.T, serverLocation string) {
serverURL := serverIP + "/swaggerapi" serverURL := serverLocation + "/apis"
_, err := readResponse(serverURL)
if err != nil {
t.Fatalf("%v", err)
}
}
func testAPIGroupList(t *testing.T, serverIP string) {
serverURL := serverIP + "/apis"
contents, err := readResponse(serverURL) contents, err := readResponse(serverURL)
if err != nil { if err != nil {
t.Fatalf("%v", err) t.Fatalf("%v", err)
} }
t.Log(string(contents))
var apiGroupList metav1.APIGroupList var apiGroupList metav1.APIGroupList
err = json.Unmarshal(contents, &apiGroupList) err = json.Unmarshal(contents, &apiGroupList)
if err != nil { if err != nil {
t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err)
} }
assert.Equal(t, 1, len(apiGroupList.Groups)) assert.Equal(t, 1, len(apiGroupList.Groups))
assert.Equal(t, apiGroupList.Groups[0].Name, groupVersion.Group) assert.Equal(t, groupVersion.Group, apiGroupList.Groups[0].Name)
assert.Equal(t, 1, len(apiGroupList.Groups[0].Versions)) assert.Equal(t, 1, len(apiGroupList.Groups[0].Versions))
assert.Equal(t, apiGroupList.Groups[0].Versions[0], groupVersionForDiscovery) assert.Equal(t, groupVersionForDiscovery, apiGroupList.Groups[0].Versions[0])
assert.Equal(t, apiGroupList.Groups[0].PreferredVersion, groupVersionForDiscovery) assert.Equal(t, groupVersionForDiscovery, apiGroupList.Groups[0].PreferredVersion)
} }
func testAPIGroup(t *testing.T, serverIP string) { func testAPIGroup(t *testing.T, serverLocation string) {
serverURL := serverIP + "/apis/testgroup.k8s.io" serverURL := serverLocation + "/apis/wardle.k8s.io"
contents, err := readResponse(serverURL) contents, err := readResponse(serverURL)
if err != nil { if err != nil {
t.Fatalf("%v", err) t.Fatalf("%v", err)
} }
t.Log(string(contents))
var apiGroup metav1.APIGroup var apiGroup metav1.APIGroup
err = json.Unmarshal(contents, &apiGroup) err = json.Unmarshal(contents, &apiGroup)
if err != nil { if err != nil {
t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err)
} }
assert.Equal(t, apiGroup.APIVersion, groupVersion.Version) assert.Equal(t, groupVersion.Group, apiGroup.Name)
assert.Equal(t, apiGroup.Name, groupVersion.Group)
assert.Equal(t, 1, len(apiGroup.Versions)) assert.Equal(t, 1, len(apiGroup.Versions))
assert.Equal(t, apiGroup.Versions[0].GroupVersion, groupVersion.String()) assert.Equal(t, groupVersion.String(), apiGroup.Versions[0].GroupVersion)
assert.Equal(t, apiGroup.Versions[0].Version, groupVersion.Version) assert.Equal(t, groupVersion.Version, apiGroup.Versions[0].Version)
assert.Equal(t, apiGroup.Versions[0], apiGroup.PreferredVersion) assert.Equal(t, apiGroup.PreferredVersion, apiGroup.Versions[0])
} }
func testAPIResourceList(t *testing.T, serverIP string) { func testAPIResourceList(t *testing.T, serverLocation string) {
serverURL := serverIP + "/apis/testgroup.k8s.io/v1" serverURL := serverLocation + "/apis/wardle.k8s.io/v1alpha1"
contents, err := readResponse(serverURL) contents, err := readResponse(serverURL)
if err != nil { if err != nil {
t.Fatalf("%v", err) t.Fatalf("%v", err)
} }
t.Log(string(contents))
var apiResourceList metav1.APIResourceList var apiResourceList metav1.APIResourceList
err = json.Unmarshal(contents, &apiResourceList) err = json.Unmarshal(contents, &apiResourceList)
if err != nil { if err != nil {
t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err)
} }
assert.Equal(t, apiResourceList.APIVersion, groupVersion.Version) assert.Equal(t, groupVersion.String(), apiResourceList.GroupVersion)
assert.Equal(t, apiResourceList.GroupVersion, groupVersion.String())
assert.Equal(t, 1, len(apiResourceList.APIResources)) assert.Equal(t, 1, len(apiResourceList.APIResources))
assert.Equal(t, apiResourceList.APIResources[0].Name, "testtypes") assert.Equal(t, "flunders", apiResourceList.APIResources[0].Name)
assert.True(t, apiResourceList.APIResources[0].Namespaced) assert.True(t, apiResourceList.APIResources[0].Namespaced)
} }

View File

@ -34,6 +34,7 @@ go_library(
"//pkg/controller:go_default_library", "//pkg/controller:go_default_library",
"//pkg/controller/replication:go_default_library", "//pkg/controller/replication:go_default_library",
"//pkg/generated/openapi:go_default_library", "//pkg/generated/openapi:go_default_library",
"//pkg/kubeapiserver:go_default_library",
"//pkg/kubectl:go_default_library", "//pkg/kubectl:go_default_library",
"//pkg/kubelet/client:go_default_library", "//pkg/kubelet/client:go_default_library",
"//pkg/master:go_default_library", "//pkg/master:go_default_library",

View File

@ -61,6 +61,7 @@ import (
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
replicationcontroller "k8s.io/kubernetes/pkg/controller/replication" replicationcontroller "k8s.io/kubernetes/pkg/controller/replication"
"k8s.io/kubernetes/pkg/generated/openapi" "k8s.io/kubernetes/pkg/generated/openapi"
"k8s.io/kubernetes/pkg/kubeapiserver"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
"k8s.io/kubernetes/pkg/master" "k8s.io/kubernetes/pkg/master"
@ -364,13 +365,18 @@ func NewMasterConfig() *master.Config {
genericConfig.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer() genericConfig.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
genericConfig.AdmissionControl = admit.NewAlwaysAdmit() genericConfig.AdmissionControl = admit.NewAlwaysAdmit()
genericConfig.EnableMetrics = true genericConfig.EnableMetrics = true
genericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{
StorageFactory: storageFactory,
EnableWatchCache: true,
EnableGarbageCollection: true,
DeleteCollectionWorkers: 1,
}
return &master.Config{ return &master.Config{
GenericConfig: genericConfig, GenericConfig: genericConfig,
APIResourceConfigSource: master.DefaultAPIResourceConfigSource(), APIResourceConfigSource: master.DefaultAPIResourceConfigSource(),
StorageFactory: storageFactory, StorageFactory: storageFactory,
EnableCoreControllers: true, EnableCoreControllers: true,
EnableWatchCache: true,
KubeletClientConfig: kubeletclient.KubeletClientConfig{Port: 10250}, KubeletClientConfig: kubeletclient.KubeletClientConfig{Port: 10250},
APIServerServicePort: 443, APIServerServicePort: 443,
MasterCount: 1, MasterCount: 1,

View File

@ -122,7 +122,6 @@ func newOwnerRC(name, namespace string) *v1.ReplicationController {
func setup(t *testing.T) (*httptest.Server, *garbagecollector.GarbageCollector, clientset.Interface) { func setup(t *testing.T) (*httptest.Server, *garbagecollector.GarbageCollector, clientset.Interface) {
masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig := framework.NewIntegrationTestMasterConfig()
masterConfig.EnableCoreControllers = false masterConfig.EnableCoreControllers = false
masterConfig.GenericConfig.EnableGarbageCollection = true
_, s := framework.RunAMaster(masterConfig) _, s := framework.RunAMaster(masterConfig)
clientSet, err := clientset.NewForConfig(&restclient.Config{Host: s.URL}) clientSet, err := clientset.NewForConfig(&restclient.Config{Host: s.URL})

126
vendor/BUILD vendored
View File

@ -9098,6 +9098,7 @@ go_library(
"//vendor:k8s.io/apiserver/pkg/endpoints/filters", "//vendor:k8s.io/apiserver/pkg/endpoints/filters",
"//vendor:k8s.io/apiserver/pkg/endpoints/openapi", "//vendor:k8s.io/apiserver/pkg/endpoints/openapi",
"//vendor:k8s.io/apiserver/pkg/endpoints/request", "//vendor:k8s.io/apiserver/pkg/endpoints/request",
"//vendor:k8s.io/apiserver/pkg/registry/generic",
"//vendor:k8s.io/apiserver/pkg/registry/rest", "//vendor:k8s.io/apiserver/pkg/registry/rest",
"//vendor:k8s.io/apiserver/pkg/server/filters", "//vendor:k8s.io/apiserver/pkg/server/filters",
"//vendor:k8s.io/apiserver/pkg/server/healthz", "//vendor:k8s.io/apiserver/pkg/server/healthz",
@ -14106,11 +14107,14 @@ go_library(
"//vendor:gopkg.in/natefinch/lumberjack.v2", "//vendor:gopkg.in/natefinch/lumberjack.v2",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/util/net", "//vendor:k8s.io/apimachinery/pkg/util/net",
"//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/admission",
"//vendor:k8s.io/apiserver/pkg/authentication/authenticatorfactory", "//vendor:k8s.io/apiserver/pkg/authentication/authenticatorfactory",
"//vendor:k8s.io/apiserver/pkg/authorization/authorizerfactory", "//vendor:k8s.io/apiserver/pkg/authorization/authorizerfactory",
"//vendor:k8s.io/apiserver/pkg/features", "//vendor:k8s.io/apiserver/pkg/features",
"//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",
"//vendor:k8s.io/apiserver/pkg/storage/storagebackend", "//vendor:k8s.io/apiserver/pkg/storage/storagebackend",
"//vendor:k8s.io/apiserver/pkg/util/feature", "//vendor:k8s.io/apiserver/pkg/util/feature",
@ -15277,3 +15281,125 @@ go_test(
"//vendor:k8s.io/client-go/util/cert", "//vendor:k8s.io/client-go/util/cert",
], ],
) )
go_binary(
name = "k8s.io/sample-apiserver_bin",
library = ":k8s.io/sample-apiserver",
tags = ["automanaged"],
)
go_library(
name = "k8s.io/sample-apiserver",
srcs = ["k8s.io/sample-apiserver/main.go"],
tags = ["automanaged"],
deps = [
"//vendor:k8s.io/apimachinery/pkg/util/wait",
"//vendor:k8s.io/sample-apiserver/pkg/cmd/server",
],
)
go_library(
name = "k8s.io/sample-apiserver/pkg/apis/wardle",
srcs = [
"k8s.io/sample-apiserver/pkg/apis/wardle/doc.go",
"k8s.io/sample-apiserver/pkg/apis/wardle/register.go",
"k8s.io/sample-apiserver/pkg/apis/wardle/types.go",
"k8s.io/sample-apiserver/pkg/apis/wardle/zz_generated.deepcopy.go",
],
tags = ["automanaged"],
deps = [
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/conversion",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
],
)
go_library(
name = "k8s.io/sample-apiserver/pkg/apis/wardle/install",
srcs = ["k8s.io/sample-apiserver/pkg/apis/wardle/install/install.go"],
tags = ["automanaged"],
deps = [
"//vendor:k8s.io/apimachinery/pkg/apimachinery/announced",
"//vendor:k8s.io/apimachinery/pkg/apimachinery/registered",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/sample-apiserver/pkg/apis/wardle",
"//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1",
],
)
go_library(
name = "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1",
srcs = [
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/doc.go",
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/register.go",
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/types.go",
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.conversion.go",
"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.deepcopy.go",
],
tags = ["automanaged"],
deps = [
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/conversion",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/sample-apiserver/pkg/apis/wardle",
],
)
go_library(
name = "k8s.io/sample-apiserver/pkg/apiserver",
srcs = ["k8s.io/sample-apiserver/pkg/apiserver/apiserver.go"],
tags = ["automanaged"],
deps = [
"//vendor:k8s.io/apimachinery/pkg/apimachinery/announced",
"//vendor:k8s.io/apimachinery/pkg/apimachinery/registered",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer",
"//vendor:k8s.io/apimachinery/pkg/version",
"//vendor:k8s.io/apiserver/pkg/registry/rest",
"//vendor:k8s.io/apiserver/pkg/server",
"//vendor:k8s.io/sample-apiserver/pkg/apis/wardle",
"//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/install",
"//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1",
"//vendor:k8s.io/sample-apiserver/pkg/registry/wardle",
],
)
go_library(
name = "k8s.io/sample-apiserver/pkg/cmd/server",
srcs = ["k8s.io/sample-apiserver/pkg/cmd/server/start.go"],
tags = ["automanaged"],
deps = [
"//vendor:github.com/pborman/uuid",
"//vendor:github.com/spf13/cobra",
"//vendor:k8s.io/apiserver/pkg/server",
"//vendor:k8s.io/apiserver/pkg/server/options",
"//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1",
"//vendor:k8s.io/sample-apiserver/pkg/apiserver",
],
)
go_library(
name = "k8s.io/sample-apiserver/pkg/registry/wardle",
srcs = [
"k8s.io/sample-apiserver/pkg/registry/wardle/etcd.go",
"k8s.io/sample-apiserver/pkg/registry/wardle/strategy.go",
],
tags = ["automanaged"],
deps = [
"//vendor:k8s.io/apimachinery/pkg/fields",
"//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
"//vendor:k8s.io/apiserver/pkg/endpoints/request",
"//vendor:k8s.io/apiserver/pkg/registry/generic",
"//vendor:k8s.io/apiserver/pkg/registry/generic/registry",
"//vendor:k8s.io/apiserver/pkg/storage",
"//vendor:k8s.io/apiserver/pkg/storage/names",
"//vendor:k8s.io/sample-apiserver/pkg/apis/wardle",
],
)

1
vendor/k8s.io/sample-apiserver generated vendored Symbolic link
View File

@ -0,0 +1 @@
../../staging/src/k8s.io/sample-apiserver