apiserver: make config completion structural recursion

This commit is contained in:
Dr. Stefan Schimanski 2017-09-06 18:06:18 +02:00
parent 7d09148ad7
commit 1bcea54104
9 changed files with 87 additions and 74 deletions

View File

@ -77,7 +77,7 @@ type Controller struct {
} }
// NewBootstrapController returns a controller for watching the core capabilities of the master // NewBootstrapController returns a controller for watching the core capabilities of the master
func (c *Config) NewBootstrapController(legacyRESTStorage corerest.LegacyRESTStorage, serviceClient coreclient.ServicesGetter, nsClient coreclient.NamespacesGetter) *Controller { func (c *completedConfig) NewBootstrapController(legacyRESTStorage corerest.LegacyRESTStorage, serviceClient coreclient.ServicesGetter, nsClient coreclient.NamespacesGetter) *Controller {
return &Controller{ return &Controller{
ServiceClient: serviceClient, ServiceClient: serviceClient,
NamespaceClient: nsClient, NamespaceClient: nsClient,

View File

@ -138,6 +138,16 @@ type Config struct {
ExtraConfig ExtraConfig ExtraConfig ExtraConfig
} }
type completedConfig struct {
GenericConfig genericapiserver.CompletedConfig
ExtraConfig *ExtraConfig
}
type CompletedConfig struct {
// Embed a private pointer that cannot be instantiated outside of this package.
*completedConfig
}
// EndpointReconcilerConfig holds the endpoint reconciler and endpoint reconciliation interval to be // EndpointReconcilerConfig holds the endpoint reconciler and endpoint reconciliation interval to be
// used by the master. // used by the master.
type EndpointReconcilerConfig struct { type EndpointReconcilerConfig struct {
@ -152,13 +162,12 @@ type Master struct {
ClientCARegistrationHook ClientCARegistrationHook ClientCARegistrationHook ClientCARegistrationHook
} }
type completedConfig struct {
*Config
}
// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. // Complete fills in any fields not set that are required to have valid data. It's mutating the receiver.
func (c *Config) Complete() completedConfig { func (cfg *Config) Complete() CompletedConfig {
c.GenericConfig.Complete() c := completedConfig{
cfg.GenericConfig.Complete(),
&cfg.ExtraConfig,
}
serviceIPRange, apiServerServiceIP, err := DefaultServiceIPRange(c.ExtraConfig.ServiceIPRange) serviceIPRange, apiServerServiceIP, err := DefaultServiceIPRange(c.ExtraConfig.ServiceIPRange)
if err != nil { if err != nil {
@ -201,12 +210,7 @@ func (c *Config) Complete() completedConfig {
// this has always been hardcoded true in the past // this has always been hardcoded true in the past
c.GenericConfig.EnableMetrics = true c.GenericConfig.EnableMetrics = true
return completedConfig{c} 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 Master from the given config. // New returns a new instance of Master from the given config.
@ -218,7 +222,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
return nil, fmt.Errorf("Master.New() called with empty config.KubeletClientConfig") return nil, fmt.Errorf("Master.New() called with empty config.KubeletClientConfig")
} }
s, err := c.Config.GenericConfig.SkipComplete().New("kube-apiserver", delegationTarget) // completion is done in Complete, no need for a second time s, err := c.GenericConfig.New("kube-apiserver", delegationTarget)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -245,7 +249,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
ServiceNodePortRange: c.ExtraConfig.ServiceNodePortRange, ServiceNodePortRange: c.ExtraConfig.ServiceNodePortRange,
LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig, LoopbackClientConfig: c.GenericConfig.LoopbackClientConfig,
} }
m.InstallLegacyAPI(c.Config, c.Config.GenericConfig.RESTOptionsGetter, legacyRESTStorageProvider) m.InstallLegacyAPI(&c, c.GenericConfig.RESTOptionsGetter, legacyRESTStorageProvider)
} }
// The order here is preserved in discovery. // The order here is preserved in discovery.
@ -284,7 +288,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
return m, nil return m, nil
} }
func (m *Master) InstallLegacyAPI(c *Config, restOptionsGetter generic.RESTOptionsGetter, legacyRESTStorageProvider corerest.LegacyRESTStorageProvider) { func (m *Master) InstallLegacyAPI(c *completedConfig, restOptionsGetter generic.RESTOptionsGetter, legacyRESTStorageProvider corerest.LegacyRESTStorageProvider) {
legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter) legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(restOptionsGetter)
if err != nil { if err != nil {
glog.Fatalf("Error building core storage: %v", err) glog.Fatalf("Error building core storage: %v", err)

View File

@ -81,11 +81,20 @@ func init() {
type ExtraConfig struct { type ExtraConfig struct {
CRDRESTOptionsGetter genericregistry.RESTOptionsGetter CRDRESTOptionsGetter genericregistry.RESTOptionsGetter
} }
type Config struct { type Config struct {
GenericConfig *genericapiserver.Config GenericConfig *genericapiserver.Config
ExtraConfig ExtraConfig ExtraConfig ExtraConfig
} }
type completedConfig struct {
GenericConfig genericapiserver.CompletedConfig
ExtraConfig *ExtraConfig
}
type CompletedConfig struct {
// Embed a private pointer that cannot be instantiated outside of this package.
*completedConfig
} }
type CustomResourceDefinitions struct { type CustomResourceDefinitions struct {
@ -95,31 +104,25 @@ type CustomResourceDefinitions struct {
Informers internalinformers.SharedInformerFactory Informers internalinformers.SharedInformerFactory
} }
type completedConfig struct {
*Config
}
// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. // Complete fills in any fields not set that are required to have valid data. It's mutating the receiver.
func (c *Config) Complete() completedConfig { func (cfg *Config) Complete() CompletedConfig {
c.GenericConfig.EnableDiscovery = false c := completedConfig{
c.GenericConfig.Complete() cfg.GenericConfig.Complete(),
&cfg.ExtraConfig,
}
c.GenericConfig.EnableDiscovery = false
c.GenericConfig.Version = &version.Info{ c.GenericConfig.Version = &version.Info{
Major: "0", Major: "0",
Minor: "1", Minor: "1",
} }
return completedConfig{c} 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 CustomResourceDefinitions from the given config. // New returns a new instance of CustomResourceDefinitions from the given config.
func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) (*CustomResourceDefinitions, error) { func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) (*CustomResourceDefinitions, error) {
genericServer, err := c.Config.GenericConfig.SkipComplete().New("apiextensions-apiserver", delegationTarget) // completion is done in Complete, no need for a second time genericServer, err := c.GenericConfig.New("apiextensions-apiserver", delegationTarget)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -62,6 +62,7 @@ import (
certutil "k8s.io/client-go/util/cert" certutil "k8s.io/client-go/util/cert"
openapicommon "k8s.io/kube-openapi/pkg/common" openapicommon "k8s.io/kube-openapi/pkg/common"
// install apis
_ "k8s.io/apiserver/pkg/apis/apiserver/install" _ "k8s.io/apiserver/pkg/apis/apiserver/install"
) )
@ -302,9 +303,14 @@ type completedConfig struct {
*Config *Config
} }
type CompletedConfig struct {
// Embed a private pointer that cannot be instantiated outside of this package.
*completedConfig
}
// Complete fills in any fields not set that are required to have valid data and can be derived // Complete fills in any fields not set that are required to have valid data and can be derived
// from other fields. If you're going to `ApplyOptions`, do that first. It's mutating the receiver. // from other fields. If you're going to `ApplyOptions`, do that first. It's mutating the receiver.
func (c *Config) Complete() completedConfig { func (c *Config) Complete() CompletedConfig {
if len(c.ExternalAddress) == 0 && c.PublicAddress != nil { if len(c.ExternalAddress) == 0 && c.PublicAddress != nil {
hostAndPort := c.PublicAddress.String() hostAndPort := c.PublicAddress.String()
if c.ReadWritePort != 0 { if c.ReadWritePort != 0 {
@ -379,12 +385,7 @@ func (c *Config) Complete() completedConfig {
c.RequestInfoResolver = NewRequestInfoResolver(c) c.RequestInfoResolver = NewRequestInfoResolver(c)
} }
return completedConfig{c} return CompletedConfig{&completedConfig{c}}
}
// SkipComplete provides a way to construct a server instance without config completion.
func (c *Config) SkipComplete() completedConfig {
return completedConfig{c}
} }
// New creates a new server which logically combines the handling chain with the passed server. // New creates a new server which logically combines the handling chain with the passed server.

View File

@ -52,7 +52,7 @@ func TestNewWithDelegate(t *testing.T) {
return fmt.Errorf("delegate failed healthcheck") return fmt.Errorf("delegate failed healthcheck")
})) }))
delegateServer, err := delegateConfig.SkipComplete().New("test", EmptyDelegate) delegateServer, err := delegateConfig.Complete().New("test", EmptyDelegate)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -147,7 +147,7 @@ func TestInstallAPIGroups(t *testing.T) {
config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix") config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix")
config.DiscoveryAddresses = discovery.DefaultAddresses{DefaultAddress: "ExternalAddress"} config.DiscoveryAddresses = discovery.DefaultAddresses{DefaultAddress: "ExternalAddress"}
s, err := config.SkipComplete().New("test", EmptyDelegate) s, err := config.Complete().New("test", EmptyDelegate)
if err != nil { if err != nil {
t.Fatalf("Error in bringing up the server: %v", err) t.Fatalf("Error in bringing up the server: %v", err)
} }
@ -351,7 +351,7 @@ func TestCustomHandlerChain(t *testing.T) {
called = true called = true
}) })
s, err := config.SkipComplete().New("test", EmptyDelegate) s, err := config.Complete().New("test", EmptyDelegate)
if err != nil { if err != nil {
t.Fatalf("Error in bringing up the server: %v", err) t.Fatalf("Error in bringing up the server: %v", err)
} }
@ -406,7 +406,7 @@ func TestNotRestRoutesHaveAuth(t *testing.T) {
kubeVersion := fakeVersion() kubeVersion := fakeVersion()
config.Version = &kubeVersion config.Version = &kubeVersion
s, err := config.SkipComplete().New("test", EmptyDelegate) s, err := config.Complete().New("test", EmptyDelegate)
if err != nil { if err != nil {
t.Fatalf("Error in bringing up the server: %v", err) t.Fatalf("Error in bringing up the server: %v", err)
} }

View File

@ -88,10 +88,20 @@ type ExtraConfig struct {
} }
type Config struct { type Config struct {
GenericConfig *genericapiserver.RecommendedConfig GenericConfig *genericapiserver.Config
ExtraConfig ExtraConfig ExtraConfig ExtraConfig
} }
type completedConfig struct {
GenericConfig genericapiserver.CompletedConfig
ExtraConfig *ExtraConfig
}
type CompletedConfig struct {
// Embed a private pointer that cannot be instantiated outside of this package.
*completedConfig
}
// APIAggregator contains state for a Kubernetes cluster master/api server. // APIAggregator contains state for a Kubernetes cluster master/api server.
type APIAggregator struct { type APIAggregator struct {
GenericAPIServer *genericapiserver.GenericAPIServer GenericAPIServer *genericapiserver.GenericAPIServer
@ -124,41 +134,35 @@ type APIAggregator struct {
openAPIAggregationController *openapicontroller.AggregationController openAPIAggregationController *openapicontroller.AggregationController
} }
type completedConfig struct {
*Config
}
// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. // Complete fills in any fields not set that are required to have valid data. It's mutating the receiver.
func (c *Config) Complete() completedConfig { func (cfg *Config) Complete() CompletedConfig {
c := completedConfig{
cfg.GenericConfig.Complete(),
&cfg.ExtraConfig,
}
// the kube aggregator wires its own discovery mechanism // the kube aggregator wires its own discovery mechanism
// TODO eventually collapse this by extracting all of the discovery out // TODO eventually collapse this by extracting all of the discovery out
c.GenericConfig.EnableDiscovery = false c.GenericConfig.EnableDiscovery = false
c.GenericConfig.Complete()
version := version.Get() version := version.Get()
c.GenericConfig.Version = &version c.GenericConfig.Version = &version
return completedConfig{c} 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 APIAggregator from the given config. // New returns a new instance of APIAggregator from the given config.
func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.DelegationTarget) (*APIAggregator, error) { func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.DelegationTarget) (*APIAggregator, error) {
// Prevent generic API server to install OpenAPI handler. Aggregator server // Prevent generic API server to install OpenAPI handler. Aggregator server
// has its own customized OpenAPI handler. // has its own customized OpenAPI handler.
openApiConfig := c.Config.GenericConfig.OpenAPIConfig openApiConfig := c.GenericConfig.OpenAPIConfig
c.Config.GenericConfig.OpenAPIConfig = nil c.GenericConfig.OpenAPIConfig = nil
genericServer, err := c.Config.GenericConfig.SkipComplete().New("kube-aggregator", delegationTarget) // completion is done in Complete, no need for a second time genericServer, err := c.GenericConfig.New("kube-aggregator", delegationTarget)
if err != nil { if err != nil {
return nil, err return nil, err
} }
apiregistrationClient, err := internalclientset.NewForConfig(c.Config.GenericConfig.LoopbackClientConfig) apiregistrationClient, err := internalclientset.NewForConfig(c.GenericConfig.LoopbackClientConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -67,8 +67,6 @@ type ExtraConfig struct {
type Config struct { type Config struct {
GenericConfig *genericapiserver.Config GenericConfig *genericapiserver.Config
// SharedInformerFactory provides shared informers for resources
SharedInformerFactory informers.SharedInformerFactory
ExtraConfig ExtraConfig ExtraConfig ExtraConfig
} }
@ -78,29 +76,33 @@ type WardleServer struct {
} }
type completedConfig struct { type completedConfig struct {
*Config GenericConfig genericapiserver.CompletedConfig
ExtraConfig *ExtraConfig
}
type CompletedConfig struct {
// Embed a private pointer that cannot be instantiated outside of this package.
*completedConfig
} }
// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. // Complete fills in any fields not set that are required to have valid data. It's mutating the receiver.
func (c *Config) Complete() completedConfig { func (cfg *Config) Complete() CompletedConfig {
c.GenericConfig.Complete() c := completedConfig{
cfg.GenericConfig.Complete(),
&cfg.ExtraConfig,
}
c.GenericConfig.Version = &version.Info{ c.GenericConfig.Version = &version.Info{
Major: "1", Major: "1",
Minor: "0", Minor: "0",
} }
return completedConfig{c} 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. // New returns a new instance of WardleServer from the given config.
func (c completedConfig) New() (*WardleServer, error) { func (c completedConfig) New() (*WardleServer, error) {
genericServer, err := c.Config.GenericConfig.SkipComplete().New("sample-apiserver", genericapiserver.EmptyDelegate) // completion is done in Complete, no need for a second time genericServer, err := c.GenericConfig.New("sample-apiserver", genericapiserver.EmptyDelegate)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -125,7 +125,6 @@ func (o WardleServerOptions) Config() (*apiserver.Config, error) {
config := &apiserver.Config{ config := &apiserver.Config{
GenericConfig: serverConfig, GenericConfig: serverConfig,
SharedInformerFactory: informerFactory,
ExtraConfig: apiserver.ExtraConfig{}, ExtraConfig: apiserver.ExtraConfig{},
} }
return config, nil return config, nil
@ -143,7 +142,7 @@ func (o WardleServerOptions) RunWardleServer(stopCh <-chan struct{}) error {
} }
server.GenericAPIServer.AddPostStartHook("start-sample-server-informers", func(context genericapiserver.PostStartHookContext) error { server.GenericAPIServer.AddPostStartHook("start-sample-server-informers", func(context genericapiserver.PostStartHookContext) error {
config.SharedInformerFactory.Start(context.StopCh) config.GenericConfig.SharedInformerFactory.Start(context.StopCh)
return nil return nil
}) })