move CRD behind TPR
This commit is contained in:
@@ -105,8 +105,18 @@ func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// kubeAPIServer is at the base for now. This ensures that CustomResourceDefinitions trump TPRs
|
// TPRs are enabled and not yet beta, since this these are the successor, they fall under the same enablement rule
|
||||||
kubeAPIServer, err := CreateKubeAPIServer(kubeAPIServerConfig, genericapiserver.EmptyDelegate, sharedInformers)
|
// If additional API servers are added, they should be gated.
|
||||||
|
apiExtensionsConfig, err := createAPIExtensionsConfig(*kubeAPIServerConfig.GenericConfig, runOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
apiExtensionsServer, err := createAPIExtensionsServer(apiExtensionsConfig, genericapiserver.EmptyDelegate)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
kubeAPIServer, err := CreateKubeAPIServer(kubeAPIServerConfig, apiExtensionsServer.GenericAPIServer, sharedInformers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -128,24 +138,12 @@ func Run(runOptions *options.ServerRunOptions, stopCh <-chan struct{}) error {
|
|||||||
// this wires up openapi
|
// this wires up openapi
|
||||||
kubeAPIServer.GenericAPIServer.PrepareRun()
|
kubeAPIServer.GenericAPIServer.PrepareRun()
|
||||||
|
|
||||||
// TPRs are enabled and not yet beta, since this these are the successor, they fall under the same enablement rule
|
|
||||||
// Subsequent API servers in between here and kube-apiserver will need to be gated.
|
|
||||||
// These come first so that if someone registers both a TPR and a CRD, the CRD is preferred.
|
|
||||||
apiExtensionsConfig, err := createAPIExtensionsConfig(*kubeAPIServerConfig.GenericConfig, runOptions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
apiExtensionsServer, err := createAPIExtensionsServer(apiExtensionsConfig, kubeAPIServer.GenericAPIServer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// aggregator comes last in the chain
|
// aggregator comes last in the chain
|
||||||
aggregatorConfig, err := createAggregatorConfig(*kubeAPIServerConfig.GenericConfig, runOptions)
|
aggregatorConfig, err := createAggregatorConfig(*kubeAPIServerConfig.GenericConfig, runOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
aggregatorServer, err := createAggregatorServer(aggregatorConfig, apiExtensionsServer.GenericAPIServer, sharedInformers, apiExtensionsServer.Informers)
|
aggregatorServer, err := createAggregatorServer(aggregatorConfig, kubeAPIServer.GenericAPIServer, sharedInformers, apiExtensionsServer.Informers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines
|
// we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines
|
||||||
return err
|
return err
|
||||||
|
@@ -227,12 +227,12 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error {
|
|||||||
cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes)
|
cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes)
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := genericConfig.Complete().New(genericapiserver.EmptyDelegate)
|
m, err := genericConfig.Complete().New("federation", genericapiserver.EmptyDelegate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
routes.UIRedirect{}.Install(m.Handler.PostGoRestfulMux)
|
routes.UIRedirect{}.Install(m.Handler.NonGoRestfulMux)
|
||||||
routes.Logs{}.Install(m.Handler.GoRestfulContainer)
|
routes.Logs{}.Install(m.Handler.GoRestfulContainer)
|
||||||
|
|
||||||
apiResourceConfigSource := storageFactory.APIResourceConfigSource
|
apiResourceConfigSource := storageFactory.APIResourceConfigSource
|
||||||
|
@@ -211,13 +211,13 @@ 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(delegationTarget) // completion is done in Complete, no need for a second time
|
s, err := c.Config.GenericConfig.SkipComplete().New("kube-apiserver", delegationTarget) // completion is done in Complete, no need for a second time
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.EnableUISupport {
|
if c.EnableUISupport {
|
||||||
routes.UIRedirect{}.Install(s.Handler.PostGoRestfulMux)
|
routes.UIRedirect{}.Install(s.Handler.NonGoRestfulMux)
|
||||||
}
|
}
|
||||||
if c.EnableLogsSupport {
|
if c.EnableLogsSupport {
|
||||||
routes.Logs{}.Install(s.Handler.GoRestfulContainer)
|
routes.Logs{}.Install(s.Handler.GoRestfulContainer)
|
||||||
|
@@ -60,7 +60,7 @@ func TestValidOpenAPISpec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure swagger.json is not registered before calling PrepareRun.
|
// make sure swagger.json is not registered before calling PrepareRun.
|
||||||
server := httptest.NewServer(apirequest.WithRequestContext(master.GenericAPIServer.Handler.GoRestfulContainer.ServeMux, master.GenericAPIServer.RequestContextMapper()))
|
server := httptest.NewServer(apirequest.WithRequestContext(master.GenericAPIServer.Handler.Director, master.GenericAPIServer.RequestContextMapper()))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
resp, err := http.Get(server.URL + "/swagger.json")
|
resp, err := http.Get(server.URL + "/swagger.json")
|
||||||
if !assert.NoError(err) {
|
if !assert.NoError(err) {
|
||||||
|
@@ -251,7 +251,7 @@ func DefaultOpenAPIConfig(getDefinitions openapicommon.GetOpenAPIDefinitions, sc
|
|||||||
// WebServices set.
|
// WebServices set.
|
||||||
func DefaultSwaggerConfig() *swagger.Config {
|
func DefaultSwaggerConfig() *swagger.Config {
|
||||||
return &swagger.Config{
|
return &swagger.Config{
|
||||||
ApiPath: "/swaggerapi/",
|
ApiPath: "/swaggerapi",
|
||||||
SwaggerPath: "/swaggerui/",
|
SwaggerPath: "/swaggerui/",
|
||||||
SwaggerFilePath: "/swagger-ui/",
|
SwaggerFilePath: "/swagger-ui/",
|
||||||
SchemaFormatHandler: func(typeName string) string {
|
SchemaFormatHandler: func(typeName string) string {
|
||||||
@@ -369,7 +369,8 @@ func (c *Config) SkipComplete() completedConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
func (c completedConfig) New(delegationTarget DelegationTarget) (*GenericAPIServer, error) {
|
// name is used to differentiate for logging. The handler chain in particular can be difficult as it starts delgating.
|
||||||
|
func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*GenericAPIServer, error) {
|
||||||
// The delegationTarget and the config must agree on the RequestContextMapper
|
// The delegationTarget and the config must agree on the RequestContextMapper
|
||||||
|
|
||||||
if c.Serializer == nil {
|
if c.Serializer == nil {
|
||||||
@@ -382,7 +383,7 @@ func (c completedConfig) New(delegationTarget DelegationTarget) (*GenericAPIServ
|
|||||||
handlerChainBuilder := func(handler http.Handler) http.Handler {
|
handlerChainBuilder := func(handler http.Handler) http.Handler {
|
||||||
return c.BuildHandlerChainFunc(handler, c.Config)
|
return c.BuildHandlerChainFunc(handler, c.Config)
|
||||||
}
|
}
|
||||||
apiServerHandler := NewAPIServerHandler(c.RequestContextMapper, c.Serializer, handlerChainBuilder, delegationTarget.UnprotectedHandler())
|
apiServerHandler := NewAPIServerHandler(name, c.RequestContextMapper, c.Serializer, handlerChainBuilder, delegationTarget.UnprotectedHandler())
|
||||||
|
|
||||||
s := &GenericAPIServer{
|
s := &GenericAPIServer{
|
||||||
discoveryAddresses: c.DiscoveryAddresses,
|
discoveryAddresses: c.DiscoveryAddresses,
|
||||||
@@ -449,7 +450,7 @@ func (c completedConfig) New(delegationTarget DelegationTarget) (*GenericAPIServ
|
|||||||
// use the UnprotectedHandler from the delegation target to ensure that we don't attempt to double authenticator, authorize,
|
// use the UnprotectedHandler from the delegation target to ensure that we don't attempt to double authenticator, authorize,
|
||||||
// or some other part of the filter chain in delegation cases.
|
// or some other part of the filter chain in delegation cases.
|
||||||
if delegationTarget.UnprotectedHandler() == nil && c.EnableIndex {
|
if delegationTarget.UnprotectedHandler() == nil && c.EnableIndex {
|
||||||
s.Handler.PostGoRestfulMux.NotFoundHandler(routes.IndexLister{
|
s.Handler.NonGoRestfulMux.NotFoundHandler(routes.IndexLister{
|
||||||
StatusCode: http.StatusNotFound,
|
StatusCode: http.StatusNotFound,
|
||||||
PathProvider: s.listedPathProvider,
|
PathProvider: s.listedPathProvider,
|
||||||
})
|
})
|
||||||
@@ -478,22 +479,22 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
|
|||||||
|
|
||||||
func installAPI(s *GenericAPIServer, c *Config) {
|
func installAPI(s *GenericAPIServer, c *Config) {
|
||||||
if c.EnableIndex {
|
if c.EnableIndex {
|
||||||
routes.Index{}.Install(s.listedPathProvider, s.Handler.PostGoRestfulMux)
|
routes.Index{}.Install(s.listedPathProvider, s.Handler.NonGoRestfulMux)
|
||||||
}
|
}
|
||||||
if c.SwaggerConfig != nil && c.EnableSwaggerUI {
|
if c.SwaggerConfig != nil && c.EnableSwaggerUI {
|
||||||
routes.SwaggerUI{}.Install(s.Handler.PostGoRestfulMux)
|
routes.SwaggerUI{}.Install(s.Handler.NonGoRestfulMux)
|
||||||
}
|
}
|
||||||
if c.EnableProfiling {
|
if c.EnableProfiling {
|
||||||
routes.Profiling{}.Install(s.Handler.PostGoRestfulMux)
|
routes.Profiling{}.Install(s.Handler.NonGoRestfulMux)
|
||||||
if c.EnableContentionProfiling {
|
if c.EnableContentionProfiling {
|
||||||
goruntime.SetBlockProfileRate(1)
|
goruntime.SetBlockProfileRate(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.EnableMetrics {
|
if c.EnableMetrics {
|
||||||
if c.EnableProfiling {
|
if c.EnableProfiling {
|
||||||
routes.MetricsWithReset{}.Install(s.Handler.PostGoRestfulMux)
|
routes.MetricsWithReset{}.Install(s.Handler.NonGoRestfulMux)
|
||||||
} else {
|
} else {
|
||||||
routes.DefaultMetrics{}.Install(s.Handler.PostGoRestfulMux)
|
routes.DefaultMetrics{}.Install(s.Handler.NonGoRestfulMux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
routes.Version{Version: c.Version}.Install(s.Handler.GoRestfulContainer)
|
routes.Version{Version: c.Version}.Install(s.Handler.GoRestfulContainer)
|
||||||
|
@@ -52,11 +52,11 @@ func TestNewWithDelegate(t *testing.T) {
|
|||||||
return fmt.Errorf("delegate failed healthcheck")
|
return fmt.Errorf("delegate failed healthcheck")
|
||||||
}))
|
}))
|
||||||
|
|
||||||
delegateServer, err := delegateConfig.SkipComplete().New(EmptyDelegate)
|
delegateServer, err := delegateConfig.SkipComplete().New("test", EmptyDelegate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
delegateServer.Handler.PostGoRestfulMux.HandleFunc("/foo", func(w http.ResponseWriter, _ *http.Request) {
|
delegateServer.Handler.NonGoRestfulMux.HandleFunc("/foo", func(w http.ResponseWriter, _ *http.Request) {
|
||||||
w.WriteHeader(http.StatusForbidden)
|
w.WriteHeader(http.StatusForbidden)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -81,11 +81,11 @@ func TestNewWithDelegate(t *testing.T) {
|
|||||||
return fmt.Errorf("wrapping failed healthcheck")
|
return fmt.Errorf("wrapping failed healthcheck")
|
||||||
}))
|
}))
|
||||||
|
|
||||||
wrappingServer, err := wrappingConfig.Complete().New(delegateServer)
|
wrappingServer, err := wrappingConfig.Complete().New("test", delegateServer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
wrappingServer.Handler.PostGoRestfulMux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
|
wrappingServer.Handler.NonGoRestfulMux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ func TestNewWithDelegate(t *testing.T) {
|
|||||||
"/healthz/poststarthook/generic-apiserver-start-informers",
|
"/healthz/poststarthook/generic-apiserver-start-informers",
|
||||||
"/healthz/poststarthook/wrapping-post-start-hook",
|
"/healthz/poststarthook/wrapping-post-start-hook",
|
||||||
"/healthz/wrapping-health",
|
"/healthz/wrapping-health",
|
||||||
"/swaggerapi/"
|
"/swaggerapi"
|
||||||
]
|
]
|
||||||
}`, t)
|
}`, t)
|
||||||
checkPath(server.URL+"/healthz", http.StatusInternalServerError, `[+]ping ok
|
checkPath(server.URL+"/healthz", http.StatusInternalServerError, `[+]ping ok
|
||||||
|
@@ -168,7 +168,8 @@ type DelegationTarget interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *GenericAPIServer) UnprotectedHandler() http.Handler {
|
func (s *GenericAPIServer) UnprotectedHandler() http.Handler {
|
||||||
return s.Handler.GoRestfulContainer.ServeMux
|
// when we delegate, we need the server we're delegating to choose whether or not to use gorestful
|
||||||
|
return s.Handler.Director
|
||||||
}
|
}
|
||||||
func (s *GenericAPIServer) PostStartHooks() map[string]postStartHookEntry {
|
func (s *GenericAPIServer) PostStartHooks() map[string]postStartHookEntry {
|
||||||
return s.postStartHooks
|
return s.postStartHooks
|
||||||
@@ -235,7 +236,7 @@ func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
|
|||||||
if s.openAPIConfig != nil {
|
if s.openAPIConfig != nil {
|
||||||
routes.OpenAPI{
|
routes.OpenAPI{
|
||||||
Config: s.openAPIConfig,
|
Config: s.openAPIConfig,
|
||||||
}.Install(s.Handler.GoRestfulContainer, s.Handler.PostGoRestfulMux)
|
}.Install(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.installHealthz()
|
s.installHealthz()
|
||||||
|
@@ -114,7 +114,7 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion
|
|||||||
func newMaster(t *testing.T) (*GenericAPIServer, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) {
|
func newMaster(t *testing.T) (*GenericAPIServer, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) {
|
||||||
etcdserver, config, assert := setUp(t)
|
etcdserver, config, assert := setUp(t)
|
||||||
|
|
||||||
s, err := config.Complete().New(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)
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,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(EmptyDelegate)
|
s, err := config.SkipComplete().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)
|
||||||
}
|
}
|
||||||
@@ -309,7 +309,7 @@ func TestPrepareRun(t *testing.T) {
|
|||||||
|
|
||||||
assert.NotNil(config.SwaggerConfig)
|
assert.NotNil(config.SwaggerConfig)
|
||||||
|
|
||||||
server := httptest.NewServer(s.Handler.GoRestfulContainer.ServeMux)
|
server := httptest.NewServer(s.Handler.Director)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|
||||||
@@ -347,13 +347,13 @@ func TestCustomHandlerChain(t *testing.T) {
|
|||||||
called = true
|
called = true
|
||||||
})
|
})
|
||||||
|
|
||||||
s, err := config.SkipComplete().New(EmptyDelegate)
|
s, err := config.SkipComplete().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)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Handler.PostGoRestfulMux.Handle("/nonswagger", handler)
|
s.Handler.NonGoRestfulMux.Handle("/nonswagger", handler)
|
||||||
s.Handler.PostGoRestfulMux.Handle("/secret", handler)
|
s.Handler.NonGoRestfulMux.Handle("/secret", handler)
|
||||||
|
|
||||||
type Test struct {
|
type Test struct {
|
||||||
handler http.Handler
|
handler http.Handler
|
||||||
@@ -402,7 +402,7 @@ func TestNotRestRoutesHaveAuth(t *testing.T) {
|
|||||||
kubeVersion := fakeVersion()
|
kubeVersion := fakeVersion()
|
||||||
config.Version = &kubeVersion
|
config.Version = &kubeVersion
|
||||||
|
|
||||||
s, err := config.SkipComplete().New(EmptyDelegate)
|
s, err := config.SkipComplete().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)
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
rt "runtime"
|
rt "runtime"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@@ -37,27 +38,45 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// APIServerHandlers holds the different http.Handlers used by the API server.
|
// APIServerHandlers holds the different http.Handlers used by the API server.
|
||||||
// This includes the full handler chain, the gorestful handler (used for the API) which falls through to the postGoRestful handler
|
// This includes the full handler chain, the director (which chooses between gorestful and nonGoRestful,
|
||||||
// and the postGoRestful handler (which can contain a fallthrough of its own)
|
// the gorestful handler (used for the API) which falls through to the nonGoRestful handler on unregistered paths,
|
||||||
|
// and the nonGoRestful handler (which can contain a fallthrough of its own)
|
||||||
|
// FullHandlerChain -> Director -> {GoRestfulContainer,NonGoRestfulMux} based on inspection of registered web services
|
||||||
type APIServerHandler struct {
|
type APIServerHandler struct {
|
||||||
// FullHandlerChain is the one that is eventually served with. It should include the full filter
|
// FullHandlerChain is the one that is eventually served with. It should include the full filter
|
||||||
// chain and then call the GoRestfulContainer.
|
// chain and then call the Director.
|
||||||
FullHandlerChain http.Handler
|
FullHandlerChain http.Handler
|
||||||
// The registered APIs
|
// The registered APIs. InstallAPIs uses this. Other servers probably shouldn't access this directly.
|
||||||
GoRestfulContainer *restful.Container
|
GoRestfulContainer *restful.Container
|
||||||
// PostGoRestfulMux is the final HTTP handler in the chain.
|
// NonGoRestfulMux is the final HTTP handler in the chain.
|
||||||
// It comes after all filters and the API handling
|
// It comes after all filters and the API handling
|
||||||
PostGoRestfulMux *mux.PathRecorderMux
|
// This is where other servers can attach handler to various parts of the chain.
|
||||||
|
NonGoRestfulMux *mux.PathRecorderMux
|
||||||
|
|
||||||
|
// Director is here so that we can properly handle fall through and proxy cases.
|
||||||
|
// This looks a bit bonkers, but here's what's happening. We need to have /apis handling registered in gorestful in order to have
|
||||||
|
// swagger generated for compatibility. Doing that with `/apis` as a webservice, means that it forcibly 404s (no defaulting allowed)
|
||||||
|
// all requests which are not /apis or /apis/. We need those calls to fall through behind goresful for proper delegation. Trying to
|
||||||
|
// register for a pattern which includes everything behind it doesn't work because gorestful negotiates for verbs and content encoding
|
||||||
|
// and all those things go crazy when gorestful really just needs to pass through. In addition, openapi enforces unique verb constraints
|
||||||
|
// which we don't fit into and it still muddies up swagger. Trying to switch the webservices into a route doesn't work because the
|
||||||
|
// containing webservice faces all the same problems listed above.
|
||||||
|
// This leads to the crazy thing done here. Our mux does what we need, so we'll place it in front of gorestful. It will introspect to
|
||||||
|
// decide if the the route is likely to be handled by goresful and route there if needed. Otherwise, it goes to PostGoRestful mux in
|
||||||
|
// order to handle "normal" paths and delegation. Hopefully no API consumers will ever have to deal with this level of detail. I think
|
||||||
|
// we should consider completely removing gorestful.
|
||||||
|
// Other servers should only use this opaquely to delegate to an API server.
|
||||||
|
Director http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandlerChainBuilderFn is used to wrap the GoRestfulContainer handler using the provided handler chain.
|
// HandlerChainBuilderFn is used to wrap the GoRestfulContainer handler using the provided handler chain.
|
||||||
// It is normally used to apply filtering like authentication and authorization
|
// It is normally used to apply filtering like authentication and authorization
|
||||||
type HandlerChainBuilderFn func(apiHandler http.Handler) http.Handler
|
type HandlerChainBuilderFn func(apiHandler http.Handler) http.Handler
|
||||||
|
|
||||||
func NewAPIServerHandler(contextMapper request.RequestContextMapper, s runtime.NegotiatedSerializer, handlerChainBuilder HandlerChainBuilderFn, notFoundHandler http.Handler) *APIServerHandler {
|
func NewAPIServerHandler(name string, contextMapper request.RequestContextMapper, s runtime.NegotiatedSerializer, handlerChainBuilder HandlerChainBuilderFn, notFoundHandler http.Handler) *APIServerHandler {
|
||||||
postGoRestfulMux := genericmux.NewPathRecorderMux()
|
nonGoRestfulMux := genericmux.NewPathRecorderMux(name)
|
||||||
if notFoundHandler != nil {
|
if notFoundHandler != nil {
|
||||||
postGoRestfulMux.NotFoundHandler(notFoundHandler)
|
nonGoRestfulMux.NotFoundHandler(notFoundHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
gorestfulContainer := restful.NewContainer()
|
gorestfulContainer := restful.NewContainer()
|
||||||
@@ -74,14 +93,17 @@ func NewAPIServerHandler(contextMapper request.RequestContextMapper, s runtime.N
|
|||||||
serviceErrorHandler(ctx, s, serviceErr, request, response)
|
serviceErrorHandler(ctx, s, serviceErr, request, response)
|
||||||
})
|
})
|
||||||
|
|
||||||
// register the defaultHandler for everything. This will allow an unhandled request to fall through to another handler instead of
|
director := director{
|
||||||
// ending up with a forced 404
|
name: name,
|
||||||
gorestfulContainer.Handle("/", postGoRestfulMux)
|
goRestfulContainer: gorestfulContainer,
|
||||||
|
nonGoRestfulMux: nonGoRestfulMux,
|
||||||
|
}
|
||||||
|
|
||||||
return &APIServerHandler{
|
return &APIServerHandler{
|
||||||
FullHandlerChain: handlerChainBuilder(gorestfulContainer.ServeMux),
|
FullHandlerChain: handlerChainBuilder(director),
|
||||||
GoRestfulContainer: gorestfulContainer,
|
GoRestfulContainer: gorestfulContainer,
|
||||||
PostGoRestfulMux: postGoRestfulMux,
|
NonGoRestfulMux: nonGoRestfulMux,
|
||||||
|
Director: director,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,12 +114,53 @@ func (a *APIServerHandler) ListedPaths() []string {
|
|||||||
for _, ws := range a.GoRestfulContainer.RegisteredWebServices() {
|
for _, ws := range a.GoRestfulContainer.RegisteredWebServices() {
|
||||||
handledPaths = append(handledPaths, ws.RootPath())
|
handledPaths = append(handledPaths, ws.RootPath())
|
||||||
}
|
}
|
||||||
handledPaths = append(handledPaths, a.PostGoRestfulMux.ListedPaths()...)
|
handledPaths = append(handledPaths, a.NonGoRestfulMux.ListedPaths()...)
|
||||||
sort.Strings(handledPaths)
|
sort.Strings(handledPaths)
|
||||||
|
|
||||||
return handledPaths
|
return handledPaths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type director struct {
|
||||||
|
name string
|
||||||
|
goRestfulContainer *restful.Container
|
||||||
|
nonGoRestfulMux *mux.PathRecorderMux
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d director) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
path := req.URL.Path
|
||||||
|
|
||||||
|
// check to see if our webservices want to claim this path
|
||||||
|
for _, ws := range d.goRestfulContainer.RegisteredWebServices() {
|
||||||
|
switch {
|
||||||
|
case ws.RootPath() == "/apis":
|
||||||
|
// if we are exactly /apis or /apis/, then we need special handling in loop.
|
||||||
|
// normally these are passed to the nonGoRestfulMux, but if discovery is enabled, it will go directly.
|
||||||
|
// We can't rely on a prefix match since /apis matches everything (see the big comment on Director above)
|
||||||
|
if path == "/apis" || path == "/apis/" {
|
||||||
|
glog.V(5).Infof("%v: %v %q satisfied by gorestful with webservice %v", d.name, req.Method, path, ws.RootPath())
|
||||||
|
// don't use servemux here because gorestful servemuxes get messed up when removing webservices
|
||||||
|
// TODO fix gorestful, remove TPRs, or stop using gorestful
|
||||||
|
d.goRestfulContainer.Dispatch(w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
case strings.HasPrefix(path, ws.RootPath()):
|
||||||
|
// ensure an exact match or a path boundary match
|
||||||
|
if len(path) == len(ws.RootPath()) || path[len(ws.RootPath())] == '/' {
|
||||||
|
glog.V(5).Infof("%v: %v %q satisfied by gorestful with webservice %v", d.name, req.Method, path, ws.RootPath())
|
||||||
|
// don't use servemux here because gorestful servemuxes get messed up when removing webservices
|
||||||
|
// TODO fix gorestful, remove TPRs, or stop using gorestful
|
||||||
|
d.goRestfulContainer.Dispatch(w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we didn't find a match, then we just skip gorestful altogether
|
||||||
|
glog.V(5).Infof("%v: %v %q satisfied by nonGoRestful", d.name, req.Method, path)
|
||||||
|
d.nonGoRestfulMux.ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: Unify with RecoverPanics?
|
//TODO: Unify with RecoverPanics?
|
||||||
func logStackOnRecover(s runtime.NegotiatedSerializer, panicReason interface{}, w http.ResponseWriter) {
|
func logStackOnRecover(s runtime.NegotiatedSerializer, panicReason interface{}, w http.ResponseWriter) {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
|
@@ -41,5 +41,5 @@ func (s *GenericAPIServer) installHealthz() {
|
|||||||
defer s.healthzLock.Unlock()
|
defer s.healthzLock.Unlock()
|
||||||
s.healthzCreated = true
|
s.healthzCreated = true
|
||||||
|
|
||||||
healthz.InstallHandler(s.Handler.PostGoRestfulMux, s.healthzChecks...)
|
healthz.InstallHandler(s.Handler.NonGoRestfulMux, s.healthzChecks...)
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@ go_library(
|
|||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
],
|
],
|
||||||
|
@@ -25,12 +25,17 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PathRecorderMux wraps a mux object and records the registered exposedPaths.
|
// PathRecorderMux wraps a mux object and records the registered exposedPaths.
|
||||||
type PathRecorderMux struct {
|
type PathRecorderMux struct {
|
||||||
|
// name is used for logging so you can trace requests through
|
||||||
|
name string
|
||||||
|
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
notFoundHandler http.Handler
|
notFoundHandler http.Handler
|
||||||
pathToHandler map[string]http.Handler
|
pathToHandler map[string]http.Handler
|
||||||
@@ -53,6 +58,9 @@ type PathRecorderMux struct {
|
|||||||
// pathHandler is an http.Handler that will satify requests first by exact match, then by prefix,
|
// pathHandler is an http.Handler that will satify requests first by exact match, then by prefix,
|
||||||
// then by notFoundHandler
|
// then by notFoundHandler
|
||||||
type pathHandler struct {
|
type pathHandler struct {
|
||||||
|
// muxName is used for logging so you can trace requests through
|
||||||
|
muxName string
|
||||||
|
|
||||||
// pathToHandler is a map of exactly matching request to its handler
|
// pathToHandler is a map of exactly matching request to its handler
|
||||||
pathToHandler map[string]http.Handler
|
pathToHandler map[string]http.Handler
|
||||||
|
|
||||||
@@ -72,8 +80,9 @@ type prefixHandler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewPathRecorderMux creates a new PathRecorderMux
|
// NewPathRecorderMux creates a new PathRecorderMux
|
||||||
func NewPathRecorderMux() *PathRecorderMux {
|
func NewPathRecorderMux(name string) *PathRecorderMux {
|
||||||
ret := &PathRecorderMux{
|
ret := &PathRecorderMux{
|
||||||
|
name: name,
|
||||||
pathToHandler: map[string]http.Handler{},
|
pathToHandler: map[string]http.Handler{},
|
||||||
prefixToHandler: map[string]http.Handler{},
|
prefixToHandler: map[string]http.Handler{},
|
||||||
mux: atomic.Value{},
|
mux: atomic.Value{},
|
||||||
@@ -104,6 +113,7 @@ func (m *PathRecorderMux) trackCallers(path string) {
|
|||||||
// not be consistent
|
// not be consistent
|
||||||
func (m *PathRecorderMux) refreshMuxLocked() {
|
func (m *PathRecorderMux) refreshMuxLocked() {
|
||||||
newMux := &pathHandler{
|
newMux := &pathHandler{
|
||||||
|
muxName: m.name,
|
||||||
pathToHandler: map[string]http.Handler{},
|
pathToHandler: map[string]http.Handler{},
|
||||||
prefixHandlers: []prefixHandler{},
|
prefixHandlers: []prefixHandler{},
|
||||||
notFoundHandler: http.NotFoundHandler(),
|
notFoundHandler: http.NotFoundHandler(),
|
||||||
@@ -227,17 +237,20 @@ func (m *PathRecorderMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// ServeHTTP makes it an http.Handler
|
// ServeHTTP makes it an http.Handler
|
||||||
func (h *pathHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *pathHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
if exactHandler, ok := h.pathToHandler[r.URL.Path]; ok {
|
if exactHandler, ok := h.pathToHandler[r.URL.Path]; ok {
|
||||||
|
glog.V(5).Infof("%v: %q satisfied by exact match", h.muxName, r.URL.Path)
|
||||||
exactHandler.ServeHTTP(w, r)
|
exactHandler.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, prefixHandler := range h.prefixHandlers {
|
for _, prefixHandler := range h.prefixHandlers {
|
||||||
if strings.HasPrefix(r.URL.Path, prefixHandler.prefix) {
|
if strings.HasPrefix(r.URL.Path, prefixHandler.prefix) {
|
||||||
|
glog.V(5).Infof("%v: %q satisfied by prefix %v", h.muxName, r.URL.Path, prefixHandler.prefix)
|
||||||
prefixHandler.handler.ServeHTTP(w, r)
|
prefixHandler.handler.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glog.V(5).Infof("%v: %q satisfied by NotFoundHandler", h.muxName, r.URL.Path)
|
||||||
h.notFoundHandler.ServeHTTP(w, r)
|
h.notFoundHandler.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,7 +25,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestSecretHandlers(t *testing.T) {
|
func TestSecretHandlers(t *testing.T) {
|
||||||
c := NewPathRecorderMux()
|
c := NewPathRecorderMux("test")
|
||||||
c.UnlistedHandleFunc("/secret", func(http.ResponseWriter, *http.Request) {})
|
c.UnlistedHandleFunc("/secret", func(http.ResponseWriter, *http.Request) {})
|
||||||
c.HandleFunc("/nonswagger", func(http.ResponseWriter, *http.Request) {})
|
c.HandleFunc("/nonswagger", func(http.ResponseWriter, *http.Request) {})
|
||||||
assert.NotContains(t, c.ListedPaths(), "/secret")
|
assert.NotContains(t, c.ListedPaths(), "/secret")
|
||||||
@@ -36,7 +36,7 @@ func TestUnregisterHandlers(t *testing.T) {
|
|||||||
first := 0
|
first := 0
|
||||||
second := 0
|
second := 0
|
||||||
|
|
||||||
c := NewPathRecorderMux()
|
c := NewPathRecorderMux("test")
|
||||||
s := httptest.NewServer(c)
|
s := httptest.NewServer(c)
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ func TestUnregisterHandlers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPrefixHandlers(t *testing.T) {
|
func TestPrefixHandlers(t *testing.T) {
|
||||||
c := NewPathRecorderMux()
|
c := NewPathRecorderMux("test")
|
||||||
s := httptest.NewServer(c)
|
s := httptest.NewServer(c)
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
|
@@ -475,7 +475,7 @@ NextTest:
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := config.Complete().New(server.EmptyDelegate)
|
s, err := config.Complete().New("test", server.EmptyDelegate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%q - failed creating the server: %v", title, err)
|
t.Errorf("%q - failed creating the server: %v", title, err)
|
||||||
return
|
return
|
||||||
|
@@ -130,7 +130,7 @@ func (c *Config) SkipComplete() completedConfig {
|
|||||||
|
|
||||||
// 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) {
|
||||||
genericServer, err := c.Config.GenericConfig.SkipComplete().New(delegationTarget) // completion is done in Complete, no need for a second time
|
genericServer, err := c.Config.GenericConfig.SkipComplete().New("kube-aggregator", delegationTarget) // completion is done in Complete, no need for a second time
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -174,8 +174,8 @@ func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.Deleg
|
|||||||
lister: s.lister,
|
lister: s.lister,
|
||||||
mapper: s.contextMapper,
|
mapper: s.contextMapper,
|
||||||
}
|
}
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.Handle("/apis", apisHandler)
|
s.GenericAPIServer.Handler.NonGoRestfulMux.Handle("/apis", apisHandler)
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.UnlistedHandle("/apis/", apisHandler)
|
s.GenericAPIServer.Handler.NonGoRestfulMux.UnlistedHandle("/apis/", apisHandler)
|
||||||
|
|
||||||
apiserviceRegistrationController := NewAPIServiceRegistrationController(informerFactory.Apiregistration().InternalVersion().APIServices(), kubeInformers.Core().V1().Services(), s)
|
apiserviceRegistrationController := NewAPIServiceRegistrationController(informerFactory.Apiregistration().InternalVersion().APIServices(), kubeInformers.Core().V1().Services(), s)
|
||||||
availableController := statuscontrollers.NewAvailableConditionController(
|
availableController := statuscontrollers.NewAvailableConditionController(
|
||||||
@@ -227,8 +227,8 @@ func (s *APIAggregator) AddAPIService(apiService *apiregistration.APIService, de
|
|||||||
}
|
}
|
||||||
proxyHandler.updateAPIService(apiService, destinationHost)
|
proxyHandler.updateAPIService(apiService, destinationHost)
|
||||||
s.proxyHandlers[apiService.Name] = proxyHandler
|
s.proxyHandlers[apiService.Name] = proxyHandler
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.Handle(proxyPath, proxyHandler)
|
s.GenericAPIServer.Handler.NonGoRestfulMux.Handle(proxyPath, proxyHandler)
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.UnlistedHandlePrefix(proxyPath+"/", proxyHandler)
|
s.GenericAPIServer.Handler.NonGoRestfulMux.UnlistedHandlePrefix(proxyPath+"/", proxyHandler)
|
||||||
|
|
||||||
// if we're dealing with the legacy group, we're done here
|
// if we're dealing with the legacy group, we're done here
|
||||||
if apiService.Name == legacyAPIServiceName {
|
if apiService.Name == legacyAPIServiceName {
|
||||||
@@ -250,8 +250,8 @@ func (s *APIAggregator) AddAPIService(apiService *apiregistration.APIService, de
|
|||||||
contextMapper: s.contextMapper,
|
contextMapper: s.contextMapper,
|
||||||
}
|
}
|
||||||
// aggregation is protected
|
// aggregation is protected
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.Handle(groupPath, groupDiscoveryHandler)
|
s.GenericAPIServer.Handler.NonGoRestfulMux.Handle(groupPath, groupDiscoveryHandler)
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.UnlistedHandle(groupPath+"/", groupDiscoveryHandler)
|
s.GenericAPIServer.Handler.NonGoRestfulMux.UnlistedHandle(groupPath+"/", groupDiscoveryHandler)
|
||||||
s.handledGroups.Insert(apiService.Spec.Group)
|
s.handledGroups.Insert(apiService.Spec.Group)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,8 +265,8 @@ func (s *APIAggregator) RemoveAPIService(apiServiceName string) {
|
|||||||
if apiServiceName == legacyAPIServiceName {
|
if apiServiceName == legacyAPIServiceName {
|
||||||
proxyPath = "/api"
|
proxyPath = "/api"
|
||||||
}
|
}
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.Unregister(proxyPath)
|
s.GenericAPIServer.Handler.NonGoRestfulMux.Unregister(proxyPath)
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.Unregister(proxyPath + "/")
|
s.GenericAPIServer.Handler.NonGoRestfulMux.Unregister(proxyPath + "/")
|
||||||
delete(s.proxyHandlers, apiServiceName)
|
delete(s.proxyHandlers, apiServiceName)
|
||||||
|
|
||||||
// TODO unregister group level discovery when there are no more versions for the group
|
// TODO unregister group level discovery when there are no more versions for the group
|
||||||
|
@@ -17,9 +17,13 @@ limitations under the License.
|
|||||||
package apiserver
|
package apiserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
||||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@@ -107,7 +111,7 @@ func (c *Config) SkipComplete() completedConfig {
|
|||||||
|
|
||||||
// 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(delegationTarget) // completion is done in Complete, no need for a second time
|
genericServer, err := c.Config.GenericConfig.SkipComplete().New("kube-apiextensions-server", delegationTarget) // completion is done in Complete, no need for a second time
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -130,7 +134,18 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
|
|||||||
|
|
||||||
crdClient, err := internalclientset.NewForConfig(s.GenericAPIServer.LoopbackClientConfig)
|
crdClient, err := internalclientset.NewForConfig(s.GenericAPIServer.LoopbackClientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
// it's really bad that this is leaking here, but until we can fix the test (which I'm pretty sure isn't even testing what it wants to test),
|
||||||
|
// we need to be able to move forward
|
||||||
|
kubeAPIVersions := os.Getenv("KUBE_API_VERSIONS")
|
||||||
|
if len(kubeAPIVersions) == 0 {
|
||||||
|
return nil, fmt.Errorf("failed to create clientset: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// KUBE_API_VERSIONS is used in test-update-storage-objects.sh, disabling a number of API
|
||||||
|
// groups. This leads to a nil client above and undefined behaviour further down.
|
||||||
|
//
|
||||||
|
// TODO: get rid of KUBE_API_VERSIONS or define sane behaviour if set
|
||||||
|
glog.Errorf("Failed to create clientset with KUBE_API_VERSIONS=%q. KUBE_API_VERSIONS is only for testing. Things will break.", kubeAPIVersions)
|
||||||
}
|
}
|
||||||
s.Informers = internalinformers.NewSharedInformerFactory(crdClient, 5*time.Minute)
|
s.Informers = internalinformers.NewSharedInformerFactory(crdClient, 5*time.Minute)
|
||||||
|
|
||||||
@@ -156,8 +171,8 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
|
|||||||
c.CRDRESTOptionsGetter,
|
c.CRDRESTOptionsGetter,
|
||||||
c.GenericConfig.AdmissionControl,
|
c.GenericConfig.AdmissionControl,
|
||||||
)
|
)
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.Handle("/apis", crdHandler)
|
s.GenericAPIServer.Handler.NonGoRestfulMux.Handle("/apis", crdHandler)
|
||||||
s.GenericAPIServer.Handler.PostGoRestfulMux.HandlePrefix("/apis/", crdHandler)
|
s.GenericAPIServer.Handler.NonGoRestfulMux.HandlePrefix("/apis/", crdHandler)
|
||||||
|
|
||||||
crdController := NewDiscoveryController(s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions(), versionDiscoveryHandler, groupDiscoveryHandler, c.GenericConfig.RequestContextMapper)
|
crdController := NewDiscoveryController(s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions(), versionDiscoveryHandler, groupDiscoveryHandler, c.GenericConfig.RequestContextMapper)
|
||||||
namingController := status.NewNamingConditionController(s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions(), crdClient)
|
namingController := status.NewNamingConditionController(s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions(), crdClient)
|
||||||
@@ -167,6 +182,11 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
|
|||||||
crdHandler,
|
crdHandler,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// this only happens when KUBE_API_VERSIONS is set. We must return without adding poststarthooks which would affect healthz
|
||||||
|
if crdClient == nil {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
s.GenericAPIServer.AddPostStartHook("start-apiextensions-informers", func(context genericapiserver.PostStartHookContext) error {
|
s.GenericAPIServer.AddPostStartHook("start-apiextensions-informers", func(context genericapiserver.PostStartHookContext) error {
|
||||||
s.Informers.Start(context.StopCh)
|
s.Informers.Start(context.StopCh)
|
||||||
return nil
|
return nil
|
||||||
|
@@ -90,7 +90,7 @@ func (c *Config) SkipComplete() completedConfig {
|
|||||||
|
|
||||||
// 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(genericapiserver.EmptyDelegate) // completion is done in Complete, no need for a second time
|
genericServer, err := c.Config.GenericConfig.SkipComplete().New("sample-apiserver", genericapiserver.EmptyDelegate) // completion is done in Complete, no need for a second time
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user