Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cca05af

Browse files
author
Dr. Stefan Schimanski
committed
Move swagger+openapi setup to routes and decouple from run
1 parent 77c53fd commit cca05af

13 files changed

Lines changed: 218 additions & 119 deletions

File tree

cmd/kube-apiserver/app/server.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import (
4242
"k8s.io/kubernetes/pkg/apis/extensions"
4343
"k8s.io/kubernetes/pkg/apiserver"
4444
"k8s.io/kubernetes/pkg/apiserver/authenticator"
45-
"k8s.io/kubernetes/pkg/apiserver/openapi"
4645
authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union"
4746
"k8s.io/kubernetes/pkg/auth/user"
4847
"k8s.io/kubernetes/pkg/capabilities"
@@ -307,7 +306,6 @@ func Run(s *options.APIServer) error {
307306
genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
308307
genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
309308
genericConfig.OpenAPIConfig.Definitions = generatedopenapi.OpenAPIDefinitions
310-
genericConfig.OpenAPIConfig.GetOperationID = openapi.GetOperationID
311309
genericConfig.EnableOpenAPISupport = true
312310
genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions
313311

@@ -339,6 +337,6 @@ func Run(s *options.APIServer) error {
339337
}
340338

341339
sharedInformers.Start(wait.NeverStop)
342-
m.GenericAPIServer.Run()
340+
m.GenericAPIServer.PrepareRun().Run()
343341
return nil
344342
}

examples/apiserver/apiserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,6 @@ func Run(serverOptions *genericoptions.ServerRunOptions) error {
105105
if err := s.InstallAPIGroup(&apiGroupInfo); err != nil {
106106
return fmt.Errorf("Error in installing API: %v", err)
107107
}
108-
s.Run()
108+
s.PrepareRun().Run()
109109
return nil
110110
}

federation/cmd/federation-apiserver/app/server.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import (
3333
"k8s.io/kubernetes/pkg/api"
3434
"k8s.io/kubernetes/pkg/api/unversioned"
3535
"k8s.io/kubernetes/pkg/apiserver/authenticator"
36-
apiserveropenapi "k8s.io/kubernetes/pkg/apiserver/openapi"
3736
authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union"
3837
"k8s.io/kubernetes/pkg/auth/user"
3938
"k8s.io/kubernetes/pkg/controller/informers"
@@ -196,9 +195,6 @@ func Run(s *options.ServerRunOptions) error {
196195
genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource
197196
genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
198197
genericConfig.OpenAPIConfig.Definitions = openapi.OpenAPIDefinitions
199-
// Reusing api-server's GetOperationID function. if federation and api-server spec diverge and
200-
// this method does not provide good operation IDs for federation, we should create federation's own GetOperationID.
201-
genericConfig.OpenAPIConfig.GetOperationID = apiserveropenapi.GetOperationID
202198
genericConfig.EnableOpenAPISupport = true
203199
genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions
204200

@@ -231,7 +227,7 @@ func Run(s *options.ServerRunOptions) error {
231227
installExtensionsAPIs(m, restOptionsFactory)
232228

233229
sharedInformers.Start(wait.NeverStop)
234-
m.Run()
230+
m.PrepareRun().Run()
235231
return nil
236232
}
237233

pkg/genericapiserver/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"k8s.io/kubernetes/pkg/api"
3838
"k8s.io/kubernetes/pkg/api/unversioned"
3939
apiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters"
40+
apiserveropenapi "k8s.io/kubernetes/pkg/apiserver/openapi"
4041
"k8s.io/kubernetes/pkg/apiserver/request"
4142
"k8s.io/kubernetes/pkg/auth/authenticator"
4243
"k8s.io/kubernetes/pkg/auth/authorizer"
@@ -222,6 +223,7 @@ func NewConfig() *Config {
222223
Description: "Default Response.",
223224
},
224225
},
226+
GetOperationID: apiserveropenapi.GetOperationID,
225227
},
226228
LongRunningFunc: genericfilters.BasicLongRunningRequestCheck(longRunningRE, map[string]string{"watch": "true"}),
227229
}

pkg/genericapiserver/genericapiserver.go

