From 470cb9d2c90b957a87295888437f74955983af3d Mon Sep 17 00:00:00 2001 From: deads2k Date: Tue, 7 Feb 2017 14:35:02 -0500 Subject: [PATCH 1/3] streamline etcd options for aggregated api server --- cmd/kube-aggregator/pkg/apiserver/BUILD | 1 - .../pkg/apiserver/apiserver.go | 6 +- cmd/kube-aggregator/pkg/cmd/server/BUILD | 4 -- cmd/kube-aggregator/pkg/cmd/server/start.go | 24 +------- cmd/kube-apiserver/app/options/options.go | 2 +- cmd/kube-apiserver/app/server.go | 7 ++- examples/apiserver/apiserver.go | 2 +- .../app/options/options.go | 2 +- .../cmd/federation-apiserver/app/server.go | 9 +-- pkg/kubeapiserver/options/storage_versions.go | 4 ++ pkg/master/master.go | 3 +- .../src/k8s.io/apiserver/pkg/server/config.go | 5 +- .../apiserver/pkg/server/options/etcd.go | 59 ++++++++++++++++--- .../apiserver/pkg/server/options/feature.go | 6 -- .../pkg/server/options/recommended.go | 7 ++- .../pkg/server/options/server_run_options.go | 11 ---- vendor/BUILD | 4 ++ 17 files changed, 84 insertions(+), 72 deletions(-) diff --git a/cmd/kube-aggregator/pkg/apiserver/BUILD b/cmd/kube-aggregator/pkg/apiserver/BUILD index 7a95b81dd13..8f64f55fad0 100644 --- a/cmd/kube-aggregator/pkg/apiserver/BUILD +++ b/cmd/kube-aggregator/pkg/apiserver/BUILD @@ -68,7 +68,6 @@ go_library( "//vendor:k8s.io/apiserver/pkg/endpoints/filters", "//vendor:k8s.io/apiserver/pkg/endpoints/handlers/responsewriters", "//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/rest", "//vendor:k8s.io/apiserver/pkg/server", diff --git a/cmd/kube-aggregator/pkg/apiserver/apiserver.go b/cmd/kube-aggregator/pkg/apiserver/apiserver.go index b5e0f4cf8d8..8311ab7040a 100644 --- a/cmd/kube-aggregator/pkg/apiserver/apiserver.go +++ b/cmd/kube-aggregator/pkg/apiserver/apiserver.go @@ -24,7 +24,6 @@ import ( "k8s.io/apimachinery/pkg/util/wait" genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" genericfilters "k8s.io/apiserver/pkg/server/filters" @@ -54,9 +53,6 @@ type Config struct { // this to confirm the proxy's identity ProxyClientCert []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. @@ -144,7 +140,7 @@ func (c completedConfig) New() (*APIAggregator, error) { apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apiregistration.GroupName, api.Registry, api.Scheme, api.ParameterCodec, api.Codecs) apiGroupInfo.GroupMeta.GroupVersion = v1alpha1.SchemeGroupVersion v1alpha1storage := map[string]rest.Storage{} - v1alpha1storage["apiservices"] = apiservicestorage.NewREST(c.RESTOptionsGetter) + v1alpha1storage["apiservices"] = apiservicestorage.NewREST(c.GenericConfig.RESTOptionsGetter) apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil { diff --git a/cmd/kube-aggregator/pkg/cmd/server/BUILD b/cmd/kube-aggregator/pkg/cmd/server/BUILD index 2fe46e62392..f2aacefa604 100644 --- a/cmd/kube-aggregator/pkg/cmd/server/BUILD +++ b/cmd/kube-aggregator/pkg/cmd/server/BUILD @@ -19,15 +19,11 @@ go_library( "//pkg/kubectl/cmd/util:go_default_library", "//vendor:github.com/pborman/uuid", "//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/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/filters", "//vendor:k8s.io/apiserver/pkg/server/options", - "//vendor:k8s.io/apiserver/pkg/storage/storagebackend", "//vendor:k8s.io/client-go/rest", ], ) diff --git a/cmd/kube-aggregator/pkg/cmd/server/start.go b/cmd/kube-aggregator/pkg/cmd/server/start.go index 2377c7bfe4b..095f99c0711 100644 --- a/cmd/kube-aggregator/pkg/cmd/server/start.go +++ b/cmd/kube-aggregator/pkg/cmd/server/start.go @@ -24,15 +24,11 @@ import ( "github.com/pborman/uuid" "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" "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" "k8s.io/apiserver/pkg/server/filters" genericoptions "k8s.io/apiserver/pkg/server/options" - "k8s.io/apiserver/pkg/storage/storagebackend" restclient "k8s.io/client-go/rest" "k8s.io/kubernetes/cmd/kube-aggregator/pkg/apiserver" "k8s.io/kubernetes/pkg/api" @@ -59,14 +55,11 @@ type AggregatorOptions struct { // NewCommandStartMaster provides a CLI handler for 'start master' command func NewCommandStartAggregator(out, err io.Writer) *cobra.Command { o := &AggregatorOptions{ - RecommendedOptions: genericoptions.NewRecommendedOptions(api.Scheme), + RecommendedOptions: genericoptions.NewRecommendedOptions(defaultEtcdPathPrefix, api.Scheme, api.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion)), StdOut: out, 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 cmd := &cobra.Command{ @@ -129,7 +122,6 @@ func (o AggregatorOptions) RunAggregator() error { config := apiserver.Config{ GenericConfig: serverConfig, - RESTOptionsGetter: &restOptionsFactory{storageConfig: &o.RecommendedOptions.Etcd.StorageConfig}, CoreAPIServerClient: coreAPIServerClient, } @@ -150,17 +142,3 @@ func (o AggregatorOptions) RunAggregator() error { 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 -} diff --git a/cmd/kube-apiserver/app/options/options.go b/cmd/kube-apiserver/app/options/options.go index 96d661c83b3..a6b90a3592d 100644 --- a/cmd/kube-apiserver/app/options/options.go +++ b/cmd/kube-apiserver/app/options/options.go @@ -68,7 +68,7 @@ type ServerRunOptions struct { func NewServerRunOptions() *ServerRunOptions { s := ServerRunOptions{ GenericServerRunOptions: genericoptions.NewServerRunOptions(), - Etcd: genericoptions.NewEtcdOptions(api.Scheme), + Etcd: genericoptions.NewEtcdOptions(kubeoptions.DefaultEtcdPathPrefix, api.Scheme, nil), SecureServing: genericoptions.NewSecureServingOptions(), InsecureServing: genericoptions.NewInsecureServingOptions(), Audit: genericoptions.NewAuditLogOptions(), diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 40b39768320..e7f459d1058 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -321,9 +321,10 @@ func Run(s *options.ServerRunOptions) error { APIResourceConfigSource: storageFactory.APIResourceConfigSource, StorageFactory: storageFactory, - EnableWatchCache: s.GenericServerRunOptions.EnableWatchCache, + EnableGarbageCollection: s.Etcd.EnableGarbageCollection, + EnableWatchCache: s.Etcd.EnableWatchCache, EnableCoreControllers: true, - DeleteCollectionWorkers: s.GenericServerRunOptions.DeleteCollectionWorkers, + DeleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, EventTTL: s.EventTTL, KubeletClientConfig: s.KubeletConfig, EnableUISupport: true, @@ -342,7 +343,7 @@ func Run(s *options.ServerRunOptions) error { 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) cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB) cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes) diff --git a/examples/apiserver/apiserver.go b/examples/apiserver/apiserver.go index 037d6d13dbd..0e30e54d887 100644 --- a/examples/apiserver/apiserver.go +++ b/examples/apiserver/apiserver.go @@ -68,7 +68,7 @@ type ServerRunOptions struct { func NewServerRunOptions() *ServerRunOptions { s := ServerRunOptions{ GenericServerRunOptions: genericoptions.NewServerRunOptions(), - Etcd: genericoptions.NewEtcdOptions(api.Scheme), + Etcd: genericoptions.NewEtcdOptions(kubeoptions.DefaultEtcdPathPrefix, api.Scheme, nil), SecureServing: genericoptions.NewSecureServingOptions(), InsecureServing: genericoptions.NewInsecureServingOptions(), Authentication: kubeoptions.NewBuiltInAuthenticationOptions().WithAll(), diff --git a/federation/cmd/federation-apiserver/app/options/options.go b/federation/cmd/federation-apiserver/app/options/options.go index 253fa0b0274..e4d5e1db103 100644 --- a/federation/cmd/federation-apiserver/app/options/options.go +++ b/federation/cmd/federation-apiserver/app/options/options.go @@ -51,7 +51,7 @@ type ServerRunOptions struct { func NewServerRunOptions() *ServerRunOptions { s := ServerRunOptions{ GenericServerRunOptions: genericoptions.NewServerRunOptions(), - Etcd: genericoptions.NewEtcdOptions(api.Scheme), + Etcd: genericoptions.NewEtcdOptions(kubeoptions.DefaultEtcdPathPrefix, api.Scheme, nil), SecureServing: genericoptions.NewSecureServingOptions(), InsecureServing: genericoptions.NewInsecureServingOptions(), Audit: genericoptions.NewAuditLogOptions(), diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 1fb92fa85f2..6049edab71f 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -198,7 +198,7 @@ func Run(s *options.ServerRunOptions) error { ) // 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.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes) } @@ -214,14 +214,15 @@ func Run(s *options.ServerRunOptions) error { // TODO: Refactor this code to share it with kube-apiserver rather than duplicating it here. restOptionsFactory := &restOptionsFactory{ storageFactory: storageFactory, - enableGarbageCollection: s.Features.EnableGarbageCollection, - deleteCollectionWorkers: s.GenericServerRunOptions.DeleteCollectionWorkers, + enableGarbageCollection: s.Etcd.EnableGarbageCollection, + deleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, } - if s.GenericServerRunOptions.EnableWatchCache { + if s.Etcd.EnableWatchCache { restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher } else { restOptionsFactory.storageDecorator = generic.UndecoratedStorage } + genericConfig.RESTOptionsGetter = restOptionsFactory installFederationAPIs(m, restOptionsFactory) installCoreAPIs(s, m, restOptionsFactory) diff --git a/pkg/kubeapiserver/options/storage_versions.go b/pkg/kubeapiserver/options/storage_versions.go index 3e72aee6f71..d466900431a 100644 --- a/pkg/kubeapiserver/options/storage_versions.go +++ b/pkg/kubeapiserver/options/storage_versions.go @@ -25,6 +25,10 @@ import ( "github.com/spf13/pflag" ) +const ( + DefaultEtcdPathPrefix = "/registry" +) + // StorageSerializationOptions contains the options for encoding resources. type StorageSerializationOptions struct { StorageVersions string diff --git a/pkg/master/master.go b/pkg/master/master.go index 697639ccd55..9ebe00d463a 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -82,6 +82,7 @@ type Config struct { APIResourceConfigSource genericapiserver.APIResourceConfigSource StorageFactory genericapiserver.StorageFactory + EnableGarbageCollection bool EnableWatchCache bool EnableCoreControllers bool EndpointReconcilerConfig EndpointReconcilerConfig @@ -223,7 +224,7 @@ func (c completedConfig) New() (*Master, error) { restOptionsFactory := &restOptionsFactory{ deleteCollectionWorkers: c.DeleteCollectionWorkers, - enableGarbageCollection: c.GenericConfig.EnableGarbageCollection, + enableGarbageCollection: c.EnableGarbageCollection, storageFactory: c.StorageFactory, } diff --git a/staging/src/k8s.io/apiserver/pkg/server/config.go b/staging/src/k8s.io/apiserver/pkg/server/config.go index 71a3147ea9f..e9e2a0786b6 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/config.go @@ -50,6 +50,7 @@ import ( genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" apiopenapi "k8s.io/apiserver/pkg/endpoints/openapi" apirequest "k8s.io/apiserver/pkg/endpoints/request" + genericregistry "k8s.io/apiserver/pkg/registry/generic" genericfilters "k8s.io/apiserver/pkg/server/filters" "k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/server/mux" @@ -92,7 +93,6 @@ type Config struct { EnableProfiling bool // Requires generic profiling enabled EnableContentionProfiling bool - EnableGarbageCollection bool EnableMetrics bool // Version will enable the /version endpoint if non-nil @@ -131,6 +131,8 @@ type Config struct { OpenAPIConfig *openapicommon.Config // SwaggerConfig will be used in generating Swagger spec. This is nil by default. Use DefaultSwaggerConfig for "working" defaults. 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. // 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), HealthzChecks: []healthz.HealthzChecker{healthz.PingHealthz}, EnableIndex: true, - EnableGarbageCollection: true, EnableProfiling: true, MaxRequestsInFlight: 400, MaxMutatingRequestsInFlight: 200, diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/etcd.go b/staging/src/k8s.io/apiserver/pkg/server/options/etcd.go index 3a612aed1a0..4a8ad9edc78 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/etcd.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/etcd.go @@ -22,13 +22,13 @@ import ( "github.com/spf13/pflag" "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" ) -const ( - DefaultEtcdPathPrefix = "/registry" -) - type EtcdOptions struct { StorageConfig storagebackend.Config @@ -37,18 +37,25 @@ type EtcdOptions struct { // To enable protobuf as storage format, it is enough // to set it to "application/vnd.kubernetes.protobuf". 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{ StorageConfig: storagebackend.Config{ - Prefix: DefaultEtcdPathPrefix, + Prefix: prefix, // Default cache size to 0 - if unset, its size will be set based on target // memory usage. DeserializationCacheSize: 0, - Copier: scheme, + Copier: copier, + Codec: codec, }, 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, ""+ "The media type to use to store objects in storage. Defaults to application/json. "+ "Some resources may only support a specific media type and will ignore this setting.") + fs.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, "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, "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 +} diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/feature.go b/staging/src/k8s.io/apiserver/pkg/server/options/feature.go index ef2b8c00a72..d67f2ba365f 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/feature.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/feature.go @@ -23,7 +23,6 @@ import ( ) type FeatureOptions struct { - EnableGarbageCollection bool EnableProfiling bool EnableContentionProfiling bool EnableSwaggerUI bool @@ -33,7 +32,6 @@ func NewFeatureOptions() *FeatureOptions { defaults := server.NewConfig() return &FeatureOptions{ - EnableGarbageCollection: defaults.EnableGarbageCollection, EnableProfiling: defaults.EnableProfiling, EnableContentionProfiling: defaults.EnableContentionProfiling, EnableSwaggerUI: defaults.EnableSwaggerUI, @@ -41,9 +39,6 @@ func NewFeatureOptions() *FeatureOptions { } 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, "Enable profiling via web interface host:port/debug/pprof/") 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 { - c.EnableGarbageCollection = o.EnableGarbageCollection c.EnableProfiling = o.EnableProfiling c.EnableContentionProfiling = o.EnableContentionProfiling c.EnableSwaggerUI = o.EnableSwaggerUI diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go b/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go index fde701fdf11..bc75edf8454 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go @@ -34,9 +34,9 @@ type RecommendedOptions struct { Features *FeatureOptions } -func NewRecommendedOptions(scheme *runtime.Scheme) *RecommendedOptions { +func NewRecommendedOptions(prefix string, copier runtime.ObjectCopier, codec runtime.Codec) *RecommendedOptions { return &RecommendedOptions{ - Etcd: NewEtcdOptions(scheme), + Etcd: NewEtcdOptions(prefix, copier, codec), SecureServing: NewSecureServingOptions(), Authentication: NewDelegatingAuthenticationOptions(), Authorization: NewDelegatingAuthorizationOptions(), @@ -55,6 +55,9 @@ func (o *RecommendedOptions) AddFlags(fs *pflag.FlagSet) { } 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 { return err } diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/server_run_options.go b/staging/src/k8s.io/apiserver/pkg/server/options/server_run_options.go index 937c9606aa0..a3733d49b4e 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/server_run_options.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/server_run_options.go @@ -39,8 +39,6 @@ type ServerRunOptions struct { AdvertiseAddress net.IP CorsAllowedOriginList []string - DeleteCollectionWorkers int - EnableWatchCache bool ExternalHost string MaxRequestsInFlight int MaxMutatingRequestsInFlight int @@ -54,8 +52,6 @@ func NewServerRunOptions() *ServerRunOptions { return &ServerRunOptions{ AdmissionControl: "AlwaysAdmit", - DeleteCollectionWorkers: 1, - EnableWatchCache: true, MaxRequestsInFlight: defaults.MaxRequestsInFlight, MaxMutatingRequestsInFlight: defaults.MaxMutatingRequestsInFlight, 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 "+ "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, "Memory limit for apiserver in MB (used to configure sizes of caches, etc.)") diff --git a/vendor/BUILD b/vendor/BUILD index a091d671e86..dd3fd45ca3c 100644 --- a/vendor/BUILD +++ b/vendor/BUILD @@ -9098,6 +9098,7 @@ go_library( "//vendor:k8s.io/apiserver/pkg/endpoints/filters", "//vendor:k8s.io/apiserver/pkg/endpoints/openapi", "//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/server/filters", "//vendor:k8s.io/apiserver/pkg/server/healthz", @@ -14106,11 +14107,14 @@ go_library( "//vendor:gopkg.in/natefinch/lumberjack.v2", "//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/util/net", "//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/authentication/authenticatorfactory", "//vendor:k8s.io/apiserver/pkg/authorization/authorizerfactory", "//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/storage/storagebackend", "//vendor:k8s.io/apiserver/pkg/util/feature", From a463540d47f16f14899b2ec60779f420df9368f4 Mon Sep 17 00:00:00 2001 From: deads2k Date: Tue, 7 Feb 2017 14:52:50 -0500 Subject: [PATCH 2/3] remove duplication of RESTOptionsGetter for kube --- cmd/kube-apiserver/app/server.go | 9 ++-- examples/apiserver/apiserver.go | 2 +- federation/cmd/federation-apiserver/app/BUILD | 1 - .../cmd/federation-apiserver/app/server.go | 52 ++++-------------- pkg/kubeapiserver/BUILD | 3 ++ pkg/kubeapiserver/rest.go | 54 +++++++++++++++++++ pkg/master/BUILD | 3 +- pkg/master/master.go | 43 +-------------- pkg/master/master_test.go | 7 +++ test/integration/framework/BUILD | 1 + test/integration/framework/master_utils.go | 8 ++- .../garbage_collector_test.go | 1 - 12 files changed, 93 insertions(+), 91 deletions(-) create mode 100644 pkg/kubeapiserver/rest.go diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index e7f459d1058..4d89e9de201 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -315,16 +315,19 @@ func Run(s *options.ServerRunOptions) error { sets.NewString("watch", "proxy"), sets.NewString("attach", "exec", "proxy", "log", "portforward"), ) + genericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{ + StorageFactory: storageFactory, + EnableWatchCache: s.Etcd.EnableWatchCache, + EnableGarbageCollection: s.Etcd.EnableGarbageCollection, + DeleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, + } config := &master.Config{ GenericConfig: genericConfig, APIResourceConfigSource: storageFactory.APIResourceConfigSource, StorageFactory: storageFactory, - EnableGarbageCollection: s.Etcd.EnableGarbageCollection, - EnableWatchCache: s.Etcd.EnableWatchCache, EnableCoreControllers: true, - DeleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, EventTTL: s.EventTTL, KubeletClientConfig: s.KubeletConfig, EnableUISupport: true, diff --git a/examples/apiserver/apiserver.go b/examples/apiserver/apiserver.go index 0e30e54d887..28eb576ad57 100644 --- a/examples/apiserver/apiserver.go +++ b/examples/apiserver/apiserver.go @@ -47,7 +47,7 @@ const ( func newStorageFactory() genericapiserver.StorageFactory { config := storagebackend.Config{ - Prefix: genericoptions.DefaultEtcdPathPrefix, + Prefix: kubeoptions.DefaultEtcdPathPrefix, ServerList: []string{"http://127.0.0.1:2379"}, Copier: api.Scheme, } diff --git a/federation/cmd/federation-apiserver/app/BUILD b/federation/cmd/federation-apiserver/app/BUILD index b6037f76f03..3d438db596f 100644 --- a/federation/cmd/federation-apiserver/app/BUILD +++ b/federation/cmd/federation-apiserver/app/BUILD @@ -71,7 +71,6 @@ go_library( "//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apiserver/pkg/admission", "//vendor:k8s.io/apiserver/pkg/registry/generic", - "//vendor:k8s.io/apiserver/pkg/registry/generic/registry", "//vendor:k8s.io/apiserver/pkg/registry/rest", "//vendor:k8s.io/apiserver/pkg/server", "//vendor:k8s.io/apiserver/pkg/server/filters", diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 6049edab71f..874d6996956 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -36,8 +36,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/registry/generic" - genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/filters" "k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options" @@ -196,6 +194,12 @@ func Run(s *options.ServerRunOptions) error { sets.NewString("watch", "proxy"), sets.NewString("attach", "exec", "proxy", "log", "portforward"), ) + genericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{ + StorageFactory: storageFactory, + EnableWatchCache: s.Etcd.EnableWatchCache, + EnableGarbageCollection: s.Etcd.EnableGarbageCollection, + DeleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, + } // TODO: Move this to generic api server (Need to move the command line flag). if s.Etcd.EnableWatchCache { @@ -211,51 +215,17 @@ func Run(s *options.ServerRunOptions) error { routes.UIRedirect{}.Install(m.HandlerContainer) routes.Logs{}.Install(m.HandlerContainer) - // TODO: Refactor this code to share it with kube-apiserver rather than duplicating it here. - restOptionsFactory := &restOptionsFactory{ - storageFactory: storageFactory, - enableGarbageCollection: s.Etcd.EnableGarbageCollection, - deleteCollectionWorkers: s.Etcd.DeleteCollectionWorkers, - } - if s.Etcd.EnableWatchCache { - restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher - } else { - restOptionsFactory.storageDecorator = generic.UndecoratedStorage - } - genericConfig.RESTOptionsGetter = restOptionsFactory - - installFederationAPIs(m, restOptionsFactory) - installCoreAPIs(s, m, restOptionsFactory) - installExtensionsAPIs(m, restOptionsFactory) - installBatchAPIs(m, restOptionsFactory) - installAutoscalingAPIs(m, restOptionsFactory) + installFederationAPIs(m, genericConfig.RESTOptionsGetter) + installCoreAPIs(s, m, genericConfig.RESTOptionsGetter) + installExtensionsAPIs(m, genericConfig.RESTOptionsGetter) + installBatchAPIs(m, genericConfig.RESTOptionsGetter) + installAutoscalingAPIs(m, genericConfig.RESTOptionsGetter) sharedInformers.Start(wait.NeverStop) m.PrepareRun().Run(wait.NeverStop) return nil } -type restOptionsFactory struct { - storageFactory genericapiserver.StorageFactory - storageDecorator generic.StorageDecorator - deleteCollectionWorkers int - enableGarbageCollection bool -} - -func (f *restOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) { - config, err := f.storageFactory.NewConfig(resource) - if err != nil { - return generic.RESTOptions{}, fmt.Errorf("Unable to find storage config for %v, due to %v", resource, err.Error()) - } - return generic.RESTOptions{ - StorageConfig: config, - Decorator: f.storageDecorator, - DeleteCollectionWorkers: f.deleteCollectionWorkers, - EnableGarbageCollection: f.enableGarbageCollection, - ResourcePrefix: f.storageFactory.ResourcePrefix(resource), - }, nil -} - // PostProcessSpec adds removed definitions for backward compatibility func postProcessOpenAPISpecForBackwardCompatibility(s *spec.Swagger) (*spec.Swagger, error) { compatibilityMap := map[string]string{ diff --git a/pkg/kubeapiserver/BUILD b/pkg/kubeapiserver/BUILD index f2fcd34356d..f47d431619e 100644 --- a/pkg/kubeapiserver/BUILD +++ b/pkg/kubeapiserver/BUILD @@ -13,12 +13,15 @@ go_library( srcs = [ "default_storage_factory_builder.go", "doc.go", + "rest.go", ], tags = ["automanaged"], deps = [ "//pkg/api:go_default_library", "//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime/schema", + "//vendor:k8s.io/apiserver/pkg/registry/generic", + "//vendor:k8s.io/apiserver/pkg/registry/generic/registry", "//vendor:k8s.io/apiserver/pkg/server", "//vendor:k8s.io/apiserver/pkg/storage/storagebackend", "//vendor:k8s.io/apiserver/pkg/util/flag", diff --git a/pkg/kubeapiserver/rest.go b/pkg/kubeapiserver/rest.go new file mode 100644 index 00000000000..c4292390107 --- /dev/null +++ b/pkg/kubeapiserver/rest.go @@ -0,0 +1,54 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kubeapiserver + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + genericapiserver "k8s.io/apiserver/pkg/server" +) + +// RESTOptionsFactory is a RESTOptionsGetter for kube apiservers since they do complicated stuff +type RESTOptionsFactory struct { + DeleteCollectionWorkers int + EnableGarbageCollection bool + EnableWatchCache bool + StorageFactory genericapiserver.StorageFactory +} + +func (f *RESTOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) { + storageConfig, err := f.StorageFactory.NewConfig(resource) + if err != nil { + return generic.RESTOptions{}, fmt.Errorf("Unable to find storage destination for %v, due to %v", resource, err.Error()) + } + + ret := generic.RESTOptions{ + StorageConfig: storageConfig, + Decorator: generic.UndecoratedStorage, + DeleteCollectionWorkers: f.DeleteCollectionWorkers, + EnableGarbageCollection: f.EnableGarbageCollection, + ResourcePrefix: f.StorageFactory.ResourcePrefix(resource), + } + if f.EnableWatchCache { + ret.Decorator = genericregistry.StorageWithCacher + } + + return ret, nil +} diff --git a/pkg/master/BUILD b/pkg/master/BUILD index b8aa8dcc54c..d702f8cb647 100644 --- a/pkg/master/BUILD +++ b/pkg/master/BUILD @@ -75,13 +75,11 @@ go_library( "//vendor:github.com/prometheus/client_golang/prometheus", "//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", - "//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/util/intstr", "//vendor:k8s.io/apimachinery/pkg/util/net", "//vendor:k8s.io/apimachinery/pkg/util/runtime", "//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apiserver/pkg/registry/generic", - "//vendor:k8s.io/apiserver/pkg/registry/generic/registry", "//vendor:k8s.io/apiserver/pkg/server", "//vendor:k8s.io/apiserver/pkg/server/healthz", ], @@ -115,6 +113,7 @@ go_test( "//pkg/client/clientset_generated/clientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/generated/openapi:go_default_library", + "//pkg/kubeapiserver:go_default_library", "//pkg/kubelet/client:go_default_library", "//pkg/version:go_default_library", "//vendor:github.com/go-openapi/loads", diff --git a/pkg/master/master.go b/pkg/master/master.go index 9ebe00d463a..c2ed608884b 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -25,10 +25,8 @@ import ( "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/registry/generic" - genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/healthz" "k8s.io/kubernetes/cmd/kube-apiserver/app/options" @@ -82,11 +80,8 @@ type Config struct { APIResourceConfigSource genericapiserver.APIResourceConfigSource StorageFactory genericapiserver.StorageFactory - EnableGarbageCollection bool - EnableWatchCache bool EnableCoreControllers bool EndpointReconcilerConfig EndpointReconcilerConfig - DeleteCollectionWorkers int EventTTL time.Duration KubeletClientConfig kubeletclient.KubeletClientConfig @@ -222,18 +217,6 @@ func (c completedConfig) New() (*Master, error) { GenericAPIServer: s, } - restOptionsFactory := &restOptionsFactory{ - deleteCollectionWorkers: c.DeleteCollectionWorkers, - enableGarbageCollection: c.EnableGarbageCollection, - storageFactory: c.StorageFactory, - } - - if c.EnableWatchCache { - restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher - } else { - restOptionsFactory.storageDecorator = generic.UndecoratedStorage - } - // install legacy rest storage if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { legacyRESTStorageProvider := corerest.LegacyRESTStorageProvider{ @@ -245,7 +228,7 @@ func (c completedConfig) New() (*Master, error) { ServiceNodePortRange: c.ServiceNodePortRange, LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig, } - m.InstallLegacyAPI(c.Config, restOptionsFactory, legacyRESTStorageProvider) + m.InstallLegacyAPI(c.Config, c.Config.GenericConfig.RESTOptionsGetter, legacyRESTStorageProvider) } restStorageProviders := []RESTStorageProvider{ @@ -260,7 +243,7 @@ func (c completedConfig) New() (*Master, error) { rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorizer}, storagerest.RESTStorageProvider{}, } - m.InstallAPIs(c.Config.APIResourceConfigSource, restOptionsFactory, restStorageProviders...) + m.InstallAPIs(c.Config.APIResourceConfigSource, c.Config.GenericConfig.RESTOptionsGetter, restStorageProviders...) if c.Tunneler != nil { m.installTunneler(c.Tunneler, corev1client.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig).Nodes()) @@ -340,28 +323,6 @@ func (m *Master) InstallAPIs(apiResourceConfigSource genericapiserver.APIResourc } } -type restOptionsFactory struct { - deleteCollectionWorkers int - enableGarbageCollection bool - storageFactory genericapiserver.StorageFactory - storageDecorator generic.StorageDecorator -} - -func (f *restOptionsFactory) GetRESTOptions(resource schema.GroupResource) (generic.RESTOptions, error) { - storageConfig, err := f.storageFactory.NewConfig(resource) - if err != nil { - return generic.RESTOptions{}, fmt.Errorf("Unable to find storage destination for %v, due to %v", resource, err.Error()) - } - - return generic.RESTOptions{ - StorageConfig: storageConfig, - Decorator: f.storageDecorator, - DeleteCollectionWorkers: f.deleteCollectionWorkers, - EnableGarbageCollection: f.enableGarbageCollection, - ResourcePrefix: f.storageFactory.ResourcePrefix(resource), - }, nil -} - type nodeAddressProvider struct { nodeClient corev1client.NodeInterface } diff --git a/pkg/master/master_test.go b/pkg/master/master_test.go index 15312603266..5f290ff499c 100644 --- a/pkg/master/master_test.go +++ b/pkg/master/master_test.go @@ -51,6 +51,7 @@ import ( extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" "k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" + "k8s.io/kubernetes/pkg/kubeapiserver" kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" kubeversion "k8s.io/kubernetes/pkg/version" @@ -87,6 +88,12 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert. config.GenericConfig.RequestContextMapper = genericapirequest.NewRequestContextMapper() config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: api.Codecs}} config.GenericConfig.EnableMetrics = true + config.GenericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{ + StorageFactory: storageFactory, + EnableWatchCache: true, + EnableGarbageCollection: true, + DeleteCollectionWorkers: 1, + } config.EnableCoreControllers = false config.KubeletClientConfig = kubeletclient.KubeletClientConfig{Port: 10250} config.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{ diff --git a/test/integration/framework/BUILD b/test/integration/framework/BUILD index de29a4d9a4b..7a21c2e41bf 100644 --- a/test/integration/framework/BUILD +++ b/test/integration/framework/BUILD @@ -34,6 +34,7 @@ go_library( "//pkg/controller:go_default_library", "//pkg/controller/replication:go_default_library", "//pkg/generated/openapi:go_default_library", + "//pkg/kubeapiserver:go_default_library", "//pkg/kubectl:go_default_library", "//pkg/kubelet/client:go_default_library", "//pkg/master:go_default_library", diff --git a/test/integration/framework/master_utils.go b/test/integration/framework/master_utils.go index a684733b6d0..fbe1b6b93b3 100644 --- a/test/integration/framework/master_utils.go +++ b/test/integration/framework/master_utils.go @@ -61,6 +61,7 @@ import ( "k8s.io/kubernetes/pkg/controller" replicationcontroller "k8s.io/kubernetes/pkg/controller/replication" "k8s.io/kubernetes/pkg/generated/openapi" + "k8s.io/kubernetes/pkg/kubeapiserver" "k8s.io/kubernetes/pkg/kubectl" kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" "k8s.io/kubernetes/pkg/master" @@ -364,13 +365,18 @@ func NewMasterConfig() *master.Config { genericConfig.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer() genericConfig.AdmissionControl = admit.NewAlwaysAdmit() genericConfig.EnableMetrics = true + genericConfig.RESTOptionsGetter = &kubeapiserver.RESTOptionsFactory{ + StorageFactory: storageFactory, + EnableWatchCache: true, + EnableGarbageCollection: true, + DeleteCollectionWorkers: 1, + } return &master.Config{ GenericConfig: genericConfig, APIResourceConfigSource: master.DefaultAPIResourceConfigSource(), StorageFactory: storageFactory, EnableCoreControllers: true, - EnableWatchCache: true, KubeletClientConfig: kubeletclient.KubeletClientConfig{Port: 10250}, APIServerServicePort: 443, MasterCount: 1, diff --git a/test/integration/garbagecollector/garbage_collector_test.go b/test/integration/garbagecollector/garbage_collector_test.go index 3963ca796be..5d337dddcad 100644 --- a/test/integration/garbagecollector/garbage_collector_test.go +++ b/test/integration/garbagecollector/garbage_collector_test.go @@ -122,7 +122,6 @@ func newOwnerRC(name, namespace string) *v1.ReplicationController { func setup(t *testing.T) (*httptest.Server, *garbagecollector.GarbageCollector, clientset.Interface) { masterConfig := framework.NewIntegrationTestMasterConfig() masterConfig.EnableCoreControllers = false - masterConfig.GenericConfig.EnableGarbageCollection = true _, s := framework.RunAMaster(masterConfig) clientSet, err := clientset.NewForConfig(&restclient.Config{Host: s.URL}) From 7cb5463b263ab235ae8dbb8757a0264df0e78d1e Mon Sep 17 00:00:00 2001 From: deads2k Date: Wed, 1 Feb 2017 08:18:37 -0500 Subject: [PATCH 3/3] create sample-apiserver repo for people to inspect --- hack/.linted_packages | 2 + hack/godep-save.sh | 3 + hack/verify-staging-imports.sh | 1 + .../apiserver/pkg/server/genericapiserver.go | 9 +- .../pkg/server/options/authentication.go | 2 +- .../artifacts/example/example.yaml | 7 + .../artifacts/simple-image/Dockerfile | 17 ++ .../artifacts/static/static-pod.yaml | 33 ++++ .../sample-apiserver/hack/build-image.sh | 28 ++++ .../sample-apiserver/hack/update-codegen.sh | 69 ++++++++ staging/src/k8s.io/sample-apiserver/main.go | 43 +++++ .../sample-apiserver/pkg/apis/wardle/doc.go | 21 +++ .../pkg/apis/wardle/install/install.go | 44 +++++ .../pkg/apis/wardle/register.go | 53 ++++++ .../sample-apiserver/pkg/apis/wardle/types.go | 43 +++++ .../pkg/apis/wardle/v1alpha1/doc.go | 22 +++ .../pkg/apis/wardle/v1alpha1/register.go | 43 +++++ .../pkg/apis/wardle/v1alpha1/types.go | 43 +++++ .../v1alpha1/zz_generated.conversion.go | 129 ++++++++++++++ .../wardle/v1alpha1/zz_generated.deepcopy.go | 93 +++++++++++ .../pkg/apis/wardle/zz_generated.deepcopy.go | 93 +++++++++++ .../pkg/apiserver/apiserver.go | 113 +++++++++++++ .../sample-apiserver/pkg/cmd/server/start.go | 124 ++++++++++++++ .../pkg/registry/wardle/etcd.go | 54 ++++++ .../pkg/registry/wardle/strategy.go | 95 +++++++++++ test/integration/examples/BUILD | 8 +- test/integration/examples/apiserver_test.go | 157 +++++++++++------- vendor/BUILD | 122 ++++++++++++++ vendor/k8s.io/sample-apiserver | 1 + 29 files changed, 1403 insertions(+), 69 deletions(-) create mode 100644 staging/src/k8s.io/sample-apiserver/artifacts/example/example.yaml create mode 100644 staging/src/k8s.io/sample-apiserver/artifacts/simple-image/Dockerfile create mode 100644 staging/src/k8s.io/sample-apiserver/artifacts/static/static-pod.yaml create mode 100755 staging/src/k8s.io/sample-apiserver/hack/build-image.sh create mode 100755 staging/src/k8s.io/sample-apiserver/hack/update-codegen.sh create mode 100644 staging/src/k8s.io/sample-apiserver/main.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/doc.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/install/install.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/register.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/types.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/doc.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/register.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/types.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.conversion.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.deepcopy.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/zz_generated.deepcopy.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/etcd.go create mode 100644 staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/strategy.go create mode 120000 vendor/k8s.io/sample-apiserver diff --git a/hack/.linted_packages b/hack/.linted_packages index cf4f5ea9bee..70d0e0bab59 100644 --- a/hack/.linted_packages +++ b/hack/.linted_packages @@ -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/homedir 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_node/runner/local test/images/clusterapi-tester diff --git a/hack/godep-save.sh b/hack/godep-save.sh index 1bc1f19ff8f..a66cc679bf6 100755 --- a/hack/godep-save.sh +++ b/hack/godep-save.sh @@ -47,6 +47,9 @@ pushd "${KUBE_ROOT}" > /dev/null if [ ! -e "vendor/k8s.io/apimachinery" ]; then ln -s ../../staging/src/k8s.io/apimachinery vendor/k8s.io/apimachinery 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 echo "Don't forget to run hack/update-godep-licenses.sh if you added or removed a dependency!" diff --git a/hack/verify-staging-imports.sh b/hack/verify-staging-imports.sh index 21653a53ce2..b48441079af 100755 --- a/hack/verify-staging-imports.sh +++ b/hack/verify-staging-imports.sh @@ -53,6 +53,7 @@ RC=0 print_forbidden_imports apimachinery k8s.io/ || 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 sample-apiserver k8s.io/kubernetes || RC=1 if [ ${RC} != 0 ]; then exit ${RC} fi diff --git a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go index 38b5dab5d82..2c19a0d2829 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go +++ b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go @@ -388,9 +388,10 @@ func NewDefaultAPIGroupInfo(group string, registry *registered.APIRegistrationMa return APIGroupInfo{ GroupMeta: *groupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{}, - OptionsExternalVersion: ®istry.GroupOrDie("").GroupVersion, - Scheme: scheme, - ParameterCodec: parameterCodec, - NegotiatedSerializer: codecs, + // TODO unhardcode this. It was hardcoded before, but we need to re-evaluate + OptionsExternalVersion: &schema.GroupVersion{Version: "v1"}, + Scheme: scheme, + ParameterCodec: parameterCodec, + NegotiatedSerializer: codecs, } } diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go b/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go index aafaa3de809..16378fa145b 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go @@ -60,7 +60,7 @@ func (s *RequestHeaderAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { // ToAuthenticationRequestHeaderConfig returns a RequestHeaderConfig config object for these options // if necessary, nil otherwise. 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 } diff --git a/staging/src/k8s.io/sample-apiserver/artifacts/example/example.yaml b/staging/src/k8s.io/sample-apiserver/artifacts/example/example.yaml new file mode 100644 index 00000000000..078a36d0a21 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/artifacts/example/example.yaml @@ -0,0 +1,7 @@ +apiVersion: serviceinjection.k8s.io/v1alpha1 +kind: ServiceInjection +metadata: + name: injector + namespace: kube-system + labels: + sample-label: foo diff --git a/staging/src/k8s.io/sample-apiserver/artifacts/simple-image/Dockerfile b/staging/src/k8s.io/sample-apiserver/artifacts/simple-image/Dockerfile new file mode 100644 index 00000000000..502f6aa9af8 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/artifacts/simple-image/Dockerfile @@ -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"] diff --git a/staging/src/k8s.io/sample-apiserver/artifacts/static/static-pod.yaml b/staging/src/k8s.io/sample-apiserver/artifacts/static/static-pod.yaml new file mode 100644 index 00000000000..960e933fc24 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/artifacts/static/static-pod.yaml @@ -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/ diff --git a/staging/src/k8s.io/sample-apiserver/hack/build-image.sh b/staging/src/k8s.io/sample-apiserver/hack/build-image.sh new file mode 100755 index 00000000000..cc61c7bc6ae --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/hack/build-image.sh @@ -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 diff --git a/staging/src/k8s.io/sample-apiserver/hack/update-codegen.sh b/staging/src/k8s.io/sample-apiserver/hack/update-codegen.sh new file mode 100755 index 00000000000..0bcf8082efe --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/hack/update-codegen.sh @@ -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 + "$@" diff --git a/staging/src/k8s.io/sample-apiserver/main.go b/staging/src/k8s.io/sample-apiserver/main.go new file mode 100644 index 00000000000..8b9424fa481 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/main.go @@ -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) + } +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/doc.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/doc.go new file mode 100644 index 00000000000..bb99a18fb81 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/doc.go @@ -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 diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/install/install.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/install/install.go new file mode 100644 index 00000000000..74a961939ae --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/install/install.go @@ -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) + } +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/register.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/register.go new file mode 100644 index 00000000000..d7ce354ccf8 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/register.go @@ -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 +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/types.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/types.go new file mode 100644 index 00000000000..270b2f45110 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/types.go @@ -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 +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/doc.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/doc.go new file mode 100644 index 00000000000..06c174cf11d --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/doc.go @@ -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 diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/register.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/register.go new file mode 100644 index 00000000000..5c8a22aae97 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/register.go @@ -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 +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/types.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/types.go new file mode 100644 index 00000000000..8d796a06514 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/types.go @@ -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"` +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.conversion.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.conversion.go new file mode 100644 index 00000000000..8e9aaa5ba48 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.conversion.go @@ -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) +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.deepcopy.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..60d9e324de7 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.deepcopy.go @@ -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 + } +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/zz_generated.deepcopy.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/zz_generated.deepcopy.go new file mode 100644 index 00000000000..450990303e1 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/zz_generated.deepcopy.go @@ -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 + } +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go b/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go new file mode 100644 index 00000000000..95ed82fb251 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go @@ -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 +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go b/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go new file mode 100644 index 00000000000..7f087e0fd41 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go @@ -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 +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/etcd.go b/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/etcd.go new file mode 100644 index 00000000000..f44ffcbf13a --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/etcd.go @@ -0,0 +1,54 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package 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} +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/strategy.go b/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/strategy.go new file mode 100644 index 00000000000..12b1a6a8172 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/strategy.go @@ -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) +} diff --git a/test/integration/examples/BUILD b/test/integration/examples/BUILD index 133d8002c8b..64e0a428dcf 100644 --- a/test/integration/examples/BUILD +++ b/test/integration/examples/BUILD @@ -12,11 +12,15 @@ go_test( srcs = ["apiserver_test.go"], tags = ["automanaged"], deps = [ - "//cmd/libs/go2idl/client-gen/test_apis/testgroup/v1:go_default_library", - "//examples/apiserver:go_default_library", + "//test/integration/framework:go_default_library", "//vendor:github.com/golang/glog", "//vendor:github.com/stretchr/testify/assert", "//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", ], ) diff --git a/test/integration/examples/apiserver_test.go b/test/integration/examples/apiserver_test.go index ff42cdac31e..636f3d370a5 100644 --- a/test/integration/examples/apiserver_test.go +++ b/test/integration/examples/apiserver_test.go @@ -22,18 +22,25 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "testing" "time" - "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup/v1" - "github.com/golang/glog" "github.com/stretchr/testify/assert" + 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{ GroupVersion: groupVersion.String(), @@ -41,52 +48,85 @@ var groupVersionForDiscovery = metav1.GroupVersionForDiscovery{ } 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{}) - go func() { - if err := apiserver.NewServerRunOptions().Run(stopCh); err != nil { - t.Fatalf("Error in bringing up the server: %v", err) - } - }() 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) } - testSwaggerSpec(t, serverIP) - testAPIGroupList(t, serverIP) - testAPIGroup(t, serverIP) - testAPIResourceList(t, serverIP) + + testAPIGroupList(t, serverLocation) + testAPIGroup(t, serverLocation) + testAPIResourceList(t, serverLocation) } -func TestRunSecureServer(t *testing.T) { - serverIP := fmt.Sprintf("https://localhost:%d", apiserver.SecurePort) - stopCh := make(chan struct{}) - go func() { - options := apiserver.NewServerRunOptions() - options.InsecureServing.BindPort = 0 - options.SecureServing.ServingOptions.BindPort = apiserver.SecurePort - if err := options.Run(stopCh); err != nil { - t.Fatalf("Error in bringing up the server: %v", err) - } - }() - defer close(stopCh) - if err := waitForApiserverUp(serverIP); err != nil { - t.Fatalf("%v", err) +func createKubeConfig(clientCfg *rest.Config) *clientcmdapi.Config { + clusterNick := "cluster" + userNick := "user" + contextNick := "context" + + config := clientcmdapi.NewConfig() + + credentials := clientcmdapi.NewAuthInfo() + credentials.Token = clientCfg.BearerToken + credentials.ClientCertificate = clientCfg.TLSClientConfig.CertFile + if len(credentials.ClientCertificate) == 0 { + credentials.ClientCertificateData = clientCfg.TLSClientConfig.CertData } - testSwaggerSpec(t, serverIP) - testAPIGroupList(t, serverIP) - testAPIGroup(t, serverIP) - testAPIResourceList(t, serverIP) + credentials.ClientKey = clientCfg.TLSClientConfig.KeyFile + if len(credentials.ClientKey) == 0 { + credentials.ClientKeyData = clientCfg.TLSClientConfig.KeyData + } + 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 { - for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(5 * time.Second) { - glog.Errorf("Waiting for : %#v", serverIP) +func waitForApiserverUp(serverLocation string) error { + for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(5 * time.Second) { + glog.Errorf("Waiting for : %#v", serverLocation) tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{Transport: tr} - _, err := client.Get(serverIP) + _, err := client.Get(serverLocation) if err == nil { return nil } @@ -116,65 +156,58 @@ func readResponse(serverURL string) ([]byte, error) { return contents, nil } -func testSwaggerSpec(t *testing.T, serverIP string) { - serverURL := serverIP + "/swaggerapi" - _, err := readResponse(serverURL) - if err != nil { - t.Fatalf("%v", err) - } -} - -func testAPIGroupList(t *testing.T, serverIP string) { - serverURL := serverIP + "/apis" +func testAPIGroupList(t *testing.T, serverLocation string) { + serverURL := serverLocation + "/apis" contents, err := readResponse(serverURL) if err != nil { t.Fatalf("%v", err) } + t.Log(string(contents)) var apiGroupList metav1.APIGroupList err = json.Unmarshal(contents, &apiGroupList) if err != nil { t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) } 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, apiGroupList.Groups[0].Versions[0], groupVersionForDiscovery) - assert.Equal(t, apiGroupList.Groups[0].PreferredVersion, groupVersionForDiscovery) + assert.Equal(t, groupVersionForDiscovery, apiGroupList.Groups[0].Versions[0]) + assert.Equal(t, groupVersionForDiscovery, apiGroupList.Groups[0].PreferredVersion) } -func testAPIGroup(t *testing.T, serverIP string) { - serverURL := serverIP + "/apis/testgroup.k8s.io" +func testAPIGroup(t *testing.T, serverLocation string) { + serverURL := serverLocation + "/apis/wardle.k8s.io" contents, err := readResponse(serverURL) if err != nil { t.Fatalf("%v", err) } + t.Log(string(contents)) var apiGroup metav1.APIGroup err = json.Unmarshal(contents, &apiGroup) if err != nil { t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) } - assert.Equal(t, apiGroup.APIVersion, groupVersion.Version) - assert.Equal(t, apiGroup.Name, groupVersion.Group) + assert.Equal(t, groupVersion.Group, apiGroup.Name) assert.Equal(t, 1, len(apiGroup.Versions)) - assert.Equal(t, apiGroup.Versions[0].GroupVersion, groupVersion.String()) - assert.Equal(t, apiGroup.Versions[0].Version, groupVersion.Version) - assert.Equal(t, apiGroup.Versions[0], apiGroup.PreferredVersion) + assert.Equal(t, groupVersion.String(), apiGroup.Versions[0].GroupVersion) + assert.Equal(t, groupVersion.Version, apiGroup.Versions[0].Version) + assert.Equal(t, apiGroup.PreferredVersion, apiGroup.Versions[0]) } -func testAPIResourceList(t *testing.T, serverIP string) { - serverURL := serverIP + "/apis/testgroup.k8s.io/v1" +func testAPIResourceList(t *testing.T, serverLocation string) { + serverURL := serverLocation + "/apis/wardle.k8s.io/v1alpha1" contents, err := readResponse(serverURL) if err != nil { t.Fatalf("%v", err) } + t.Log(string(contents)) var apiResourceList metav1.APIResourceList err = json.Unmarshal(contents, &apiResourceList) if err != nil { t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) } - assert.Equal(t, apiResourceList.APIVersion, groupVersion.Version) - assert.Equal(t, apiResourceList.GroupVersion, groupVersion.String()) + assert.Equal(t, groupVersion.String(), apiResourceList.GroupVersion) 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) } diff --git a/vendor/BUILD b/vendor/BUILD index dd3fd45ca3c..9202866e0e1 100644 --- a/vendor/BUILD +++ b/vendor/BUILD @@ -15281,3 +15281,125 @@ go_test( "//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", + ], +) diff --git a/vendor/k8s.io/sample-apiserver b/vendor/k8s.io/sample-apiserver new file mode 120000 index 00000000000..23b10fee7a1 --- /dev/null +++ b/vendor/k8s.io/sample-apiserver @@ -0,0 +1 @@ +../../staging/src/k8s.io/sample-apiserver \ No newline at end of file