mirror of https://github.com/linkerd/linkerd2.git
249 lines
5.9 KiB
Go
249 lines
5.9 KiB
Go
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
|
"github.com/linkerd/linkerd2/controller/k8s"
|
|
"github.com/linkerd/linkerd2/pkg/prometheus"
|
|
"github.com/linkerd/linkerd2/pkg/protohttp"
|
|
"github.com/linkerd/linkerd2/viz/metrics-api/client"
|
|
pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
|
|
promApi "github.com/prometheus/client_golang/api"
|
|
promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var (
|
|
gatewaysPath = fullURLPathFor("Gateways")
|
|
statSummaryPath = fullURLPathFor("StatSummary")
|
|
topRoutesPath = fullURLPathFor("TopRoutes")
|
|
listPodsPath = fullURLPathFor("ListPods")
|
|
listServicesPath = fullURLPathFor("ListServices")
|
|
selfCheckPath = fullURLPathFor("SelfCheck")
|
|
edgesPath = fullURLPathFor("Edges")
|
|
)
|
|
|
|
type handler struct {
|
|
grpcServer Server
|
|
}
|
|
|
|
func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
log.WithFields(log.Fields{
|
|
"req.Method": req.Method, "req.URL": req.URL, "req.Form": req.Form,
|
|
}).Debugf("Serving %s %s", req.Method, req.URL.Path)
|
|
// Validate request method
|
|
if req.Method != http.MethodPost {
|
|
protohttp.WriteErrorToHTTPResponse(w, fmt.Errorf("POST required"))
|
|
return
|
|
}
|
|
|
|
// Serve request
|
|
switch req.URL.Path {
|
|
case gatewaysPath:
|
|
h.handleGateways(w, req)
|
|
case statSummaryPath:
|
|
h.handleStatSummary(w, req)
|
|
case topRoutesPath:
|
|
h.handleTopRoutes(w, req)
|
|
case listPodsPath:
|
|
h.handleListPods(w, req)
|
|
case listServicesPath:
|
|
h.handleListServices(w, req)
|
|
case selfCheckPath:
|
|
h.handleSelfCheck(w, req)
|
|
case edgesPath:
|
|
h.handleEdges(w, req)
|
|
default:
|
|
http.NotFound(w, req)
|
|
}
|
|
|
|
}
|
|
|
|
func (h *handler) handleGateways(w http.ResponseWriter, req *http.Request) {
|
|
var protoRequest pb.GatewaysRequest
|
|
|
|
err := protohttp.HTTPRequestToProto(req, &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
rsp, err := h.grpcServer.Gateways(req.Context(), &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
err = protohttp.WriteProtoToHTTPResponse(w, rsp)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (h *handler) handleStatSummary(w http.ResponseWriter, req *http.Request) {
|
|
var protoRequest pb.StatSummaryRequest
|
|
|
|
err := protohttp.HTTPRequestToProto(req, &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
rsp, err := h.grpcServer.StatSummary(req.Context(), &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
err = protohttp.WriteProtoToHTTPResponse(w, rsp)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (h *handler) handleEdges(w http.ResponseWriter, req *http.Request) {
|
|
var protoRequest pb.EdgesRequest
|
|
|
|
err := protohttp.HTTPRequestToProto(req, &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
rsp, err := h.grpcServer.Edges(req.Context(), &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
err = protohttp.WriteProtoToHTTPResponse(w, rsp)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (h *handler) handleTopRoutes(w http.ResponseWriter, req *http.Request) {
|
|
var protoRequest pb.TopRoutesRequest
|
|
|
|
err := protohttp.HTTPRequestToProto(req, &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
rsp, err := h.grpcServer.TopRoutes(req.Context(), &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
err = protohttp.WriteProtoToHTTPResponse(w, rsp)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (h *handler) handleSelfCheck(w http.ResponseWriter, req *http.Request) {
|
|
var protoRequest healthcheckPb.SelfCheckRequest
|
|
err := protohttp.HTTPRequestToProto(req, &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
rsp, err := h.grpcServer.SelfCheck(req.Context(), &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
err = protohttp.WriteProtoToHTTPResponse(w, rsp)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (h *handler) handleListPods(w http.ResponseWriter, req *http.Request) {
|
|
var protoRequest pb.ListPodsRequest
|
|
err := protohttp.HTTPRequestToProto(req, &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
rsp, err := h.grpcServer.ListPods(req.Context(), &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
err = protohttp.WriteProtoToHTTPResponse(w, rsp)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (h *handler) handleListServices(w http.ResponseWriter, req *http.Request) {
|
|
var protoRequest pb.ListServicesRequest
|
|
|
|
err := protohttp.HTTPRequestToProto(req, &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
rsp, err := h.grpcServer.ListServices(req.Context(), &protoRequest)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
|
|
err = protohttp.WriteProtoToHTTPResponse(w, rsp)
|
|
if err != nil {
|
|
protohttp.WriteErrorToHTTPResponse(w, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func fullURLPathFor(method string) string {
|
|
return client.APIRoot + client.APIPrefix + method
|
|
}
|
|
|
|
// NewServer creates a Public API HTTP server.
|
|
func NewServer(
|
|
addr string,
|
|
prometheusClient promApi.Client,
|
|
k8sAPI *k8s.API,
|
|
controllerNamespace string,
|
|
clusterDomain string,
|
|
ignoredNamespaces []string,
|
|
) *http.Server {
|
|
|
|
var promAPI promv1.API
|
|
if prometheusClient != nil {
|
|
promAPI = promv1.NewAPI(prometheusClient)
|
|
}
|
|
|
|
grpcServer := newGrpcServer(
|
|
promAPI,
|
|
k8sAPI,
|
|
controllerNamespace,
|
|
clusterDomain,
|
|
ignoredNamespaces,
|
|
)
|
|
baseHandler := &handler{
|
|
grpcServer: grpcServer,
|
|
}
|
|
|
|
instrumentedHandler := prometheus.WithTelemetry(baseHandler)
|
|
|
|
return &http.Server{
|
|
Addr: addr,
|
|
Handler: instrumentedHandler,
|
|
}
|
|
}
|