feat(agent): expose HTTP debug server over tailnet API (#12582)

This commit is contained in:
Cian Johnston 2024-03-14 10:02:01 +00:00 committed by GitHub
parent 0d16df9df9
commit 3b406878e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 43 deletions

View File

@ -1660,52 +1660,50 @@ func (a *agent) isClosed() bool {
return a.hardCtx.Err() != nil
}
func (a *agent) requireNetwork() (*tailnet.Conn, bool) {
a.closeMutex.Lock()
defer a.closeMutex.Unlock()
return a.network, a.network != nil
}
func (a *agent) HandleHTTPDebugMagicsock(w http.ResponseWriter, r *http.Request) {
network, ok := a.requireNetwork()
if !ok {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("network is not ready yet"))
return
}
network.MagicsockServeHTTPDebug(w, r)
}
func (a *agent) HandleHTTPMagicsockDebugLoggingState(w http.ResponseWriter, r *http.Request) {
state := chi.URLParam(r, "state")
stateBool, err := strconv.ParseBool(state)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
_, _ = fmt.Fprintf(w, "invalid state %q, must be a boolean", state)
return
}
network, ok := a.requireNetwork()
if !ok {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("network is not ready yet"))
return
}
network.MagicsockSetDebugLoggingEnabled(stateBool)
a.logger.Info(r.Context(), "updated magicsock debug logging due to debug request", slog.F("new_state", stateBool))
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintf(w, "updated magicsock debug logging to %v", stateBool)
}
func (a *agent) HTTPDebug() http.Handler {
r := chi.NewRouter()
requireNetwork := func(w http.ResponseWriter) (*tailnet.Conn, bool) {
a.closeMutex.Lock()
network := a.network
a.closeMutex.Unlock()
if network == nil {
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte("network is not ready yet"))
return nil, false
}
return network, true
}
r.Get("/debug/magicsock", func(w http.ResponseWriter, r *http.Request) {
network, ok := requireNetwork(w)
if !ok {
return
}
network.MagicsockServeHTTPDebug(w, r)
})
r.Get("/debug/magicsock/debug-logging/{state}", func(w http.ResponseWriter, r *http.Request) {
state := chi.URLParam(r, "state")
stateBool, err := strconv.ParseBool(state)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
_, _ = fmt.Fprintf(w, "invalid state %q, must be a boolean", state)
return
}
network, ok := requireNetwork(w)
if !ok {
return
}
network.MagicsockSetDebugLoggingEnabled(stateBool)
a.logger.Info(r.Context(), "updated magicsock debug logging due to debug request", slog.F("new_state", stateBool))
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintf(w, "updated magicsock debug logging to %v", stateBool)
})
r.Get("/debug/magicsock", a.HandleHTTPDebugMagicsock)
r.Get("/debug/magicsock/debug-logging/{state}", a.HandleHTTPMagicsockDebugLoggingState)
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte("404 not found"))

View File

@ -36,6 +36,8 @@ func (a *agent) apiHandler() http.Handler {
cacheDuration: cacheDuration,
}
r.Get("/api/v0/listening-ports", lp.handler)
r.Get("/debug/magicsock", a.HandleHTTPDebugMagicsock)
r.Get("/debug/magicsock/debug-logging/{state}", a.HandleHTTPMagicsockDebugLoggingState)
return r
}

View File

@ -356,6 +356,22 @@ func (c *WorkspaceAgentConn) ListeningPorts(ctx context.Context) (WorkspaceAgent
return resp, json.NewDecoder(res.Body).Decode(&resp)
}
// DebugMagicsock makes a request to the workspace agent's magicsock debug endpoint.
func (c *WorkspaceAgentConn) DebugMagicsock(ctx context.Context) ([]byte, error) {
ctx, span := tracing.StartSpan(ctx)
defer span.End()
res, err := c.apiRequest(ctx, http.MethodGet, "/debug/magicsock", nil)
if err != nil {
return nil, xerrors.Errorf("do request: %w", err)
}
defer res.Body.Close()
bs, err := io.ReadAll(res.Body)
if err != nil {
return nil, xerrors.Errorf("read response body: %w", err)
}
return bs, nil
}
// apiRequest makes a request to the workspace agent's HTTP API server.
func (c *WorkspaceAgentConn) apiRequest(ctx context.Context, method, path string, body io.Reader) (*http.Response, error) {
ctx, span := tracing.StartSpan(ctx)