Lines changed: 14 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ import (
3030

3131
systemd "github.com/coreos/go-systemd/daemon"
3232
"github.com/emicklei/go-restful"
33-
"github.com/emicklei/go-restful/swagger"
3433
"github.com/golang/glog"
3534

36-
"github.com/go-openapi/spec"
3735
"k8s.io/kubernetes/pkg/admission"
3836
"k8s.io/kubernetes/pkg/api"
3937
"k8s.io/kubernetes/pkg/api/rest"
@@ -43,8 +41,8 @@ import (
4341
"k8s.io/kubernetes/pkg/apiserver"
4442
"k8s.io/kubernetes/pkg/client/restclient"
4543
genericmux "k8s.io/kubernetes/pkg/genericapiserver/mux"
46-
"k8s.io/kubernetes/pkg/genericapiserver/openapi"
4744
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
45+
"k8s.io/kubernetes/pkg/genericapiserver/routes"
4846
"k8s.io/kubernetes/pkg/runtime"
4947
certutil "k8s.io/kubernetes/pkg/util/cert"
5048
utilnet "k8s.io/kubernetes/pkg/util/net"
@@ -151,9 +149,6 @@ type GenericAPIServer struct {
151149

152150
// See Config.$name for documentation of these flags:
153151

154-
openAPIInfo spec.Info
155-
openAPIDefaultResponse spec.Response
156-
openAPIDefinitions *common.OpenAPIDefinitions
157152
MasterCount int
158153
KubernetesServiceNodePort int // TODO(sttts): move into master
159154
ServiceReadWriteIP net.IP
@@ -179,15 +174,25 @@ func (s *GenericAPIServer) MinRequestTimeout() time.Duration {
179174
return s.minRequestTimeout
180175
}
181176

182-
func (s *GenericAPIServer) Run() {
177+
type preparedGenericAPIServer struct {
178+
*GenericAPIServer
179+
}
180+
181+
// PrepareRun does post API installation setup steps.
182+
func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
183183
// install APIs which depend on other APIs to be installed
184184
if s.enableSwaggerSupport {
185-
s.InstallSwaggerAPI()
185+
routes.Swagger{ExternalAddress: s.ExternalAddress}.Install(s.HandlerContainer)
186186
}
187187
if s.enableOpenAPISupport {
188-
s.InstallOpenAPI()
188+
routes.OpenAPI{
189+
Config: s.openAPIConfig,
190+
}.Install(s.HandlerContainer)
189191
}
192+
return preparedGenericAPIServer{s}
193+
}
190194

195+
func (s preparedGenericAPIServer) Run() {
191196
if s.SecureServingInfo != nil && s.Handler != nil {
192197
secureServer := &http.Server{
193198
Addr: s.SecureServingInfo.BindAddress,
@@ -424,60 +429,6 @@ func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV
424429
}, nil
425430
}
426431

427-
// getSwaggerConfig returns swagger config shared between SwaggerAPI and OpenAPI spec generators
428-
func (s *GenericAPIServer) getSwaggerConfig() *swagger.Config {
429-
hostAndPort := s.ExternalAddress
430-
protocol := "https://"
431-
webServicesUrl := protocol + hostAndPort
432-
return &swagger.Config{
433-
WebServicesUrl: webServicesUrl,
434-
WebServices: s.HandlerContainer.RegisteredWebServices(),
435-
ApiPath: "/swaggerapi/",
436-
SwaggerPath: "/swaggerui/",
437-
SwaggerFilePath: "/swagger-ui/",
438-
SchemaFormatHandler: func(typeName string) string {
439-
switch typeName {
440-
case "unversioned.Time", "*unversioned.Time":
441-
return "date-time"
442-
}
443-
return ""
444-
},
445-
}
446-
}
447-
448-
// InstallSwaggerAPI installs the /swaggerapi/ endpoint to allow schema discovery
449-
// and traversal. It is optional to allow consumers of the Kubernetes GenericAPIServer to
450-
// register their own web services into the Kubernetes mux prior to initialization
451-
// of swagger, so that other resource types show up in the documentation.
452-
func (s *GenericAPIServer) InstallSwaggerAPI() {
453-
// Enable swagger UI and discovery API
454-
swagger.RegisterSwaggerService(*s.getSwaggerConfig(), s.HandlerContainer.Container)
455-
}
456-
457-
// InstallOpenAPI installs spec endpoints for each web service.
458-
func (s *GenericAPIServer) InstallOpenAPI() {
459-
// Install one spec per web service, an ideal client will have a ClientSet containing one client
460-
// per each of these specs.
461-
for _, w := range s.HandlerContainer.RegisteredWebServices() {
462-
if strings.HasPrefix(w.RootPath(), "/swaggerapi") {
463-
continue
464-
}
465-
config := *s.openAPIConfig
466-
config.Info = new(spec.Info)
467-
*config.Info = *s.openAPIConfig.Info
468-
config.Info.Title = config.Info.Title + " " + w.RootPath()
469-
err := openapi.RegisterOpenAPIService(w.RootPath()+"/swagger.json", []*restful.WebService{w}, &config, s.HandlerContainer.Container)
470-
if err != nil {
471-
glog.Fatalf("Failed to register open api spec for %v: %v", w.RootPath(), err)
472-
}
473-
}
474-
err := openapi.RegisterOpenAPIService("/swagger.json", s.HandlerContainer.RegisteredWebServices(), s.openAPIConfig, s.HandlerContainer.Container)
475-
476-
if err != nil {
477-
glog.Fatalf("Failed to register open api spec for root: %v", err)
478-
}
479-
}
480-
481432
// DynamicApisDiscovery returns a webservice serving api group discovery.
482433
// Note: during the server runtime apiGroupsForDiscovery might change.
483434
func (s *GenericAPIServer) DynamicApisDiscovery() *restful.WebService {

pkg/genericapiserver/genericapiserver_test.go

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ import (
3636
"k8s.io/kubernetes/pkg/apis/extensions"
3737
"k8s.io/kubernetes/pkg/auth/authorizer"
3838
"k8s.io/kubernetes/pkg/auth/user"
39-
genericmux "k8s.io/kubernetes/pkg/genericapiserver/mux"
39+
openapigen "k8s.io/kubernetes/pkg/generated/openapi"
4040
ipallocator "k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
4141
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
4242
"k8s.io/kubernetes/pkg/util/sets"
4343
"k8s.io/kubernetes/pkg/version"
4444

45+
"github.com/go-openapi/spec"
4546
"github.com/stretchr/testify/assert"
4647
)
4748

@@ -54,6 +55,16 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion
5455
config.RequestContextMapper = api.NewRequestContextMapper()
5556
config.LegacyAPIGroupPrefixes = sets.NewString("/api")
5657

58+
config.EnableOpenAPISupport = true
59+
config.EnableSwaggerSupport = true
60+
config.OpenAPIConfig.Definitions = openapigen.OpenAPIDefinitions
61+
config.OpenAPIConfig.Info = &spec.Info{
62+
InfoProps: spec.InfoProps{
63+
Title: "Kubernetes",
64+
Version: "unversioned",
65+
},
66+
}
67+
5768
return etcdServer, *config, assert.New(t)
5869
}
5970

@@ -142,6 +153,29 @@ func TestInstallAPIGroups(t *testing.T) {
142153
}
143154
}
144155

156+
func TestPrepareRun(t *testing.T) {
157+
s, etcdserver, config, assert := newMaster(t)
158+
defer etcdserver.Terminate(t)
159+
160+
assert.True(config.EnableSwaggerSupport)
161+
assert.True(config.EnableOpenAPISupport)
162+
163+
server := httptest.NewServer(s.HandlerContainer.ServeMux)
164+
defer server.Close()
165+
166+
s.PrepareRun()
167+
168+
// openapi is installed in PrepareRun
169+
resp, err := http.Get(server.URL + "/swagger.json")
170+
assert.NoError(err)
171+
assert.Equal(http.StatusOK, resp.StatusCode)
172+
173+
// swagger is installed in PrepareRun
174+
resp, err = http.Get(server.URL + "/swaggerapi/")
175+
assert.NoError(err)
176+
assert.Equal(http.StatusOK, resp.StatusCode)
177+
}
178+
145179
// TestCustomHandlerChain verifies the handler chain with custom handler chain builder functions.
146180
func TestCustomHandlerChain(t *testing.T) {
147181
etcdserver, config, _ := setUp(t)
@@ -266,41 +300,6 @@ func (authn *mockAuthenticator) AuthenticateRequest(req *http.Request) (user.Inf
266300
}, true, nil
267301
}
268302

269-
// TestInstallSwaggerAPI verifies that the swagger api is added
270-
// at the proper endpoint.
271-
func TestInstallSwaggerAPI(t *testing.T) {
272-
etcdserver, _, assert := setUp(t)
273-
defer etcdserver.Terminate(t)
274-
275-
mux := http.NewServeMux()
276-
server := &GenericAPIServer{}
277-
server.HandlerContainer = genericmux.NewAPIContainer(mux, nil)
278-
279-
// Ensure swagger isn't installed without the call
280-
ws := server.HandlerContainer.RegisteredWebServices()
281-
if !assert.Equal(len(ws), 0) {
282-
for x := range ws {
283-
assert.NotEqual("/swaggerapi", ws[x].RootPath(), "SwaggerAPI was installed without a call to InstallSwaggerAPI()")
284-
}
285-
}
286-
287-
// Install swagger and test
288-
server.InstallSwaggerAPI()
289-
ws = server.HandlerContainer.RegisteredWebServices()
290-
if assert.NotEqual(0, len(ws), "SwaggerAPI not installed.") {
291-
assert.Equal("/swaggerapi/", ws[0].RootPath(), "SwaggerAPI did not install to the proper path. %s != /swaggerapi", ws[0].RootPath())
292-
}
293-
294-
// Empty externalHost verification
295-
mux = http.NewServeMux()
296-
server.HandlerContainer = genericmux.NewAPIContainer(mux, nil)
297-
server.ExternalAddress = ""
298-
server.InstallSwaggerAPI()
299-
if assert.NotEqual(0, len(ws), "SwaggerAPI not installed.") {
300-
assert.Equal("/swaggerapi/", ws[0].RootPath(), "SwaggerAPI did not install to the proper path. %s != /swaggerapi", ws[0].RootPath())
301-
}
302-
}
303-
304303
func decodeResponse(resp *http.Response, obj interface{}) error {
305304
defer resp.Body.Close()
306305

@@ -385,8 +384,7 @@ func TestGetServerAddressByClientCIDRs(t *testing.T) {
385384

386385
publicAddressCIDRMap := []unversioned.ServerAddressByClientCIDR{
387386
{
388-
ClientCIDR: "0.0.0.0/0",
389-
387+
ClientCIDR: "0.0.0.0/0",
390388
ServerAddress: s.ExternalAddress,
391389
},
392390
}

pkg/genericapiserver/openapi/openapi.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/emicklei/go-restful"
2626
"github.com/go-openapi/spec"
2727

28+
genericmux "k8s.io/kubernetes/pkg/genericapiserver/mux"
2829
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
2930
"k8s.io/kubernetes/pkg/util"
3031
"k8s.io/kubernetes/pkg/util/json"
@@ -42,7 +43,7 @@ type openAPI struct {
4243
}
4344

4445
// RegisterOpenAPIService registers a handler to provides standard OpenAPI specification.
45-
func RegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *common.Config, containers *restful.Container) (err error) {
46+
func RegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *common.Config, container *genericmux.APIContainer) (err error) {
4647
o := openAPI{
4748
config: config,
4849
servePath: servePath,
@@ -61,7 +62,7 @@ func RegisterOpenAPIService(servePath string, webServices []*restful.WebService,
6162
return err
6263
}
6364

64-
containers.ServeMux.HandleFunc(servePath, func(w http.ResponseWriter, r *http.Request) {
65+
container.SecretRoutes.HandleFunc(servePath, func(w http.ResponseWriter, r *http.Request) {
6566
resp := restful.NewResponse(w)
6667
if r.URL.Path != servePath {
6768
resp.WriteErrorString(http.StatusNotFound, "Path not found!")
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
Copyright 2016 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package routes
18+
19+
import (
20+
"strings"
21+
22+
"k8s.io/kubernetes/pkg/genericapiserver/mux"
23+
"k8s.io/kubernetes/pkg/genericapiserver/openapi"
24+
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
25+
26+
"github.com/emicklei/go-restful"
27+
"github.com/go-openapi/spec"
28+
"github.com/golang/glog"
29+
)
30+
31+
// OpenAPI installs spec endpoints for each web service.
32+
type OpenAPI struct {
33+
Config *common.Config
34+
}
35+
36+
// Install adds the SwaggerUI webservice to the given mux.
37+
func (oa OpenAPI) Install(c *mux.APIContainer) {
38+
// Install one spec per web service, an ideal client will have a ClientSet containing one client
39+
// per each of these specs.
40+
for _, w := range c.RegisteredWebServices() {
41+
if strings.HasPrefix(w.RootPath(), "/swaggerapi") {
42+
continue
43+
}
44+
45+
config := *oa.Config
46+
config.Info = new(spec.Info)
47+
*config.Info = *oa.Config.Info
48+
config.Info.Title = config.Info.Title + " " + w.RootPath()
49+
err := openapi.RegisterOpenAPIService(w.RootPath()+"/swagger.json", []*restful.WebService{w}, &config, c)
50+
if err != nil {
51+
glog.Fatalf("Failed to register open api spec for %v: %v", w.RootPath(), err)
52+
}
53+
}
54+
err := openapi.RegisterOpenAPIService("/swagger.json", c.RegisteredWebServices(), oa.Config, c)
55+
if err != nil {
56+
glog.Fatalf("Failed to register open api spec for root: %v", err)
57+
}
58+
}

0 commit comments

Comments
 (0)