* Move tracing exporter registration This doesn't belong in the library and should be configured by the consumer of the opencensus package. * Rename `vkublet` package to `node` `vkubelet` does not convey any information to the consumers of the package. Really it would be nice to move this package to the root of the repo, but then you wind up with... interesting... import semantics due to the repo name... and after thinking about it some, a subpackage is really not so bad as long as it has a name that convey's some information. `node` was chosen since this package deals with all the semantics of operating a node in Kubernetes.
122 lines
4.1 KiB
Go
122 lines
4.1 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/virtual-kubelet/virtual-kubelet/log"
|
|
"go.opencensus.io/plugin/ochttp"
|
|
"go.opencensus.io/plugin/ochttp/propagation/b3"
|
|
)
|
|
|
|
// ServeMux defines an interface used to attach routes to an existing http
|
|
// serve mux.
|
|
// It is used to enable callers creating a new server to completely manage
|
|
// their own HTTP server while allowing us to attach the required routes to
|
|
// satisfy the Kubelet HTTP interfaces.
|
|
type ServeMux interface {
|
|
Handle(path string, h http.Handler)
|
|
}
|
|
|
|
type PodHandlerConfig struct {
|
|
RunInContainer ContainerExecHandlerFunc
|
|
GetContainerLogs ContainerLogsHandlerFunc
|
|
GetPods PodListerFunc
|
|
}
|
|
|
|
// PodHandler creates an http handler for interacting with pods/containers.
|
|
func PodHandler(p PodHandlerConfig, debug bool) http.Handler {
|
|
r := mux.NewRouter()
|
|
|
|
// This matches the behaviour in the reference kubelet
|
|
r.StrictSlash(true)
|
|
if debug {
|
|
r.HandleFunc("/runningpods/", HandleRunningPods(p.GetPods)).Methods("GET")
|
|
}
|
|
r.HandleFunc("/containerLogs/{namespace}/{pod}/{container}", HandleContainerLogs(p.GetContainerLogs)).Methods("GET")
|
|
r.HandleFunc("/exec/{namespace}/{pod}/{container}", HandleContainerExec(p.RunInContainer)).Methods("POST")
|
|
r.NotFoundHandler = http.HandlerFunc(NotFound)
|
|
return r
|
|
}
|
|
|
|
// PodStatsSummaryHandler creates an http handler for serving pod metrics.
|
|
//
|
|
// If the passed in handler func is nil this will create handlers which only
|
|
// serves http.StatusNotImplemented
|
|
func PodStatsSummaryHandler(f PodStatsSummaryHandlerFunc) http.Handler {
|
|
if f == nil {
|
|
return http.HandlerFunc(NotImplemented)
|
|
}
|
|
|
|
r := mux.NewRouter()
|
|
|
|
const summaryRoute = "/stats/summary"
|
|
h := HandlePodStatsSummary(f)
|
|
|
|
r.Handle(summaryRoute, ochttp.WithRouteTag(h, "PodStatsSummaryHandler")).Methods("GET")
|
|
r.Handle(summaryRoute+"/", ochttp.WithRouteTag(h, "PodStatsSummaryHandler")).Methods("GET")
|
|
|
|
r.NotFoundHandler = http.HandlerFunc(NotFound)
|
|
return r
|
|
}
|
|
|
|
// AttachPodRoutes adds the http routes for pod stuff to the passed in serve mux.
|
|
//
|
|
// Callers should take care to namespace the serve mux as they see fit, however
|
|
// these routes get called by the Kubernetes API server.
|
|
func AttachPodRoutes(p PodHandlerConfig, mux ServeMux, debug bool) {
|
|
mux.Handle("/", InstrumentHandler(PodHandler(p, debug)))
|
|
}
|
|
|
|
// PodMetricsConfig stores the handlers for pod metrics routes
|
|
// It is used by AttachPodMetrics.
|
|
//
|
|
// The main reason for this struct is in case of expansion we do not need to break
|
|
// the package level API.
|
|
type PodMetricsConfig struct {
|
|
GetStatsSummary PodStatsSummaryHandlerFunc
|
|
}
|
|
|
|
// AttachPodMetricsRoutes adds the http routes for pod/node metrics to the passed in serve mux.
|
|
//
|
|
// Callers should take care to namespace the serve mux as they see fit, however
|
|
// these routes get called by the Kubernetes API server.
|
|
func AttachPodMetricsRoutes(p PodMetricsConfig, mux ServeMux) {
|
|
mux.Handle("/", InstrumentHandler(HandlePodStatsSummary(p.GetStatsSummary)))
|
|
}
|
|
|
|
func instrumentRequest(r *http.Request) *http.Request {
|
|
ctx := r.Context()
|
|
logger := log.G(ctx).WithFields(log.Fields{
|
|
"uri": r.RequestURI,
|
|
"vars": mux.Vars(r),
|
|
})
|
|
ctx = log.WithLogger(ctx, logger)
|
|
|
|
return r.WithContext(ctx)
|
|
}
|
|
|
|
// InstrumentHandler wraps an http.Handler and injects instrumentation into the request context.
|
|
func InstrumentHandler(h http.Handler) http.Handler {
|
|
instrumented := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
req = instrumentRequest(req)
|
|
h.ServeHTTP(w, req)
|
|
})
|
|
return &ochttp.Handler{
|
|
Handler: instrumented,
|
|
Propagation: &b3.HTTPFormat{},
|
|
}
|
|
}
|
|
|
|
// NotFound provides a handler for cases where the requested endpoint doesn't exist
|
|
func NotFound(w http.ResponseWriter, r *http.Request) {
|
|
log.G(r.Context()).Debug("404 request not found")
|
|
http.Error(w, "404 request not found", http.StatusNotFound)
|
|
}
|
|
|
|
// NotImplemented provides a handler for cases where a provider does not implement a given API
|
|
func NotImplemented(w http.ResponseWriter, r *http.Request) {
|
|
log.G(r.Context()).Debug("501 not implemented")
|
|
http.Error(w, "501 not implemented", http.StatusNotImplemented)
|
|
}
|