Add new openapi endpoint in aggregator server

This commit is contained in:
Haowei Cai 2018-02-20 09:22:25 -08:00
parent 8b38e080c4
commit 2eb3d046ce
4 changed files with 35 additions and 5 deletions

View File

@ -175,6 +175,7 @@ func ClusterRoles() []rbac.ClusterRole {
// do not expand this pattern for openapi discovery docs // do not expand this pattern for openapi discovery docs
// move to a single openapi endpoint that takes accept/accept-encoding headers // move to a single openapi endpoint that takes accept/accept-encoding headers
"/swagger.json", "/swagger-2.0.0.pb-v1", "/swagger.json", "/swagger-2.0.0.pb-v1",
"/openapi", "/openapi/*",
"/api", "/api/*", "/api", "/api/*",
"/apis", "/apis/*", "/apis", "/apis/*",
).RuleOrDie(), ).RuleOrDie(),

View File

@ -635,6 +635,8 @@ items:
- /apis - /apis
- /apis/* - /apis/*
- /healthz - /healthz
- /openapi
- /openapi/*
- /swagger-2.0.0.pb-v1 - /swagger-2.0.0.pb-v1
- /swagger.json - /swagger.json
- /swaggerapi - /swaggerapi

View File

@ -17,7 +17,7 @@ limitations under the License.
package routes package routes
import ( import (
"github.com/emicklei/go-restful" restful "github.com/emicklei/go-restful"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/apiserver/pkg/server/mux" "k8s.io/apiserver/pkg/server/mux"
@ -32,8 +32,15 @@ type OpenAPI struct {
// Install adds the SwaggerUI webservice to the given mux. // Install adds the SwaggerUI webservice to the given mux.
func (oa OpenAPI) Install(c *restful.Container, mux *mux.PathRecorderMux) { func (oa OpenAPI) Install(c *restful.Container, mux *mux.PathRecorderMux) {
// NOTE: [DEPRECATION] We will announce deprecation for format-separated endpoints for OpenAPI spec,
// and switch to a single /openapi/v2 endpoint in Kubernetes 1.10. The design doc and deprecation process
// are tracked at: https://docs.google.com/document/d/19lEqE9lc4yHJ3WJAJxS_G7TcORIJXGHyq3wpwcH28nU.
_, err := handler.BuildAndRegisterOpenAPIService("/swagger.json", c.RegisteredWebServices(), oa.Config, mux) _, err := handler.BuildAndRegisterOpenAPIService("/swagger.json", c.RegisteredWebServices(), oa.Config, mux)
if err != nil { if err != nil {
glog.Fatalf("Failed to register open api spec for root: %v", err) glog.Fatalf("Failed to register open api spec for root: %v", err)
} }
_, err = handler.BuildAndRegisterOpenAPIVersionedService("/openapi/v2", c.RegisteredWebServices(), oa.Config, mux)
if err != nil {
glog.Fatalf("Failed to register versioned open api spec for root: %v", err)
}
} }

View File

@ -23,7 +23,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/emicklei/go-restful" restful "github.com/emicklei/go-restful"
"github.com/go-openapi/spec" "github.com/go-openapi/spec"
"k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server"
@ -51,7 +51,8 @@ type specAggregator struct {
openAPISpecs map[string]*openAPISpecInfo openAPISpecs map[string]*openAPISpecInfo
// provided for dynamic OpenAPI spec // provided for dynamic OpenAPI spec
openAPIService *handler.OpenAPIService openAPIService *handler.OpenAPIService
openAPIVersionedService *handler.OpenAPIService
} }
var _ AggregationManager = &specAggregator{} var _ AggregationManager = &specAggregator{}
@ -109,11 +110,19 @@ func BuildAndRegisterAggregator(downloader *Downloader, delegationTarget server.
} }
// Install handler // Install handler
// NOTE: [DEPRECATION] We will announce deprecation for format-separated endpoints for OpenAPI spec,
// and switch to a single /openapi/v2 endpoint in Kubernetes 1.10. The design doc and deprecation process
// are tracked at: https://docs.google.com/document/d/19lEqE9lc4yHJ3WJAJxS_G7TcORIJXGHyq3wpwcH28nU.
s.openAPIService, err = handler.RegisterOpenAPIService( s.openAPIService, err = handler.RegisterOpenAPIService(
specToServe, "/swagger.json", pathHandler) specToServe, "/swagger.json", pathHandler)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.openAPIVersionedService, err = handler.RegisterOpenAPIVersionedService(
specToServe, "/openapi/v2", pathHandler)
if err != nil {
return nil, err
}
return s, nil return s, nil
} }
@ -207,14 +216,25 @@ func (s *specAggregator) buildOpenAPISpec() (specToReturn *spec.Swagger, err err
// updateOpenAPISpec aggregates all OpenAPI specs. It is not thread-safe. The caller is responsible to hold proper locks. // updateOpenAPISpec aggregates all OpenAPI specs. It is not thread-safe. The caller is responsible to hold proper locks.
func (s *specAggregator) updateOpenAPISpec() error { func (s *specAggregator) updateOpenAPISpec() error {
if s.openAPIService == nil { if s.openAPIService == nil || s.openAPIVersionedService == nil {
// openAPIVersionedService and deprecated openAPIService should be initialized together
if !(s.openAPIService == nil && s.openAPIVersionedService == nil) {
return fmt.Errorf("unexpected openapi service initialization error")
}
return nil return nil
} }
specToServe, err := s.buildOpenAPISpec() specToServe, err := s.buildOpenAPISpec()
if err != nil { if err != nil {
return err return err
} }
return s.openAPIService.UpdateSpec(specToServe) // openAPIService.UpdateSpec and openAPIVersionedService.UpdateSpec read the same swagger spec
// serially and update their local caches separately. Both endpoints will have same spec in
// their caches if the caller is holding proper locks.
err = s.openAPIService.UpdateSpec(specToServe)
if err != nil {
return err
}
return s.openAPIVersionedService.UpdateSpec(specToServe)
} }
// tryUpdatingServiceSpecs tries updating openAPISpecs map with specified specInfo, and keeps the map intact // tryUpdatingServiceSpecs tries updating openAPISpecs map with specified specInfo, and keeps the map intact