mirror of
https://github.com/tailscale/tailscale.git
synced 2025-07-31 00:03:47 +00:00

Add a PreStop lifecycle hook to the ProxyGroup ingress spec so that we can explicitly notify control that the service is being unadvertised and prompt it to update the netmap for clients faster. Without this, control just treats the device as temporarily offline and allows it a grace period before no longer considering it part of the service. Updates tailscale/corp#24795 Change-Id: I0a9a4fe7a5395ca76135ceead05cbc3ee32b3d3c Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com>
80 lines
2.3 KiB
Go
80 lines
2.3 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
//go:build linux
|
|
|
|
package main
|
|
|
|
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.
|
|
}
|