mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-29 23:31:28 +01:00 
			
		
		
		
	* Modifies the k8s-proxy to expose health check and metrics endpoints on the Pod's IP. * Moves cmd/containerboot/healthz.go and cmd/containerboot/metrics.go to /kube to be shared with /k8s-proxy. Updates #13358 Signed-off-by: David Bond <davidsbond93@gmail.com>
		
			
				
	
	
		
			82 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| //go:build !plan9
 | |
| 
 | |
| // Package metrics contains shared types and underlying methods for serving
 | |
| // localapi metrics. This is primarily consumed by containerboot and k8s-proxy.
 | |
| package metrics
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 
 | |
| 	"tailscale.com/client/local"
 | |
| 	"tailscale.com/client/tailscale/apitype"
 | |
| )
 | |
| 
 | |
| // metrics is a simple metrics HTTP server, if enabled it forwards requests to
 | |
| // the tailscaled's LocalAPI usermetrics endpoint at /localapi/v0/usermetrics.
 | |
| type metrics struct {
 | |
| 	debugEndpoint string
 | |
| 	lc            *local.Client
 | |
| }
 | |
| 
 | |
| func proxy(w http.ResponseWriter, r *http.Request, url string, do func(*http.Request) (*http.Response, error)) {
 | |
| 	req, err := http.NewRequestWithContext(r.Context(), r.Method, url, r.Body)
 | |
| 	if err != nil {
 | |
| 		http.Error(w, fmt.Sprintf("failed to construct request: %s", err), http.StatusInternalServerError)
 | |
| 		return
 | |
| 	}
 | |
| 	req.Header = r.Header.Clone()
 | |
| 
 | |
| 	resp, err := do(req)
 | |
| 	if err != nil {
 | |
| 		http.Error(w, fmt.Sprintf("failed to proxy request: %s", err), http.StatusInternalServerError)
 | |
| 		return
 | |
| 	}
 | |
| 	defer resp.Body.Close()
 | |
| 
 | |
| 	for key, val := range resp.Header {
 | |
| 		for _, v := range val {
 | |
| 			w.Header().Add(key, v)
 | |
| 		}
 | |
| 	}
 | |
| 	w.WriteHeader(resp.StatusCode)
 | |
| 	if _, err := io.Copy(w, resp.Body); err != nil {
 | |
| 		http.Error(w, err.Error(), http.StatusInternalServerError)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (m *metrics) handleMetrics(w http.ResponseWriter, r *http.Request) {
 | |
| 	localAPIURL := "http://" + apitype.LocalAPIHost + "/localapi/v0/usermetrics"
 | |
| 	proxy(w, r, localAPIURL, m.lc.DoLocalRequest)
 | |
| }
 | |
| 
 | |
| func (m *metrics) handleDebug(w http.ResponseWriter, r *http.Request) {
 | |
| 	if m.debugEndpoint == "" {
 | |
| 		http.Error(w, "debug endpoint not configured", http.StatusNotFound)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	debugURL := "http://" + m.debugEndpoint + r.URL.Path
 | |
| 	proxy(w, r, debugURL, http.DefaultClient.Do)
 | |
| }
 | |
| 
 | |
| // registerMetricsHandlers registers a simple HTTP metrics handler at /metrics, forwarding
 | |
| // requests to tailscaled's /localapi/v0/usermetrics API.
 | |
| //
 | |
| // In 1.78.x and 1.80.x, it also proxies debug paths to tailscaled's debug
 | |
| // endpoint if configured to ease migration for a breaking change serving user
 | |
| // metrics instead of debug metrics on the "metrics" port.
 | |
| func RegisterMetricsHandlers(mux *http.ServeMux, lc *local.Client, debugAddrPort string) {
 | |
| 	m := &metrics{
 | |
| 		lc:            lc,
 | |
| 		debugEndpoint: debugAddrPort,
 | |
| 	}
 | |
| 
 | |
| 	mux.HandleFunc("GET /metrics", m.handleMetrics)
 | |
| 	mux.HandleFunc("/debug/", m.handleDebug) // TODO(tomhjp): Remove for 1.82.0 release.
 | |
| }
 |