From 2eb3d046ce8b0a1b500d68d5a83fa7e575da7ca9 Mon Sep 17 00:00:00 2001 From: Haowei Cai Date: Tue, 20 Feb 2018 09:22:25 -0800 Subject: [PATCH] Add new openapi endpoint in aggregator server --- .../authorizer/rbac/bootstrappolicy/policy.go | 1 + .../testdata/cluster-roles.yaml | 2 ++ .../apiserver/pkg/server/routes/openapi.go | 9 +++++- .../pkg/controllers/openapi/aggregator.go | 28 ++++++++++++++++--- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go index cbbb3a33ae4..9aa9631d0c5 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go @@ -175,6 +175,7 @@ func ClusterRoles() []rbac.ClusterRole { // do not expand this pattern for openapi discovery docs // move to a single openapi endpoint that takes accept/accept-encoding headers "/swagger.json", "/swagger-2.0.0.pb-v1", + "/openapi", "/openapi/*", "/api", "/api/*", "/apis", "/apis/*", ).RuleOrDie(), diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml index f8fcaacb51d..dd4c027206f 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml @@ -635,6 +635,8 @@ items: - /apis - /apis/* - /healthz + - /openapi + - /openapi/* - /swagger-2.0.0.pb-v1 - /swagger.json - /swaggerapi diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go b/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go index 1bbfacf43ab..06c723d3753 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/openapi.go @@ -17,7 +17,7 @@ limitations under the License. package routes import ( - "github.com/emicklei/go-restful" + restful "github.com/emicklei/go-restful" "github.com/golang/glog" "k8s.io/apiserver/pkg/server/mux" @@ -32,8 +32,15 @@ type OpenAPI struct { // Install adds the SwaggerUI webservice to the given mux. 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) if err != nil { 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) + } } diff --git a/staging/src/k8s.io/kube-aggregator/pkg/controllers/openapi/aggregator.go b/staging/src/k8s.io/kube-aggregator/pkg/controllers/openapi/aggregator.go index c32da4cdd79..4c1f75bd6d9 100644 --- a/staging/src/k8s.io/kube-aggregator/pkg/controllers/openapi/aggregator.go +++ b/staging/src/k8s.io/kube-aggregator/pkg/controllers/openapi/aggregator.go @@ -23,7 +23,7 @@ import ( "sync" "time" - "github.com/emicklei/go-restful" + restful "github.com/emicklei/go-restful" "github.com/go-openapi/spec" "k8s.io/apiserver/pkg/server" @@ -51,7 +51,8 @@ type specAggregator struct { openAPISpecs map[string]*openAPISpecInfo // provided for dynamic OpenAPI spec - openAPIService *handler.OpenAPIService + openAPIService *handler.OpenAPIService + openAPIVersionedService *handler.OpenAPIService } var _ AggregationManager = &specAggregator{} @@ -109,11 +110,19 @@ func BuildAndRegisterAggregator(downloader *Downloader, delegationTarget server. } // 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( specToServe, "/swagger.json", pathHandler) if err != nil { return nil, err } + s.openAPIVersionedService, err = handler.RegisterOpenAPIVersionedService( + specToServe, "/openapi/v2", pathHandler) + if err != nil { + return nil, err + } 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. 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 } specToServe, err := s.buildOpenAPISpec() if err != nil { 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