mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Merge pull request #74098 from roycaihw/genericapiserver-openapi-service
genericapiserver: expose openapi service to allow updating the served spec
This commit is contained in:
commit
02d1039ec3
@ -115,6 +115,7 @@ go_library(
|
|||||||
"//vendor/k8s.io/klog: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/builder:go_default_library",
|
||||||
"//vendor/k8s.io/kube-openapi/pkg/common: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:go_default_library",
|
||||||
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
|
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
|
||||||
],
|
],
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
systemd "github.com/coreos/go-systemd/daemon"
|
systemd "github.com/coreos/go-systemd/daemon"
|
||||||
|
"github.com/go-openapi/spec"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
@ -46,6 +47,7 @@ import (
|
|||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
openapibuilder "k8s.io/kube-openapi/pkg/builder"
|
openapibuilder "k8s.io/kube-openapi/pkg/builder"
|
||||||
openapicommon "k8s.io/kube-openapi/pkg/common"
|
openapicommon "k8s.io/kube-openapi/pkg/common"
|
||||||
|
"k8s.io/kube-openapi/pkg/handler"
|
||||||
openapiutil "k8s.io/kube-openapi/pkg/util"
|
openapiutil "k8s.io/kube-openapi/pkg/util"
|
||||||
openapiproto "k8s.io/kube-openapi/pkg/util/proto"
|
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.
|
// Enable swagger and/or OpenAPI if these configs are non-nil.
|
||||||
openAPIConfig *openapicommon.Config
|
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
|
// 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.
|
// 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.
|
// 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.
|
// PrepareRun does post API installation setup steps.
|
||||||
func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
|
func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
|
||||||
if s.openAPIConfig != nil {
|
if s.openAPIConfig != nil {
|
||||||
routes.OpenAPI{
|
s.OpenAPIVersionedService, s.StaticOpenAPISpec = routes.OpenAPI{
|
||||||
Config: s.openAPIConfig,
|
Config: s.openAPIConfig,
|
||||||
}.Install(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
|
}.Install(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-openapi/spec"
|
||||||
openapi "github.com/go-openapi/spec"
|
openapi "github.com/go-openapi/spec"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@ -338,6 +339,46 @@ func TestPrepareRun(t *testing.T) {
|
|||||||
assert.Equal(http.StatusOK, resp.StatusCode)
|
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.
|
// TestCustomHandlerChain verifies the handler chain with custom handler chain builder functions.
|
||||||
func TestCustomHandlerChain(t *testing.T) {
|
func TestCustomHandlerChain(t *testing.T) {
|
||||||
config, _ := setUp(t)
|
config, _ := setUp(t)
|
||||||
|
@ -27,8 +27,10 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/server/mux:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/server/mux:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/etcd/metrics: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/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/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||||
"//vendor/k8s.io/klog: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/common:go_default_library",
|
||||||
"//vendor/k8s.io/kube-openapi/pkg/handler:go_default_library",
|
"//vendor/k8s.io/kube-openapi/pkg/handler:go_default_library",
|
||||||
],
|
],
|
||||||
|
@ -18,9 +18,11 @@ package routes
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
restful "github.com/emicklei/go-restful"
|
restful "github.com/emicklei/go-restful"
|
||||||
|
"github.com/go-openapi/spec"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
|
|
||||||
"k8s.io/apiserver/pkg/server/mux"
|
"k8s.io/apiserver/pkg/server/mux"
|
||||||
|
"k8s.io/kube-openapi/pkg/builder"
|
||||||
"k8s.io/kube-openapi/pkg/common"
|
"k8s.io/kube-openapi/pkg/common"
|
||||||
"k8s.io/kube-openapi/pkg/handler"
|
"k8s.io/kube-openapi/pkg/handler"
|
||||||
)
|
)
|
||||||
@ -31,9 +33,14 @@ 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) (*handler.OpenAPIService, *spec.Swagger) {
|
||||||
_, err := handler.BuildAndRegisterOpenAPIVersionedService("/openapi/v2", c.RegisteredWebServices(), oa.Config, mux)
|
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 {
|
if err != nil {
|
||||||
klog.Fatalf("Failed to register versioned open api spec for root: %v", err)
|
klog.Fatalf("Failed to register versioned open api spec for root: %v", err)
|
||||||
}
|
}
|
||||||
|
return openAPIVersionedService, spec
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user