Skip to content

Commit

Permalink
Changes to improve swagger ui.
Browse files Browse the repository at this point in the history
- Separating out index, version and api handlers into independent web
  services. Moved the index handler to /welcome, version handler to
  /version and the api handler to /api,
  • Loading branch information
nikhiljindal committed Jan 9, 2015
1 parent 7bff03f commit 7e909ed
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 51 deletions.
102 changes: 76 additions & 26 deletions pkg/apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const (
// Handle returns a Handler function that exposes the provided storage interfaces
// as RESTful resources at prefix, serialized by codec, and also includes the support
// http resources.
// Note: This method is used only in tests.
func Handle(storage map[string]RESTStorage, codec runtime.Codec, root string, version string, selfLinker runtime.SelfLinker, admissionControl admission.Interface) http.Handler {
prefix := root + "/" + version
group := NewAPIGroupVersion(storage, codec, prefix, selfLinker, admissionControl)
Expand Down Expand Up @@ -122,14 +123,19 @@ func registerResourceHandlers(ws *restful.WebService, version string, path strin
// and status-code behavior
if namespaceScope {
path = "ns/{namespace}/" + path
ws.Param(ws.PathParameter("namespace", "object name and auth scope, such as for teams and projects").DataType("string"))
}
glog.V(3).Infof("Installing version=/%s, kind=/%s, path=/%s\n", version, kind, path)

ws.Route(ws.POST(path).To(h).
Doc("create a " + kind).
Operation("create" + kind).
Reads(versionedObject)) // from the request
nameParam := ws.PathParameter("name", "name of the "+kind).DataType("string")
namespaceParam := ws.PathParameter("namespace", "object name and auth scope, such as for teams and projects").DataType("string")

ws.Route(
addParamIf(
ws.POST(path).To(h).
Doc("create a "+kind).
Operation("create"+kind).
Reads(versionedObject), // from the request
namespaceParam, namespaceScope))

// TODO: This seems like a hack. Add NewList() to storage?
listKind := kind + "List"
Expand All @@ -142,31 +148,51 @@ func registerResourceHandlers(ws *restful.WebService, version string, path strin
} else {
versionedList := indirectArbitraryPointer(versionedListPtr)
glog.V(3).Infoln("type: ", reflect.TypeOf(versionedList))
ws.Route(ws.GET(path).To(h).
Doc("list objects of kind "+kind).
Operation("list"+kind).
Returns(http.StatusOK, "OK", versionedList))
ws.Route(
addParamIf(
ws.GET(path).To(h).
Doc("list objects of kind "+kind).
Operation("list"+kind).
Returns(http.StatusOK, "OK", versionedList),
namespaceParam, namespaceScope))
}
}

ws.Route(ws.GET(path + "/{name}").To(h).
Doc("read the specified " + kind).
Operation("read" + kind).
Param(ws.PathParameter("name", "name of the "+kind).DataType("string")).
Writes(versionedObject)) // on the response

ws.Route(ws.PUT(path + "/{name}").To(h).
Doc("update the specified " + kind).
Operation("update" + kind).
Param(ws.PathParameter("name", "name of the "+kind).DataType("string")).
Reads(versionedObject)) // from the request
ws.Route(
addParamIf(
ws.GET(path+"/{name}").To(h).
Doc("read the specified "+kind).
Operation("read"+kind).
Param(nameParam).
Writes(versionedObject), // on the response
namespaceParam, namespaceScope))

ws.Route(
addParamIf(
ws.PUT(path+"/{name}").To(h).
Doc("update the specified "+kind).
Operation("update"+kind).
Param(nameParam).
Reads(versionedObject), // from the request
namespaceParam, namespaceScope))

// TODO: Support PATCH

ws.Route(ws.DELETE(path + "/{name}").To(h).
Doc("delete the specified " + kind).
Operation("delete" + kind).
Param(ws.PathParameter("name", "name of the "+kind).DataType("string")))
ws.Route(
addParamIf(
ws.DELETE(path+"/{name}").To(h).
Doc("delete the specified "+kind).
Operation("delete"+kind).
Param(nameParam),
namespaceParam, namespaceScope))
}

// Adds the given param to the given route builder if shouldAdd is true. Does nothing if shouldAdd is false.
func addParamIf(b *restful.RouteBuilder, parameter *restful.Parameter, shouldAdd bool) *restful.RouteBuilder {
if !shouldAdd {
return b
}
return b.Param(parameter)
}

// InstallREST registers the REST handlers (storage, watch, and operations) into a restful Container.
Expand Down Expand Up @@ -266,8 +292,16 @@ func InstallValidator(mux Mux, servers func() map[string]Server) {
func InstallSupport(container *restful.Container, ws *restful.WebService) {
// TODO: convert healthz to restful and remove container arg
healthz.InstallHandler(container.ServeMux)
ws.Route(ws.GET("/").To(handleIndex))
ws.Route(ws.GET("/version").To(handleVersion))

// Set up a service to return the git code version.
ws.Path("/version")
ws.Doc("git code version from which this is built")
ws.Route(
ws.GET("/").To(handleVersion).
Doc("get the code version").
Operation("getCodeVersion").
Produces(restful.MIME_JSON).
Consumes(restful.MIME_JSON))
}

// InstallLogsSupport registers the APIServer log support function into a mux.
Expand All @@ -277,6 +311,22 @@ func InstallLogsSupport(mux Mux) {
mux.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/"))))
}

// Adds a service to return the supported api versions.
func AddApiWebService(container *restful.Container, apiPrefix string, versions []string) {
// TODO: InstallREST should register each version automatically

versionHandler := APIVersionHandler(versions[:]...)
getApiVersionsWebService := new(restful.WebService)
getApiVersionsWebService.Path(apiPrefix)
getApiVersionsWebService.Doc("get available api versions")
getApiVersionsWebService.Route(getApiVersionsWebService.GET("/").To(versionHandler).
Doc("get available api versions").
Operation("getApiVersions").
Produces(restful.MIME_JSON).
Consumes(restful.MIME_JSON))
container.Add(getApiVersionsWebService)
}

// handleVersion writes the server's version information.
func handleVersion(req *restful.Request, resp *restful.Response) {
// TODO: use restful's Response methods
Expand Down
16 changes: 3 additions & 13 deletions pkg/apiserver/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,11 @@ limitations under the License.
package apiserver

import (
"fmt"
"io"
"net/http"

"github.com/emicklei/go-restful"
)

// handleIndex is the root index page for Kubernetes.
func handleIndex(req *restful.Request, resp *restful.Response) {
// TODO: use restful's Request/Response methods
if req.Request.URL.Path != "/" && req.Request.URL.Path != "/index.html" {
notFound(resp.ResponseWriter, req.Request)
return
}
resp.ResponseWriter.WriteHeader(http.StatusOK)
// TODO: serve this out of a file
data := "<html><body>Welcome to Kubernetes</body></html>"
fmt.Fprint(resp.ResponseWriter, data)
func HandleIndex(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "<html><body>Welcome to Kubernetes</body></html>")
}
15 changes: 8 additions & 7 deletions pkg/master/master.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,27 +357,28 @@ func (m *Master) init(c *Config) {
"bindings": binding.NewREST(m.bindingRegistry),
}

versionHandler := apiserver.APIVersionHandler("v1beta1", "v1beta2")

apiVersions := []string{"v1beta1", "v1beta2"}
apiserver.NewAPIGroupVersion(m.API_v1beta1()).InstallREST(m.handlerContainer, c.APIPrefix, "v1beta1")
apiserver.NewAPIGroupVersion(m.API_v1beta2()).InstallREST(m.handlerContainer, c.APIPrefix, "v1beta2")
if c.EnableV1Beta3 {
apiserver.NewAPIGroupVersion(m.API_v1beta3()).InstallREST(m.handlerContainer, c.APIPrefix, "v1beta3")
versionHandler = apiserver.APIVersionHandler("v1beta1", "v1beta2", "v1beta3")
apiVersions = []string{"v1beta1", "v1beta2", "v1beta3"}
}

// TODO: InstallREST should register each version automatically
m.rootWebService.Route(m.rootWebService.GET(c.APIPrefix).To(versionHandler))

apiserver.InstallSupport(m.handlerContainer, m.rootWebService)
apiserver.AddApiWebService(m.handlerContainer, c.APIPrefix, apiVersions)

// Register root handler.
// We do not register this using restful Webservice since we do not want to surface this in api docs.
m.mux.HandleFunc("/", apiserver.HandleIndex)

// TODO: use go-restful
apiserver.InstallValidator(m.mux, func() map[string]apiserver.Server { return m.getServersToValidate(c) })
if c.EnableLogsSupport {
apiserver.InstallLogsSupport(m.mux)
}
if c.EnableUISupport {
ui.InstallSupport(m.mux)
ui.InstallSupport(m.mux, m.enableSwaggerSupport)
}

// TODO: install runtime/pprof handler
Expand Down
12 changes: 7 additions & 5 deletions pkg/ui/installsupport.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ type MuxInterface interface {
Handle(pattern string, handler http.Handler)
}

func InstallSupport(mux MuxInterface) {
func InstallSupport(mux MuxInterface, enableSwaggerSupport bool) {
// Expose files in www/ on <host>/static/
fileServer := http.FileServer(&assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "www"})
prefix := "/static/"
mux.Handle(prefix, http.StripPrefix(prefix, fileServer))

// Expose files in third_party/swagger-ui/ on <host>/swagger-ui/
fileServer = http.FileServer(&assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "third_party/swagger-ui"})
prefix = "/swagger-ui/"
mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
if enableSwaggerSupport {
// Expose files in third_party/swagger-ui/ on <host>/swagger-ui
fileServer = http.FileServer(&assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "third_party/swagger-ui"})
prefix = "/swagger-ui/"
mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
}
}

0 comments on commit 7e909ed

Please sign in to comment.