mirror of https://github.com/k3s-io/k3s
Cleanup non-rest apiserver handlers
- rename MuxHelper -> PathRecorderMux - move non-rest handlers into routes packages within genericapiserver and `pkg/routes` (those from master) - move ui and logs handlers out of genericapiserver (they are not generic) - make version handler configurable (`config.EnableVersion`)pull/6/head
parent
265746af18
commit
7f78661d0b
|
@ -1,10 +1,6 @@
|
|||
{
|
||||
"swaggerVersion": "1.2",
|
||||
"apis": [
|
||||
{
|
||||
"path": "/logs",
|
||||
"description": "get log files"
|
||||
},
|
||||
{
|
||||
"path": "/version",
|
||||
"description": "git code version from which this is built"
|
||||
|
@ -13,6 +9,10 @@
|
|||
"path": "/apis",
|
||||
"description": "get available API versions"
|
||||
},
|
||||
{
|
||||
"path": "/logs",
|
||||
"description": "get log files"
|
||||
},
|
||||
{
|
||||
"path": "/api/v1",
|
||||
"description": "API at /api/v1"
|
||||
|
|
|
@ -289,6 +289,8 @@ func Run(s *options.APIServer) error {
|
|||
DeleteCollectionWorkers: s.DeleteCollectionWorkers,
|
||||
EventTTL: s.EventTTL,
|
||||
KubeletClient: kubeletClient,
|
||||
EnableUISupport: true,
|
||||
EnableLogsSupport: true,
|
||||
|
||||
Tunneler: tunneler,
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ import (
|
|||
roleetcd "k8s.io/kubernetes/pkg/registry/role/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/rolebinding"
|
||||
rolebindingetcd "k8s.io/kubernetes/pkg/registry/rolebinding/etcd"
|
||||
"k8s.io/kubernetes/pkg/routes"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
)
|
||||
|
||||
|
@ -196,6 +197,9 @@ func Run(s *options.ServerRunOptions) error {
|
|||
return err
|
||||
}
|
||||
|
||||
routes.UIRedirect{}.Install(m.Mux, m.HandlerContainer)
|
||||
routes.Logs{}.Install(m.Mux, m.HandlerContainer)
|
||||
|
||||
installFederationAPIs(s, m, storageFactory)
|
||||
installCoreAPIs(s, m, storageFactory)
|
||||
installExtensionsAPIs(s, m, storageFactory)
|
||||
|
|
|
@ -37,7 +37,7 @@ readonly SWAGGER_PKG="swagger"
|
|||
function kube::hack::build_ui() {
|
||||
local pkg="$1"
|
||||
local src="$2"
|
||||
local output_file="pkg/ui/data/${pkg}/datafile.go"
|
||||
local output_file="pkg/genericapiserver/routes/data/${pkg}/datafile.go"
|
||||
|
||||
go-bindata -nocompress -o "${output_file}" -prefix ${PWD} -pkg "${pkg}" "${src}"
|
||||
|
||||
|
|
|
@ -42,7 +42,6 @@ import (
|
|||
"k8s.io/kubernetes/pkg/util/flushwriter"
|
||||
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/wsstream"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/golang/glog"
|
||||
|
@ -52,12 +51,6 @@ func init() {
|
|||
metrics.Register()
|
||||
}
|
||||
|
||||
// mux is an object that can register http handlers.
|
||||
type Mux interface {
|
||||
Handle(pattern string, handler http.Handler)
|
||||
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
||||
}
|
||||
|
||||
type APIResourceLister interface {
|
||||
ListAPIResources() []unversioned.APIResource
|
||||
}
|
||||
|
@ -190,48 +183,6 @@ func (g *APIGroupVersion) newInstaller() *APIInstaller {
|
|||
return installer
|
||||
}
|
||||
|
||||
// TODO: document all handlers
|
||||
// InstallVersionHandler registers the APIServer's `/version` handler
|
||||
func InstallVersionHandler(mux Mux, container *restful.Container) {
|
||||
// Set up a service to return the git code version.
|
||||
versionWS := new(restful.WebService)
|
||||
versionWS.Path("/version")
|
||||
versionWS.Doc("git code version from which this is built")
|
||||
versionWS.Route(
|
||||
versionWS.GET("/").To(handleVersion).
|
||||
Doc("get the code version").
|
||||
Operation("getCodeVersion").
|
||||
Produces(restful.MIME_JSON).
|
||||
Consumes(restful.MIME_JSON).
|
||||
Writes(version.Info{}))
|
||||
|
||||
container.Add(versionWS)
|
||||
}
|
||||
|
||||
// InstallLogsSupport registers the APIServer's `/logs` into a mux.
|
||||
func InstallLogsSupport(mux Mux, container *restful.Container) {
|
||||
// use restful: ws.Route(ws.GET("/logs/{logpath:*}").To(fileHandler))
|
||||
// See github.com/emicklei/go-restful/blob/master/examples/restful-serve-static.go
|
||||
ws := new(restful.WebService)
|
||||
ws.Path("/logs")
|
||||
ws.Doc("get log files")
|
||||
ws.Route(ws.GET("/{logpath:*}").To(logFileHandler).Param(ws.PathParameter("logpath", "path to the log").DataType("string")))
|
||||
ws.Route(ws.GET("/").To(logFileListHandler))
|
||||
|
||||
container.Add(ws)
|
||||
}
|
||||
|
||||
func logFileHandler(req *restful.Request, resp *restful.Response) {
|
||||
logdir := "/var/log"
|
||||
actual := path.Join(logdir, req.PathParameter("logpath"))
|
||||
http.ServeFile(resp.ResponseWriter, req.Request, actual)
|
||||
}
|
||||
|
||||
func logFileListHandler(req *restful.Request, resp *restful.Response) {
|
||||
logdir := "/var/log"
|
||||
http.ServeFile(resp.ResponseWriter, req.Request, logdir)
|
||||
}
|
||||
|
||||
// TODO: needs to perform response type negotiation, this is probably the wrong way to recover panics
|
||||
func InstallRecoverHandler(s runtime.NegotiatedSerializer, container *restful.Container) {
|
||||
container.RecoverHandler(func(panicReason interface{}, httpWriter http.ResponseWriter) {
|
||||
|
@ -403,11 +354,6 @@ func AddSupportedResourcesWebService(s runtime.NegotiatedSerializer, ws *restful
|
|||
Writes(unversioned.APIResourceList{}))
|
||||
}
|
||||
|
||||
// handleVersion writes the server's version information.
|
||||
func handleVersion(req *restful.Request, resp *restful.Response) {
|
||||
writeRawJSON(http.StatusOK, version.Get(), resp.ResponseWriter)
|
||||
}
|
||||
|
||||
// APIVersionHandler returns a handler which will list the provided versions as available.
|
||||
func APIVersionHandler(s runtime.NegotiatedSerializer, getAPIVersionsFunc func(req *restful.Request) *unversioned.APIVersions) restful.RouteFunction {
|
||||
return func(req *restful.Request, resp *restful.Response) {
|
||||
|
@ -484,7 +430,7 @@ func writeNegotiated(s runtime.NegotiatedSerializer, gv unversioned.GroupVersion
|
|||
serializer, err := negotiateOutputSerializer(req, s)
|
||||
if err != nil {
|
||||
status := errToAPIStatus(err)
|
||||
writeRawJSON(int(status.Code), status, w)
|
||||
WriteRawJSON(int(status.Code), status, w)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -528,8 +474,8 @@ func errorJSONFatal(err error, codec runtime.Encoder, w http.ResponseWriter) int
|
|||
return code
|
||||
}
|
||||
|
||||
// writeRawJSON writes a non-API object in JSON.
|
||||
func writeRawJSON(statusCode int, object interface{}, w http.ResponseWriter) {
|
||||
// WriteRawJSON writes a non-API object in JSON.
|
||||
func WriteRawJSON(statusCode int, object interface{}, w http.ResponseWriter) {
|
||||
output, err := json.MarshalIndent(object, "", " ")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
|
|
@ -46,7 +46,6 @@ import (
|
|||
"k8s.io/kubernetes/pkg/util"
|
||||
"k8s.io/kubernetes/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
"k8s.io/kubernetes/pkg/watch/versioned"
|
||||
"k8s.io/kubernetes/plugin/pkg/admission/admit"
|
||||
|
@ -317,8 +316,6 @@ func handleInternal(storage map[string]rest.Storage, admissionControl admission.
|
|||
}
|
||||
}
|
||||
|
||||
InstallVersionHandler(mux, container)
|
||||
|
||||
return &defaultAPIServer{mux, container}
|
||||
}
|
||||
|
||||
|
@ -865,33 +862,6 @@ func TestUnimplementedRESTStorage(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
handler := handle(map[string]rest.Storage{})
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
client := http.Client{}
|
||||
|
||||
request, err := http.NewRequest("GET", server.URL+"/version", nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
var info version.Info
|
||||
err = json.NewDecoder(response.Body).Decode(&info)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(version.Get(), info) {
|
||||
t.Errorf("Expected %#v, Got %#v", version.Get(), info)
|
||||
}
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
testCases := []struct {
|
||||
url string
|
||||
|
@ -1262,9 +1232,8 @@ func TestMetadata(t *testing.T) {
|
|||
if matches["text/plain,application/json,application/yaml,application/vnd.kubernetes.protobuf"] == 0 ||
|
||||
matches["application/json,application/json;stream=watch,application/vnd.kubernetes.protobuf,application/vnd.kubernetes.protobuf;stream=watch"] == 0 ||
|
||||
matches["application/json,application/yaml,application/vnd.kubernetes.protobuf"] == 0 ||
|
||||
matches["application/json"] == 0 ||
|
||||
matches["*/*"] == 0 ||
|
||||
len(matches) != 5 {
|
||||
len(matches) != 4 {
|
||||
t.Errorf("unexpected mime types: %v", matches)
|
||||
}
|
||||
}
|
||||
|
@ -2985,7 +2954,7 @@ func (m *marshalError) MarshalJSON() ([]byte, error) {
|
|||
|
||||
func TestWriteRAWJSONMarshalError(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
writeRawJSON(http.StatusOK, &marshalError{errors.New("Undecodable")}, w)
|
||||
WriteRawJSON(http.StatusOK, &marshalError{errors.New("Undecodable")}, w)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := http.Client{}
|
||||
|
@ -3270,8 +3239,6 @@ func TestXGSubresource(t *testing.T) {
|
|||
panic(fmt.Sprintf("unable to install container %s: %v", group.GroupVersion, err))
|
||||
}
|
||||
|
||||
InstallVersionHandler(mux, container)
|
||||
|
||||
handler := defaultAPIServer{mux, container}
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apiserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Mux is an object that can register http handlers.
|
||||
type Mux interface {
|
||||
Handle(pattern string, handler http.Handler)
|
||||
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
||||
}
|
||||
|
||||
// PathRecorderMux wraps a mux object and records the registered paths. It is _not_ go routine safe.
|
||||
type PathRecorderMux struct {
|
||||
mux Mux
|
||||
paths []string
|
||||
}
|
||||
|
||||
// NewPathRecorderMux creates a new PathRecorderMux with the given mux as the base mux.
|
||||
func NewPathRecorderMux(mux Mux) *PathRecorderMux {
|
||||
return &PathRecorderMux{
|
||||
mux: mux,
|
||||
}
|
||||
}
|
||||
|
||||
// BaseMux returns the underlying mux.
|
||||
func (m *PathRecorderMux) BaseMux() Mux {
|
||||
return m.mux
|
||||
}
|
||||
|
||||
// HandledPaths returns the registered handler paths.
|
||||
func (m *PathRecorderMux) HandledPaths() []string {
|
||||
return append([]string{}, m.paths...)
|
||||
}
|
||||
|
||||
// Handle registers the handler for the given pattern.
|
||||
// If a handler already exists for pattern, Handle panics.
|
||||
func (m *PathRecorderMux) Handle(path string, handler http.Handler) {
|
||||
m.paths = append(m.paths, path)
|
||||
m.mux.Handle(path, handler)
|
||||
}
|
||||
|
||||
// HandleFunc registers the handler function for the given pattern.
|
||||
func (m *PathRecorderMux) HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) {
|
||||
m.paths = append(m.paths, path)
|
||||
m.mux.HandleFunc(path, handler)
|
||||
}
|
|
@ -19,9 +19,9 @@ package genericapiserver
|
|||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -42,12 +42,12 @@ import (
|
|||
"k8s.io/kubernetes/pkg/auth/handlers"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver/options"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver/routes"
|
||||
genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
"k8s.io/kubernetes/pkg/registry/generic/registry"
|
||||
ipallocator "k8s.io/kubernetes/pkg/registry/service/ipallocator"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/ui"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||
)
|
||||
|
@ -60,20 +60,18 @@ type Config struct {
|
|||
AuditLogMaxAge int
|
||||
AuditLogMaxBackups int
|
||||
AuditLogMaxSize int
|
||||
// allow downstream consumers to disable the core controller loops
|
||||
EnableLogsSupport bool
|
||||
EnableUISupport bool
|
||||
// Allow downstream consumers to disable swagger.
|
||||
// This includes returning the generated swagger spec at /swaggerapi and swagger ui at /swagger-ui.
|
||||
EnableSwaggerSupport bool
|
||||
// Allow downstream consumers to disable swagger ui.
|
||||
// Note that this is ignored if either EnableSwaggerSupport or EnableUISupport is false.
|
||||
// Note that this is ignored if EnableSwaggerSupport is false
|
||||
EnableSwaggerUI bool
|
||||
// Allows api group versions or specific resources to be conditionally enabled/disabled.
|
||||
APIResourceConfigSource APIResourceConfigSource
|
||||
// allow downstream consumers to disable the index route
|
||||
EnableIndex bool
|
||||
EnableProfiling bool
|
||||
EnableVersion bool
|
||||
EnableWatchCache bool
|
||||
EnableGarbageCollection bool
|
||||
APIPrefix string
|
||||
|
@ -172,11 +170,10 @@ func NewConfig(options *options.ServerRunOptions) *Config {
|
|||
AuditLogMaxSize: options.AuditLogMaxSize,
|
||||
EnableGarbageCollection: options.EnableGarbageCollection,
|
||||
EnableIndex: true,
|
||||
EnableLogsSupport: options.EnableLogsSupport,
|
||||
EnableProfiling: options.EnableProfiling,
|
||||
EnableSwaggerSupport: true,
|
||||
EnableSwaggerUI: options.EnableSwaggerUI,
|
||||
EnableUISupport: true,
|
||||
EnableVersion: true,
|
||||
EnableWatchCache: options.EnableWatchCache,
|
||||
ExternalHost: options.ExternalHost,
|
||||
KubernetesServiceNodePort: options.KubernetesServiceNodePort,
|
||||
|
@ -320,16 +317,13 @@ func (c Config) New() (*GenericAPIServer, error) {
|
|||
}
|
||||
|
||||
if c.RestfulContainer != nil {
|
||||
s.mux = c.RestfulContainer.ServeMux
|
||||
s.HandlerContainer = c.RestfulContainer
|
||||
} else {
|
||||
mux := http.NewServeMux()
|
||||
s.mux = mux
|
||||
s.HandlerContainer = NewHandlerContainer(mux, c.Serializer)
|
||||
s.HandlerContainer = NewHandlerContainer(http.NewServeMux(), c.Serializer)
|
||||
}
|
||||
// Use CurlyRouter to be able to use regular expressions in paths. Regular expressions are required in paths for example for proxy (where the path is proxy/{kind}/{name}/{*})
|
||||
s.HandlerContainer.Router(restful.CurlyRouter{})
|
||||
s.MuxHelper = &apiserver.MuxHelper{Mux: s.mux, RegisteredPaths: []string{}}
|
||||
s.Mux = apiserver.NewPathRecorderMux(s.HandlerContainer.ServeMux)
|
||||
|
||||
if c.ProxyDialer != nil || c.ProxyTLSClientConfig != nil {
|
||||
s.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{
|
||||
|
@ -338,29 +332,29 @@ func (c Config) New() (*GenericAPIServer, error) {
|
|||
})
|
||||
}
|
||||
|
||||
// Send correct mime type for .svg files.
|
||||
// TODO: remove when https://github.com/golang/go/commit/21e47d831bafb59f22b1ea8098f709677ec8ce33
|
||||
// makes it into all of our supported go versions (only in v1.7.1 now).
|
||||
mime.AddExtensionType(".svg", "image/svg+xml")
|
||||
|
||||
// Register root handler.
|
||||
// We do not register this using restful Webservice since we do not want to surface this in api docs.
|
||||
// Allow GenericAPIServer to be embedded in contexts which already have something registered at the root
|
||||
if c.EnableIndex {
|
||||
s.mux.HandleFunc("/", apiserver.IndexHandler(s.HandlerContainer, s.MuxHelper))
|
||||
routes.Index{}.Install(s.Mux, s.HandlerContainer)
|
||||
}
|
||||
|
||||
if c.EnableLogsSupport {
|
||||
apiserver.InstallLogsSupport(s.MuxHelper, s.HandlerContainer)
|
||||
if c.EnableSwaggerSupport && c.EnableSwaggerUI {
|
||||
routes.SwaggerUI{}.Install(s.Mux, s.HandlerContainer)
|
||||
}
|
||||
if c.EnableUISupport {
|
||||
ui.InstallSupport(s.MuxHelper, c.EnableSwaggerSupport && c.EnableSwaggerUI)
|
||||
}
|
||||
|
||||
if c.EnableProfiling {
|
||||
s.mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||
s.mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
s.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
routes.Profiling{}.Install(s.Mux, s.HandlerContainer)
|
||||
}
|
||||
if c.EnableVersion {
|
||||
routes.Version{}.Install(s.Mux, s.HandlerContainer)
|
||||
}
|
||||
|
||||
apiserver.InstallVersionHandler(s.MuxHelper, s.HandlerContainer)
|
||||
|
||||
handler := http.Handler(s.mux.(*http.ServeMux))
|
||||
handler := http.Handler(s.Mux.BaseMux().(*http.ServeMux))
|
||||
|
||||
// TODO: handle CORS and auth using go-restful
|
||||
// See github.com/emicklei/go-restful/blob/master/examples/restful-CORS-filter.go, and
|
||||
|
|
|
@ -123,8 +123,7 @@ type GenericAPIServer struct {
|
|||
// should be determining the backing storage for the RESTStorage interfaces
|
||||
storageDecorator generic.StorageDecorator
|
||||
|
||||
mux apiserver.Mux
|
||||
MuxHelper *apiserver.MuxHelper
|
||||
Mux *apiserver.PathRecorderMux
|
||||
HandlerContainer *restful.Container
|
||||
MasterCount int
|
||||
|
||||
|
@ -198,7 +197,7 @@ func (s *GenericAPIServer) HandleWithAuth(pattern string, handler http.Handler)
|
|||
// sensible policy defaults for plugged-in endpoints. This will be different
|
||||
// for generic endpoints versus REST object endpoints.
|
||||
// TODO: convert to go-restful
|
||||
s.MuxHelper.Handle(pattern, handler)
|
||||
s.Mux.Handle(pattern, handler)
|
||||
}
|
||||
|
||||
// HandleFuncWithAuth adds an http.Handler for pattern to an http.ServeMux
|
||||
|
@ -206,7 +205,7 @@ func (s *GenericAPIServer) HandleWithAuth(pattern string, handler http.Handler)
|
|||
// to the request is used for the GenericAPIServer's built-in endpoints.
|
||||
func (s *GenericAPIServer) HandleFuncWithAuth(pattern string, handler func(http.ResponseWriter, *http.Request)) {
|
||||
// TODO: convert to go-restful
|
||||
s.MuxHelper.HandleFunc(pattern, handler)
|
||||
s.Mux.HandleFunc(pattern, handler)
|
||||
}
|
||||
|
||||
func NewHandlerContainer(mux *http.ServeMux, s runtime.NegotiatedSerializer) *restful.Container {
|
||||
|
|
|
@ -36,6 +36,8 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
ipallocator "k8s.io/kubernetes/pkg/registry/service/ipallocator"
|
||||
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
|
||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||
|
@ -173,12 +175,11 @@ func TestHandleWithAuth(t *testing.T) {
|
|||
server, etcdserver, _, assert := setUp(t)
|
||||
defer etcdserver.Terminate(t)
|
||||
|
||||
mh := apiserver.MuxHelper{Mux: http.NewServeMux()}
|
||||
server.MuxHelper = &mh
|
||||
server.Mux = apiserver.NewPathRecorderMux(http.NewServeMux())
|
||||
handler := func(r http.ResponseWriter, w *http.Request) { w.Write(nil) }
|
||||
server.HandleWithAuth("/test", http.HandlerFunc(handler))
|
||||
|
||||
assert.Contains(server.MuxHelper.RegisteredPaths, "/test", "Path not found in MuxHelper")
|
||||
assert.Contains(server.Mux.HandledPaths(), "/test", "Path not found in MuxHelper")
|
||||
}
|
||||
|
||||
// TestHandleFuncWithAuth verifies HandleFuncWithAuth adds the path
|
||||
|
@ -187,12 +188,78 @@ func TestHandleFuncWithAuth(t *testing.T) {
|
|||
server, etcdserver, _, assert := setUp(t)
|
||||
defer etcdserver.Terminate(t)
|
||||
|
||||
mh := apiserver.MuxHelper{Mux: http.NewServeMux()}
|
||||
server.MuxHelper = &mh
|
||||
server.Mux = apiserver.NewPathRecorderMux(http.NewServeMux())
|
||||
handler := func(r http.ResponseWriter, w *http.Request) { w.Write(nil) }
|
||||
server.HandleFuncWithAuth("/test", handler)
|
||||
|
||||
assert.Contains(server.MuxHelper.RegisteredPaths, "/test", "Path not found in MuxHelper")
|
||||
assert.Contains(server.Mux.HandledPaths(), "/test", "Path not found in MuxHelper")
|
||||
}
|
||||
|
||||
// TestNotRestRoutesHaveAuth checks that special non-routes are behind authz/authn.
|
||||
func TestNotRestRoutesHaveAuth(t *testing.T) {
|
||||
_, etcdserver, config, _ := setUp(t)
|
||||
defer etcdserver.Terminate(t)
|
||||
|
||||
authz := mockAuthorizer{}
|
||||
|
||||
config.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil }
|
||||
config.ProxyTLSClientConfig = &tls.Config{}
|
||||
config.APIPrefix = "/apiPrefix"
|
||||
config.APIGroupPrefix = "/apiGroupPrefix"
|
||||
config.Serializer = api.Codecs
|
||||
config.Authorizer = &authz
|
||||
|
||||
config.EnableSwaggerUI = true
|
||||
config.EnableIndex = true
|
||||
config.EnableProfiling = true
|
||||
config.EnableSwaggerSupport = true
|
||||
config.EnableVersion = true
|
||||
|
||||
s, err := config.New()
|
||||
if err != nil {
|
||||
t.Fatalf("Error in bringing up the server: %v", err)
|
||||
}
|
||||
|
||||
for _, test := range []struct {
|
||||
route string
|
||||
}{
|
||||
{"/"},
|
||||
{"/swagger-ui/"},
|
||||
{"/debug/pprof/"},
|
||||
{"/version"},
|
||||
} {
|
||||
resp := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", test.route, nil)
|
||||
s.Handler.ServeHTTP(resp, req)
|
||||
if resp.Code != 200 {
|
||||
t.Errorf("route %q expected to work: code %d", test.route, resp.Code)
|
||||
continue
|
||||
}
|
||||
|
||||
if authz.lastURI != test.route {
|
||||
t.Errorf("route %q expected to go through authorization, last route did: %q", test.route, authz.lastURI)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type mockAuthorizer struct {
|
||||
lastURI string
|
||||
}
|
||||
|
||||
func (authz *mockAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
||||
authz.lastURI = a.GetPath()
|
||||
return true, "", nil
|
||||
}
|
||||
|
||||
type mockAuthenticator struct {
|
||||
lastURI string
|
||||
}
|
||||
|
||||
func (authn *mockAuthenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
||||
authn.lastURI = req.RequestURI
|
||||
return &user.DefaultInfo{
|
||||
Name: "foo",
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
// TestInstallSwaggerAPI verifies that the swagger api is added
|
||||
|
|
|
@ -84,7 +84,6 @@ type ServerRunOptions struct {
|
|||
AuditLogMaxBackups int
|
||||
AuditLogMaxSize int
|
||||
EnableGarbageCollection bool
|
||||
EnableLogsSupport bool
|
||||
EnableProfiling bool
|
||||
EnableSwaggerUI bool
|
||||
EnableWatchCache bool
|
||||
|
@ -135,7 +134,6 @@ func NewServerRunOptions() *ServerRunOptions {
|
|||
DefaultStorageVersions: registered.AllPreferredGroupVersions(),
|
||||
DeleteCollectionWorkers: 1,
|
||||
EnableGarbageCollection: true,
|
||||
EnableLogsSupport: true,
|
||||
EnableProfiling: true,
|
||||
EnableWatchCache: true,
|
||||
InsecureBindAddress: net.ParseIP("127.0.0.1"),
|
||||
|
|
|
@ -6,4 +6,7 @@ hack/build-ui.sh
|
|||
Do not edit by hand.
|
||||
|
||||
|
||||
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/pkg/ui/data/README.md?pixel)]()
|
||||
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/pkg/genericapiserver/addons/data/README.md?pixel)]()
|
||||
|
||||
|
||||
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/pkg/genericapiserver/routes/data/README.md?pixel)]()
|
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -14,6 +14,5 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// package ui contains utilities for accessing the static data files compiled in
|
||||
// the data/* subdirectories.
|
||||
package ui // import "k8s.io/kubernetes/pkg/ui"
|
||||
// Package routes holds a collection of optional genericapiserver http handlers.
|
||||
package routes
|
|
@ -14,19 +14,22 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apiserver
|
||||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
)
|
||||
|
||||
func IndexHandler(container *restful.Container, muxHelper *MuxHelper) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
type Index struct{}
|
||||
|
||||
func (i Index) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
||||
mux.BaseMux().HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
status := http.StatusOK
|
||||
if r.URL.Path != "/" && r.URL.Path != "/index.html" {
|
||||
// Since "/" matches all paths, handleIndex is called for all paths for which there is no handler registered.
|
||||
|
@ -35,12 +38,12 @@ func IndexHandler(container *restful.Container, muxHelper *MuxHelper) func(http.
|
|||
}
|
||||
var handledPaths []string
|
||||
// Extract the paths handled using restful.WebService
|
||||
for _, ws := range container.RegisteredWebServices() {
|
||||
for _, ws := range c.RegisteredWebServices() {
|
||||
handledPaths = append(handledPaths, ws.RootPath())
|
||||
}
|
||||
// Extract the paths handled using mux handler.
|
||||
handledPaths = append(handledPaths, muxHelper.RegisteredPaths...)
|
||||
handledPaths = append(handledPaths, mux.HandledPaths()...)
|
||||
sort.Strings(handledPaths)
|
||||
writeRawJSON(status, unversioned.RootPaths{Paths: handledPaths}, w)
|
||||
}
|
||||
apiserver.WriteRawJSON(status, unversioned.RootPaths{Paths: handledPaths}, w)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
"net/http/pprof"
|
||||
)
|
||||
|
||||
// Profiling adds handlers for pprof under /debug/pprof.
|
||||
type Profiling struct{}
|
||||
|
||||
func (d Profiling) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
||||
mux.BaseMux().HandleFunc("/debug/pprof/", pprof.Index)
|
||||
mux.BaseMux().HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
mux.BaseMux().HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver/routes/data/swagger"
|
||||
)
|
||||
|
||||
// SwaggerUI exposes files in third_party/swagger-ui/ under /swagger-ui.
|
||||
type SwaggerUI struct{}
|
||||
|
||||
func (l SwaggerUI) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
||||
fileServer := http.FileServer(&assetfs.AssetFS{
|
||||
Asset: swagger.Asset,
|
||||
AssetDir: swagger.AssetDir,
|
||||
Prefix: "third_party/swagger-ui",
|
||||
})
|
||||
prefix := "/swagger-ui/"
|
||||
mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
)
|
||||
|
||||
type Version struct{}
|
||||
|
||||
// InstallVersionHandler registers the APIServer's `/version` handler
|
||||
func (v Version) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
||||
// Set up a service to return the git code version.
|
||||
versionWS := new(restful.WebService)
|
||||
versionWS.Path("/version")
|
||||
versionWS.Doc("git code version from which this is built")
|
||||
versionWS.Route(
|
||||
versionWS.GET("/").To(handleVersion).
|
||||
Doc("get the code version").
|
||||
Operation("getCodeVersion").
|
||||
Produces(restful.MIME_JSON).
|
||||
Consumes(restful.MIME_JSON).
|
||||
Writes(version.Info{}))
|
||||
|
||||
c.Add(versionWS)
|
||||
}
|
||||
|
||||
// handleVersion writes the server's version information.
|
||||
func handleVersion(req *restful.Request, resp *restful.Response) {
|
||||
apiserver.WriteRawJSON(http.StatusOK, version.Get(), resp.ResponseWriter)
|
||||
}
|
|
@ -18,7 +18,6 @@ package master
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -52,7 +51,6 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageapiv1beta1 "k8s.io/kubernetes/pkg/apis/storage/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
apiservermetrics "k8s.io/kubernetes/pkg/apiserver/metrics"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||
"k8s.io/kubernetes/pkg/healthz"
|
||||
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
|
||||
|
@ -77,22 +75,22 @@ import (
|
|||
resourcequotaetcd "k8s.io/kubernetes/pkg/registry/resourcequota/etcd"
|
||||
secretetcd "k8s.io/kubernetes/pkg/registry/secret/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/service"
|
||||
"k8s.io/kubernetes/pkg/registry/service/allocator"
|
||||
etcdallocator "k8s.io/kubernetes/pkg/registry/service/allocator/etcd"
|
||||
serviceetcd "k8s.io/kubernetes/pkg/registry/service/etcd"
|
||||
ipallocator "k8s.io/kubernetes/pkg/registry/service/ipallocator"
|
||||
"k8s.io/kubernetes/pkg/registry/service/portallocator"
|
||||
serviceaccountetcd "k8s.io/kubernetes/pkg/registry/serviceaccount/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata"
|
||||
thirdpartyresourcedataetcd "k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata/etcd"
|
||||
"k8s.io/kubernetes/pkg/routes"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
etcdmetrics "k8s.io/kubernetes/pkg/storage/etcd/metrics"
|
||||
etcdutil "k8s.io/kubernetes/pkg/storage/etcd/util"
|
||||
"k8s.io/kubernetes/pkg/storage/storagebackend"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"k8s.io/kubernetes/pkg/registry/service/allocator"
|
||||
"k8s.io/kubernetes/pkg/registry/service/portallocator"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -112,7 +110,9 @@ type Config struct {
|
|||
// RESTStorageProviders provides RESTStorage building methods keyed by groupName
|
||||
RESTStorageProviders map[string]RESTStorageProvider
|
||||
// Used to start and monitor tunneling
|
||||
Tunneler genericapiserver.Tunneler
|
||||
Tunneler genericapiserver.Tunneler
|
||||
EnableUISupport bool
|
||||
EnableLogsSupport bool
|
||||
|
||||
disableThirdPartyControllerForTesting bool
|
||||
}
|
||||
|
@ -179,11 +179,20 @@ func New(c *Config) (*Master, error) {
|
|||
return nil, fmt.Errorf("Master.New() called with config.KubeletClient == nil")
|
||||
}
|
||||
|
||||
s, err := c.Config.New()
|
||||
gc := *c.Config // copy before mutations
|
||||
gc.EnableSwaggerUI = gc.EnableSwaggerUI && c.EnableUISupport // disable swagger UI if general UI supports it
|
||||
s, err := gc.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.EnableUISupport {
|
||||
routes.UIRedirect{}.Install(s.Mux, s.HandlerContainer)
|
||||
}
|
||||
if c.EnableLogsSupport {
|
||||
routes.Logs{}.Install(s.Mux, s.HandlerContainer)
|
||||
}
|
||||
|
||||
m := &Master{
|
||||
GenericAPIServer: s,
|
||||
enableCoreControllers: c.EnableCoreControllers,
|
||||
|
@ -220,19 +229,6 @@ func New(c *Config) (*Master, error) {
|
|||
return m, nil
|
||||
}
|
||||
|
||||
var defaultMetricsHandler = prometheus.Handler().ServeHTTP
|
||||
|
||||
// MetricsWithReset is a handler that resets metrics when DELETE is passed to the endpoint.
|
||||
func MetricsWithReset(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method == "DELETE" {
|
||||
apiservermetrics.Reset()
|
||||
etcdmetrics.Reset()
|
||||
io.WriteString(w, "metrics reset\n")
|
||||
return
|
||||
}
|
||||
defaultMetricsHandler(w, req)
|
||||
}
|
||||
|
||||
func (m *Master) InstallAPIs(c *Config) {
|
||||
apiGroupsInfo := []genericapiserver.APIGroupInfo{}
|
||||
|
||||
|
@ -270,12 +266,12 @@ func (m *Master) InstallAPIs(c *Config) {
|
|||
Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.",
|
||||
}, func() float64 { return float64(m.tunneler.SecondsSinceSync()) })
|
||||
}
|
||||
healthz.InstallHandler(m.MuxHelper, healthzChecks...)
|
||||
healthz.InstallHandler(m.Mux, healthzChecks...)
|
||||
|
||||
if c.EnableProfiling {
|
||||
m.MuxHelper.HandleFunc("/metrics", MetricsWithReset)
|
||||
routes.MetricsWithReset{}.Install(m.Mux, m.HandlerContainer)
|
||||
} else {
|
||||
m.MuxHelper.HandleFunc("/metrics", defaultMetricsHandler)
|
||||
routes.DefaultMetrics{}.Install(m.Mux, m.HandlerContainer)
|
||||
}
|
||||
|
||||
// Install third party resource support if requested
|
||||
|
|
|
@ -63,6 +63,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
|
@ -104,6 +105,7 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.
|
|||
config.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil }
|
||||
config.ProxyTLSClientConfig = &tls.Config{}
|
||||
config.RequestContextMapper = api.NewRequestContextMapper()
|
||||
config.Config.EnableVersion = true
|
||||
|
||||
// TODO: this is kind of hacky. The trouble is that the sync loop
|
||||
// runs in a go-routine and there is no way to validate in the test
|
||||
|
@ -203,6 +205,29 @@ func TestNamespaceSubresources(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestVersion tests /version
|
||||
func TestVersion(t *testing.T) {
|
||||
s, etcdserver, _, _ := newMaster(t)
|
||||
defer etcdserver.Terminate(t)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/version", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
s.InsecureHandler.ServeHTTP(resp, req)
|
||||
if resp.Code != 200 {
|
||||
t.Fatalf("expected http 200, got: %d", resp.Code)
|
||||
}
|
||||
|
||||
var info version.Info
|
||||
err := json.NewDecoder(resp.Body).Decode(&info)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(version.Get(), info) {
|
||||
t.Errorf("Expected %#v, Got %#v", version.Get(), info)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetServersToValidate verifies the unexported getServersToValidate function
|
||||
func TestGetServersToValidate(t *testing.T) {
|
||||
master, etcdserver, config, assert := setUp(t)
|
||||
|
|
|
@ -14,24 +14,5 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apiserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Offers additional functionality over ServeMux, for ex: supports listing registered paths.
|
||||
type MuxHelper struct {
|
||||
Mux Mux
|
||||
RegisteredPaths []string
|
||||
}
|
||||
|
||||
func (m *MuxHelper) Handle(path string, handler http.Handler) {
|
||||
m.RegisteredPaths = append(m.RegisteredPaths, path)
|
||||
m.Mux.Handle(path, handler)
|
||||
}
|
||||
|
||||
func (m *MuxHelper) HandleFunc(path string, handler func(http.ResponseWriter, *http.Request)) {
|
||||
m.RegisteredPaths = append(m.RegisteredPaths, path)
|
||||
m.Mux.HandleFunc(path, handler)
|
||||
}
|
||||
// Package routes holds a collection of optional master http handlers.
|
||||
package routes
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
)
|
||||
|
||||
// Logs adds handlers for the /logs path serving log files from /var/log.
|
||||
type Logs struct{}
|
||||
|
||||
func (l Logs) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
||||
// use restful: ws.Route(ws.GET("/logs/{logpath:*}").To(fileHandler))
|
||||
// See github.com/emicklei/go-restful/blob/master/examples/restful-serve-static.go
|
||||
ws := new(restful.WebService)
|
||||
ws.Path("/logs")
|
||||
ws.Doc("get log files")
|
||||
ws.Route(ws.GET("/{logpath:*}").To(logFileHandler).Param(ws.PathParameter("logpath", "path to the log").DataType("string")))
|
||||
ws.Route(ws.GET("/").To(logFileListHandler))
|
||||
|
||||
c.Add(ws)
|
||||
}
|
||||
|
||||
func logFileHandler(req *restful.Request, resp *restful.Response) {
|
||||
logdir := "/var/log"
|
||||
actual := path.Join(logdir, req.PathParameter("logpath"))
|
||||
http.ServeFile(resp.ResponseWriter, req.Request, actual)
|
||||
}
|
||||
|
||||
func logFileListHandler(req *restful.Request, resp *restful.Response) {
|
||||
logdir := "/var/log"
|
||||
http.ServeFile(resp.ResponseWriter, req.Request, logdir)
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
apiservermetrics "k8s.io/kubernetes/pkg/apiserver/metrics"
|
||||
etcdmetrics "k8s.io/kubernetes/pkg/storage/etcd/metrics"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// DefaultMetrics installs the default prometheus metrics handler
|
||||
type DefaultMetrics struct{}
|
||||
|
||||
func (m DefaultMetrics) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
||||
mux.HandleFunc("/metrics", prometheus.Handler().ServeHTTP)
|
||||
}
|
||||
|
||||
// MetricsWithReset install the prometheus metrics handler extended with support for the DELETE method
|
||||
// which resets the metrics.
|
||||
type MetricsWithReset struct{}
|
||||
|
||||
func (m MetricsWithReset) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
||||
defaultMetricsHandler := prometheus.Handler().ServeHTTP
|
||||
mux.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method == "DELETE" {
|
||||
apiservermetrics.Reset()
|
||||
etcdmetrics.Reset()
|
||||
io.WriteString(w, "metrics reset\n")
|
||||
return
|
||||
}
|
||||
defaultMetricsHandler(w, req)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
)
|
||||
|
||||
const dashboardPath = "/api/v1/proxy/namespaces/kube-system/services/kubernetes-dashboard"
|
||||
|
||||
// UIRediect redirects /ui to the kube-ui proxy path.
|
||||
type UIRedirect struct{}
|
||||
|
||||
func (r UIRedirect) Install(mux *apiserver.PathRecorderMux, c *restful.Container) {
|
||||
mux.HandleFunc("/ui/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, dashboardPath, http.StatusTemporaryRedirect)
|
||||
})
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ui
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/kubernetes/pkg/ui/data/swagger"
|
||||
|
||||
assetfs "github.com/elazarl/go-bindata-assetfs"
|
||||
)
|
||||
|
||||
const dashboardPath = "/api/v1/proxy/namespaces/kube-system/services/kubernetes-dashboard"
|
||||
|
||||
type MuxInterface interface {
|
||||
Handle(pattern string, handler http.Handler)
|
||||
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
||||
}
|
||||
|
||||
func InstallSupport(mux MuxInterface, enableSwaggerSupport bool) {
|
||||
|
||||
// Send correct mime type for .svg files. TODO: remove when
|
||||
// https://github.com/golang/go/commit/21e47d831bafb59f22b1ea8098f709677ec8ce33
|
||||
// makes it into all of our supported go versions.
|
||||
mime.AddExtensionType(".svg", "image/svg+xml")
|
||||
|
||||
// Redirect /ui to the kube-ui proxy path
|
||||
prefix := "/ui/"
|
||||
mux.HandleFunc(prefix, func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, dashboardPath, http.StatusTemporaryRedirect)
|
||||
})
|
||||
|
||||
if enableSwaggerSupport {
|
||||
// Expose files in third_party/swagger-ui/ on <host>/swagger-ui
|
||||
fileServer := http.FileServer(&assetfs.AssetFS{
|
||||
Asset: swagger.Asset,
|
||||
AssetDir: swagger.AssetDir,
|
||||
Prefix: "third_party/swagger-ui",
|
||||
})
|
||||
prefix = "/swagger-ui/"
|
||||
mux.Handle(prefix, http.StripPrefix(prefix, fileServer))
|
||||
}
|
||||
}
|
|
@ -229,6 +229,7 @@ func NewMasterConfig() *master.Config {
|
|||
// Set those values to avoid annoying warnings in logs.
|
||||
ServiceClusterIPRange: parseCIDROrDie("10.0.0.0/24"),
|
||||
ServiceNodePortRange: utilnet.PortRange{Base: 30000, Size: 2768},
|
||||
EnableVersion: true,
|
||||
},
|
||||
KubeletClient: kubeletclient.FakeKubeletClient{},
|
||||
}
|
||||
|
@ -239,6 +240,7 @@ func NewIntegrationTestMasterConfig() *master.Config {
|
|||
masterConfig := NewMasterConfig()
|
||||
masterConfig.EnableCoreControllers = true
|
||||
masterConfig.EnableIndex = true
|
||||
masterConfig.EnableVersion = true
|
||||
masterConfig.PublicAddress = net.ParseIP("192.168.10.4")
|
||||
masterConfig.APIResourceConfigSource = master.DefaultAPIResourceConfigSource()
|
||||
return masterConfig
|
||||
|
|
|
@ -28,11 +28,12 @@ import (
|
|||
func TestMasterExportsSymbols(t *testing.T) {
|
||||
_ = &master.Config{
|
||||
Config: &genericapiserver.Config{
|
||||
EnableUISupport: false,
|
||||
EnableSwaggerSupport: false,
|
||||
RestfulContainer: nil,
|
||||
},
|
||||
EnableCoreControllers: false,
|
||||
EnableUISupport: false,
|
||||
EnableLogsSupport: false,
|
||||
}
|
||||
m := &master.Master{
|
||||
GenericAPIServer: &genericapiserver.GenericAPIServer{},
|
||||
|
|
Loading…
Reference in New Issue