Remove intermediate API server objects
Instead just generate HTTP handler functions directly.
This commit is contained in:
@@ -34,9 +34,11 @@ func NotFound(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, "404 request not found", http.StatusNotFound)
|
http.Error(w, "404 request not found", http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KubeletServer implements HTTP endpoints for serving kubelet API's
|
// NotImplemented provides a handler for cases where a provider does not implement a given API
|
||||||
type KubeletServer struct {
|
func NotImplemented(w http.ResponseWriter, r *http.Request) {
|
||||||
p Provider
|
logger := log.G(loggingContext(r))
|
||||||
|
log.Trace(logger, "501 not implemented")
|
||||||
|
http.Error(w, "501 not implemented", http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KubeletServertStart starts the virtual kubelet HTTP server.
|
// KubeletServertStart starts the virtual kubelet HTTP server.
|
||||||
@@ -47,9 +49,8 @@ func KubeletServerStart(p Provider) {
|
|||||||
addr := fmt.Sprintf(":%s", port)
|
addr := fmt.Sprintf(":%s", port)
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
s := &KubeletServer{p: p}
|
r.HandleFunc("/containerLogs/{namespace}/{pod}/{container}", PodLogsHandlerFunc(p)).Methods("GET")
|
||||||
r.HandleFunc("/containerLogs/{namespace}/{pod}/{container}", s.ApiServerHandler).Methods("GET")
|
r.HandleFunc("/exec/{namespace}/{pod}/{container}", PodExecHandlerFunc(p)).Methods("POST")
|
||||||
r.HandleFunc("/exec/{namespace}/{pod}/{container}", s.ApiServerHandlerExec).Methods("POST")
|
|
||||||
r.NotFoundHandler = http.HandlerFunc(NotFound)
|
r.NotFoundHandler = http.HandlerFunc(NotFound)
|
||||||
|
|
||||||
if err := http.ListenAndServeTLS(addr, certFilePath, keyFilePath, r); err != nil {
|
if err := http.ListenAndServeTLS(addr, certFilePath, keyFilePath, r); err != nil {
|
||||||
@@ -61,120 +62,115 @@ func KubeletServerStart(p Provider) {
|
|||||||
// TLS is never enabled on this endpoint.
|
// TLS is never enabled on this endpoint.
|
||||||
func MetricsServerStart(p Provider, addr string) {
|
func MetricsServerStart(p Provider, addr string) {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
s := &MetricsServer{p: p}
|
|
||||||
r.HandleFunc("/stats/summary", s.MetricsSummaryHandler).Methods("GET")
|
mp, ok := p.(MetricsProvider)
|
||||||
r.HandleFunc("/stats/summary/", s.MetricsSummaryHandler).Methods("GET")
|
if !ok {
|
||||||
|
r.HandleFunc("/stats/summary", NotImplemented).Methods("GET")
|
||||||
|
r.HandleFunc("/stats/summary/", NotImplemented).Methods("GET")
|
||||||
|
} else {
|
||||||
|
r.HandleFunc("/stats/summary", PodMetricsHandlerFunc(mp)).Methods("GET")
|
||||||
|
r.HandleFunc("/stats/summary/", PodMetricsHandlerFunc(mp)).Methods("GET")
|
||||||
|
}
|
||||||
r.NotFoundHandler = http.HandlerFunc(NotFound)
|
r.NotFoundHandler = http.HandlerFunc(NotFound)
|
||||||
if err := http.ListenAndServe(addr, r); err != nil {
|
if err := http.ListenAndServe(addr, r); err != nil {
|
||||||
log.G(context.TODO()).WithError(err).Error("Error starting http server")
|
log.G(context.TODO()).WithError(err).Error("Error starting http server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetricsServer provides an HTTP endpopint for accessing pod metrics
|
// PodMetricsHandlerFunc makes an HTTP handler for implementing the kubelet summary stats endpoint
|
||||||
type MetricsServer struct {
|
func PodMetricsHandlerFunc(mp MetricsProvider) http.HandlerFunc {
|
||||||
p Provider
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
ctx := loggingContext(req)
|
||||||
|
|
||||||
// MetricsSummaryHandler is an HTTP handler for implementing the kubelet summary stats endpoint
|
stats, err := mp.GetStatsSummary(req.Context())
|
||||||
func (s *MetricsServer) MetricsSummaryHandler(w http.ResponseWriter, req *http.Request) {
|
|
||||||
ctx := loggingContext(req)
|
|
||||||
|
|
||||||
mp, ok := s.p.(MetricsProvider)
|
|
||||||
if !ok {
|
|
||||||
log.G(ctx).Debug("stats not implemented for provider")
|
|
||||||
http.Error(w, "not implememnted", http.StatusNotImplemented)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stats, err := mp.GetStatsSummary(req.Context())
|
|
||||||
if err != nil {
|
|
||||||
if errors.Cause(err) == context.Canceled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.G(ctx).Error("Error getting stats from provider:", err)
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := json.Marshal(stats)
|
|
||||||
if err != nil {
|
|
||||||
log.G(ctx).WithError(err).Error("Could not marshal stats")
|
|
||||||
http.Error(w, "could not marshal stats: "+err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := w.Write(b); err != nil {
|
|
||||||
log.G(ctx).WithError(err).Debug("Could not write to client")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *KubeletServer) ApiServerHandler(w http.ResponseWriter, req *http.Request) {
|
|
||||||
vars := mux.Vars(req)
|
|
||||||
if len(vars) != 3 {
|
|
||||||
NotFound(w, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := loggingContext(req)
|
|
||||||
|
|
||||||
namespace := vars["namespace"]
|
|
||||||
pod := vars["pod"]
|
|
||||||
container := vars["container"]
|
|
||||||
tail := 10
|
|
||||||
q := req.URL.Query()
|
|
||||||
|
|
||||||
if queryTail := q.Get("tailLines"); queryTail != "" {
|
|
||||||
t, err := strconv.Atoi(queryTail)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger := log.G(context.TODO()).WithError(err)
|
if errors.Cause(err) == context.Canceled {
|
||||||
log.Trace(logger, "could not parse tailLines")
|
return
|
||||||
http.Error(w, fmt.Sprintf("could not parse \"tailLines\": %v", err), http.StatusBadRequest)
|
}
|
||||||
|
log.G(ctx).Error("Error getting stats from provider:", err)
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tail = t
|
|
||||||
}
|
|
||||||
|
|
||||||
podsLogs, err := s.p.GetContainerLogs(ctx, namespace, pod, container, tail)
|
b, err := json.Marshal(stats)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.G(ctx).WithError(err).Error("error getting container logs")
|
log.G(ctx).WithError(err).Error("Could not marshal stats")
|
||||||
http.Error(w, fmt.Sprintf("error while getting container logs: %v", err), http.StatusInternalServerError)
|
http.Error(w, "could not marshal stats: "+err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := io.WriteString(w, podsLogs); err != nil {
|
if _, err := w.Write(b); err != nil {
|
||||||
log.G(ctx).WithError(err).Warn("error writing response to client")
|
log.G(ctx).WithError(err).Debug("Could not write to client")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *KubeletServer) ApiServerHandlerExec(w http.ResponseWriter, req *http.Request) {
|
// PodLogsHandlerFunc creates an http handler function from a provider to serve logs from a pod
|
||||||
vars := mux.Vars(req)
|
func PodLogsHandlerFunc(p Provider) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
if len(vars) != 3 {
|
||||||
|
NotFound(w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
namespace := vars["namespace"]
|
ctx := loggingContext(req)
|
||||||
pod := vars["pod"]
|
|
||||||
container := vars["container"]
|
|
||||||
|
|
||||||
supportedStreamProtocols := strings.Split(req.Header.Get("X-Stream-Protocol-Version"), ",")
|
namespace := vars["namespace"]
|
||||||
|
pod := vars["pod"]
|
||||||
|
container := vars["container"]
|
||||||
|
tail := 10
|
||||||
|
q := req.URL.Query()
|
||||||
|
|
||||||
q := req.URL.Query()
|
if queryTail := q.Get("tailLines"); queryTail != "" {
|
||||||
command := q["command"]
|
t, err := strconv.Atoi(queryTail)
|
||||||
|
if err != nil {
|
||||||
|
logger := log.G(context.TODO()).WithError(err)
|
||||||
|
log.Trace(logger, "could not parse tailLines")
|
||||||
|
http.Error(w, fmt.Sprintf("could not parse \"tailLines\": %v", err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tail = t
|
||||||
|
}
|
||||||
|
|
||||||
// streamOpts := &remotecommand.Options{
|
podsLogs, err := p.GetContainerLogs(ctx, namespace, pod, container, tail)
|
||||||
// Stdin: (q.Get("input") == "1"),
|
if err != nil {
|
||||||
// Stdout: (q.Get("output") == "1"),
|
log.G(ctx).WithError(err).Error("error getting container logs")
|
||||||
// Stderr: (q.Get("error") == "1"),
|
http.Error(w, fmt.Sprintf("error while getting container logs: %v", err), http.StatusInternalServerError)
|
||||||
// TTY: (q.Get("tty") == "1"),
|
return
|
||||||
// }
|
}
|
||||||
|
|
||||||
// TODO: tty flag causes remotecommand.createStreams to wait for the wrong number of streams
|
if _, err := io.WriteString(w, podsLogs); err != nil {
|
||||||
streamOpts := &remotecommand.Options{
|
log.G(ctx).WithError(err).Warn("error writing response to client")
|
||||||
Stdin: true,
|
}
|
||||||
Stdout: true,
|
}
|
||||||
Stderr: true,
|
}
|
||||||
TTY: false,
|
|
||||||
|
// PodExecHandlerFunc makes an http handler func from a Provider which execs a command in a pod's container
|
||||||
|
func PodExecHandlerFunc(p Provider) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
|
||||||
|
namespace := vars["namespace"]
|
||||||
|
pod := vars["pod"]
|
||||||
|
container := vars["container"]
|
||||||
|
|
||||||
|
supportedStreamProtocols := strings.Split(req.Header.Get("X-Stream-Protocol-Version"), ",")
|
||||||
|
|
||||||
|
q := req.URL.Query()
|
||||||
|
command := q["command"]
|
||||||
|
|
||||||
|
// TODO: tty flag causes remotecommand.createStreams to wait for the wrong number of streams
|
||||||
|
streamOpts := &remotecommand.Options{
|
||||||
|
Stdin: true,
|
||||||
|
Stdout: true,
|
||||||
|
Stderr: true,
|
||||||
|
TTY: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
idleTimeout := time.Second * 30
|
||||||
|
streamCreationTimeout := time.Second * 30
|
||||||
|
|
||||||
|
remotecommand.ServeExec(w, req, p, fmt.Sprintf("%s-%s", namespace, pod), "", container, command, streamOpts, idleTimeout, streamCreationTimeout, supportedStreamProtocols)
|
||||||
}
|
}
|
||||||
|
|
||||||
idleTimeout := time.Second * 30
|
|
||||||
streamCreationTimeout := time.Second * 30
|
|
||||||
|
|
||||||
remotecommand.ServeExec(w, req, s.p, fmt.Sprintf("%s-%s", namespace, pod), "", container, command, streamOpts, idleTimeout, streamCreationTimeout, supportedStreamProtocols)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user