mirror of https://github.com/coder/coder.git
feat(agent): expose HTTP debug server over tailnet API (#12582)
This commit is contained in:
parent
0d16df9df9
commit
3b406878e0
|
@ -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"))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue