* Define and use an interface for logging. This allows alternative implementations to use whatever logging package they want. Currently the interface just mimicks what logrus already implements, with minor modifications to not rely on logrus itself. I think the interface is pretty solid in terms of logging implementations being able to do what they need to. * Make tracing interface to coalesce logging/tracing Allows us to share data between the tracer and the logger so we can simplify log/trace handling wher we generally want data to go both places.
107 lines
3.6 KiB
Go
107 lines
3.6 KiB
Go
package vkubelet
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/virtual-kubelet/virtual-kubelet/log"
|
|
"github.com/virtual-kubelet/virtual-kubelet/providers"
|
|
"github.com/virtual-kubelet/virtual-kubelet/vkubelet/api"
|
|
"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)
|
|
}
|
|
|
|
// PodHandler creates an http handler for interacting with pods/containers.
|
|
func PodHandler(p providers.Provider) http.Handler {
|
|
r := mux.NewRouter()
|
|
|
|
r.HandleFunc("/containerLogs/{namespace}/{pod}/{container}", api.PodLogsHandlerFunc(p)).Methods("GET")
|
|
r.HandleFunc("/exec/{namespace}/{pod}/{container}", api.PodExecHandlerFunc(p)).Methods("POST")
|
|
r.NotFoundHandler = http.HandlerFunc(NotFound)
|
|
return r
|
|
}
|
|
|
|
// MetricsSummaryHandler creates an http handler for serving pod metrics.
|
|
//
|
|
// If the passed in provider does not implement providers.PodMetricsProvider,
|
|
// it will create handlers that just serves http.StatusNotImplemented
|
|
func MetricsSummaryHandler(p providers.Provider) http.Handler {
|
|
r := mux.NewRouter()
|
|
|
|
const summaryRoute = "/stats/summary"
|
|
var h http.HandlerFunc
|
|
|
|
mp, ok := p.(providers.PodMetricsProvider)
|
|
if !ok {
|
|
h = NotImplemented
|
|
} else {
|
|
h = api.PodMetricsHandlerFunc(mp)
|
|
}
|
|
|
|
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 providers.Provider, mux ServeMux) {
|
|
mux.Handle("/", InstrumentHandler(PodHandler(p)))
|
|
}
|
|
|
|
// AttachMetricsRoutes 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 AttachMetricsRoutes(p providers.Provider, mux ServeMux) {
|
|
mux.Handle("/", InstrumentHandler(MetricsSummaryHandler(p)))
|
|
}
|
|
|
|
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)
|
|
}
|