Skip to content

Commit 1cd5f38

Browse files
authored
feat: add debug server for tailnet coordinators (#5861)
Implements a Tailscale-like debug server for our in-memory coordinator. This should provide some visibility into why connections could be failing. Resolves: #5845 ![image](https://user-images.githubusercontent.com/6332295/214680832-2724d633-2d54-44d6-a7ce-5841e5824ee5.png)
1 parent 8830ddf commit 1cd5f38

File tree

16 files changed

+261
-34
lines changed

16 files changed

+261
-34
lines changed

agent/agent_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,7 @@ func (c *client) ListenWorkspaceAgent(_ context.Context) (net.Conn, error) {
11931193
}
11941194
c.t.Cleanup(c.lastWorkspaceAgent)
11951195
go func() {
1196-
_ = c.coordinator.ServeAgent(serverConn, c.agentID)
1196+
_ = c.coordinator.ServeAgent(serverConn, c.agentID, "")
11971197
close(closed)
11981198
}()
11991199
return clientConn, nil

coderd/apidoc/docs.go

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,25 @@ func New(options *Options) *API {
613613
r.Get("/", api.workspaceApplicationAuth)
614614
})
615615
})
616+
617+
r.Route("/debug", func(r chi.Router) {
618+
r.Use(
619+
apiKeyMiddleware,
620+
// Ensure only owners can access debug endpoints.
621+
func(next http.Handler) http.Handler {
622+
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
623+
if !api.Authorize(r, rbac.ActionRead, rbac.ResourceDebugInfo) {
624+
httpapi.ResourceNotFound(rw)
625+
return
626+
}
627+
628+
next.ServeHTTP(rw, r)
629+
})
630+
},
631+
)
632+
633+
r.Get("/coordinator", api.debugCoordinator)
634+
})
616635
})
617636

618637
if options.SwaggerEndpoint {

coderd/coderdtest/authorize.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,11 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
272272
AssertAction: rbac.ActionRead,
273273
AssertObject: rbac.ResourceTemplate,
274274
},
275+
276+
"GET:/api/v2/debug/coordinator": {
277+
AssertAction: rbac.ActionRead,
278+
AssertObject: rbac.ResourceDebugInfo,
279+
},
275280
}
276281

277282
// Routes like proxy routes support all HTTP methods. A helper func to expand

coderd/coderdtest/swaggerparser.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ func assertAccept(t *testing.T, comment SwaggerComment) {
327327
}
328328
}
329329

330-
var allowedProduceTypes = []string{"json", "text/event-stream"}
330+
var allowedProduceTypes = []string{"json", "text/event-stream", "text/html"}
331331

332332
func assertProduce(t *testing.T, comment SwaggerComment) {
333333
var hasResponseModel bool
@@ -344,7 +344,8 @@ func assertProduce(t *testing.T, comment SwaggerComment) {
344344
} else {
345345
if (comment.router == "/workspaceagents/me/app-health" && comment.method == "post") ||
346346
(comment.router == "/workspaceagents/me/version" && comment.method == "post") ||
347-
(comment.router == "/licenses/{id}" && comment.method == "delete") {
347+
(comment.router == "/licenses/{id}" && comment.method == "delete") ||
348+
(comment.router == "/debug/coordinator" && comment.method == "get") {
348349
return // Exception: HTTP 200 is returned without response entity
349350
}
350351

coderd/debug.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package coderd
2+
3+
import "net/http"
4+
5+
// @Summary Debug Info Wireguard Coordinator
6+
// @ID debug-info-wireguard-coordinator
7+
// @Security CoderSessionToken
8+
// @Produce text/html
9+
// @Tags Debug
10+
// @Success 200
11+
// @Router /debug/coordinator [get]
12+
func (api *API) debugCoordinator(rw http.ResponseWriter, r *http.Request) {
13+
(*api.TailnetCoordinator.Load()).ServeHTTPDebug(rw, r)
14+
}

coderd/rbac/object.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ var (
150150
ResourceReplicas = Object{
151151
Type: "replicas",
152152
}
153+
154+
// ResourceDebugInfo controls access to the debug routes `/api/v2/debug/*`.
155+
ResourceDebugInfo = Object{
156+
Type: "debug_info",
157+
}
153158
)
154159

155160
// Object is used to create objects for authz checks when you have none in

coderd/workspaceagents.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,16 @@ func (api *API) workspaceAgentCoordinate(rw http.ResponseWriter, r *http.Request
521521
})
522522
return
523523
}
524+
525+
workspace, err := api.Database.GetWorkspaceByID(ctx, build.WorkspaceID)
526+
if err != nil {
527+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
528+
Message: "Internal error fetching workspace.",
529+
Detail: err.Error(),
530+
})
531+
return
532+
}
533+
524534
// Ensure the resource is still valid!
525535
// We only accept agents for resources on the latest build.
526536
ensureLatestBuild := func() error {
@@ -618,7 +628,7 @@ func (api *API) workspaceAgentCoordinate(rw http.ResponseWriter, r *http.Request
618628
closeChan := make(chan struct{})
619629
go func() {
620630
defer close(closeChan)
621-
err := (*api.TailnetCoordinator.Load()).ServeAgent(wsNetConn, workspaceAgent.ID)
631+
err := (*api.TailnetCoordinator.Load()).ServeAgent(wsNetConn, workspaceAgent.ID, fmt.Sprintf("%s-%s", workspace.Name, workspaceAgent.Name))
622632
if err != nil {
623633
api.Logger.Warn(ctx, "tailnet coordinator agent error", slog.Error(err))
624634
_ = conn.Close(websocket.StatusInternalError, err.Error())

coderd/wsconncache/wsconncache_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ func (c *client) ListenWorkspaceAgent(_ context.Context) (net.Conn, error) {
207207
<-closed
208208
})
209209
go func() {
210-
_ = c.coordinator.ServeAgent(serverConn, c.agentID)
210+
_ = c.coordinator.ServeAgent(serverConn, c.agentID, "")
211211
close(closed)
212212
}()
213213
return clientConn, nil

0 commit comments

Comments
 (0)