Merge pull request #74098 from roycaihw/genericapiserver-openapi-service

genericapiserver: expose openapi service to allow updating the served spec
pull/564/head
Kubernetes Prow Robot 2019-02-15 12:43:56 -08:00 committed by GitHub
commit 02d1039ec3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 3 deletions

View File

@ -115,6 +115,7 @@ go_library(
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/builder:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/handler:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/util:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
],

View File

@ -25,6 +25,7 @@ import (
"time"
systemd "github.com/coreos/go-systemd/daemon"
"github.com/go-openapi/spec"
"k8s.io/klog"
"k8s.io/apimachinery/pkg/api/meta"
@ -46,6 +47,7 @@ import (
restclient "k8s.io/client-go/rest"
openapibuilder "k8s.io/kube-openapi/pkg/builder"
openapicommon "k8s.io/kube-openapi/pkg/common"
"k8s.io/kube-openapi/pkg/handler"
openapiutil "k8s.io/kube-openapi/pkg/util"
openapiproto "k8s.io/kube-openapi/pkg/util/proto"
)
@ -122,6 +124,14 @@ type GenericAPIServer struct {
// Enable swagger and/or OpenAPI if these configs are non-nil.
openAPIConfig *openapicommon.Config
// OpenAPIVersionedService controls the /openapi/v2 endpoint, and can be used to update the served spec.
// It is set during PrepareRun.
OpenAPIVersionedService *handler.OpenAPIService
// StaticOpenAPISpec is the spec derived from the restful container endpoints.
// It is set during PrepareRun.
StaticOpenAPISpec *spec.Swagger
// PostStartHooks are each called after the server has started listening, in a separate go func for each
// with no guarantee of ordering between them. The map key is a name used for error reporting.
// It may kill the process with a panic if it wishes to by returning an error.
@ -239,7 +249,7 @@ type preparedGenericAPIServer struct {
// PrepareRun does post API installation setup steps.
func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
if s.openAPIConfig != nil {
routes.OpenAPI{
s.OpenAPIVersionedService, s.StaticOpenAPISpec = routes.OpenAPI{
Config: s.openAPIConfig,
}.Install(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
}

View File

@ -31,6 +31,7 @@ import (
"testing"
"time"
"github.com/go-openapi/spec"
openapi "github.com/go-openapi/spec"
"github.com/stretchr/testify/assert"
@ -338,6 +339,46 @@ func TestPrepareRun(t *testing.T) {
assert.Equal(http.StatusOK, resp.StatusCode)
}
func TestUpdateOpenAPISpec(t *testing.T) {
s, _, assert := newMaster(t)
s.PrepareRun()
s.RunPostStartHooks(make(chan struct{}))
server := httptest.NewServer(s.Handler.Director)
defer server.Close()
// verify the static spec in record is what we currently serve
oldSpec, err := json.Marshal(s.StaticOpenAPISpec)
assert.NoError(err)
resp, err := http.Get(server.URL + "/openapi/v2")
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
body, err := ioutil.ReadAll(resp.Body)
assert.NoError(err)
assert.Equal(oldSpec, body)
resp.Body.Close()
// verify we are able to update the served spec using the exposed service
newSpec := []byte(`{"swagger":"2.0","info":{"title":"Test Updated Generic API Server Swagger","version":"v0.1.0"},"paths":null}`)
swagger := new(spec.Swagger)
err = json.Unmarshal(newSpec, swagger)
assert.NoError(err)
err = s.OpenAPIVersionedService.UpdateSpec(swagger)
assert.NoError(err)
resp, err = http.Get(server.URL + "/openapi/v2")
assert.NoError(err)
defer resp.Body.Close()
assert.Equal(http.StatusOK, resp.StatusCode)
body, err = ioutil.ReadAll(resp.Body)
assert.NoError(err)
assert.Equal(newSpec, body)
}
// TestCustomHandlerChain verifies the handler chain with custom handler chain builder functions.
func TestCustomHandlerChain(t *testing.T) {
config, _ := setUp(t)

View File

@ -27,8 +27,10 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/server/mux:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage/etcd/metrics:go_default_library",
"//vendor/github.com/emicklei/go-restful:go_default_library",
"//vendor/github.com/go-openapi/spec:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/builder:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/handler:go_default_library",
],

View File

@ -18,9 +18,11 @@ package routes
import (
restful "github.com/emicklei/go-restful"
"github.com/go-openapi/spec"
"k8s.io/klog"
"k8s.io/apiserver/pkg/server/mux"
"k8s.io/kube-openapi/pkg/builder"
"k8s.io/kube-openapi/pkg/common"
"k8s.io/kube-openapi/pkg/handler"
)
@ -31,9 +33,14 @@ type OpenAPI struct {
}
// Install adds the SwaggerUI webservice to the given mux.
func (oa OpenAPI) Install(c *restful.Container, mux *mux.PathRecorderMux) {
_, err := handler.BuildAndRegisterOpenAPIVersionedService("/openapi/v2", c.RegisteredWebServices(), oa.Config, mux)
func (oa OpenAPI) Install(c *restful.Container, mux *mux.PathRecorderMux) (*handler.OpenAPIService, *spec.Swagger) {
spec, err := builder.BuildOpenAPISpec(c.RegisteredWebServices(), oa.Config)
if err != nil {
klog.Fatalf("Failed to build open api spec for root: %v", err)
}
openAPIVersionedService, err := handler.RegisterOpenAPIVersionedService(spec, "/openapi/v2", mux)
if err != nil {
klog.Fatalf("Failed to register versioned open api spec for root: %v", err)
}
return openAPIVersionedService, spec
}