From 3a7ae831c7b2272cfba5ec8ef9515dfe9ec6b9d7 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Tue, 24 Jan 2023 14:49:41 -0600 Subject: [PATCH 1/7] feat: add debug server for tailnet coordinators Resolves: https://github.com/coder/coder/issues/5845 --- agent/agent_test.go | 2 +- coderd/coderd.go | 21 ++++ coderd/coderdtest/authorize.go | 5 + coderd/rbac/object.go | 5 + coderd/workspaceagents.go | 12 ++- coderd/wsconncache/wsconncache_test.go | 2 +- enterprise/tailnet/coordinator.go | 10 +- enterprise/tailnet/coordinator_test.go | 10 +- tailnet/coordinator.go | 135 +++++++++++++++++++++---- tailnet/coordinator_test.go | 10 +- 10 files changed, 180 insertions(+), 32 deletions(-) diff --git a/agent/agent_test.go b/agent/agent_test.go index 0f0d93f923937..384c967a7f438 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -1193,7 +1193,7 @@ func (c *client) ListenWorkspaceAgent(_ context.Context) (net.Conn, error) { } c.t.Cleanup(c.lastWorkspaceAgent) go func() { - _ = c.coordinator.ServeAgent(serverConn, c.agentID) + _ = c.coordinator.ServeAgent(serverConn, c.agentID, "") close(closed) }() return clientConn, nil diff --git a/coderd/coderd.go b/coderd/coderd.go index 6119497796354..4b31b45b6b5f3 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -613,6 +613,27 @@ func New(options *Options) *API { r.Get("/", api.workspaceApplicationAuth) }) }) + + r.Route("/debug", func(r chi.Router) { + r.Use( + apiKeyMiddleware, + // Ensure only owners can access debug endpoints. + func(next http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + if !api.Authorize(r, rbac.ActionRead, rbac.ResourceDebugInfo) { + httpapi.ResourceNotFound(rw) + return + } + + next.ServeHTTP(rw, r) + }) + }, + ) + + r.HandleFunc("/coordinator", func(w http.ResponseWriter, r *http.Request) { + (*api.TailnetCoordinator.Load()).ServeHTTPDebug(w, r) + }) + }) }) if options.SwaggerEndpoint { diff --git a/coderd/coderdtest/authorize.go b/coderd/coderdtest/authorize.go index 03ad70ed338e6..783ef5e964458 100644 --- a/coderd/coderdtest/authorize.go +++ b/coderd/coderdtest/authorize.go @@ -272,6 +272,11 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) { AssertAction: rbac.ActionRead, AssertObject: rbac.ResourceTemplate, }, + + "GET:/api/v2/debug/coordinator": { + AssertAction: rbac.ActionRead, + AssertObject: rbac.ResourceDebugInfo, + }, } // Routes like proxy routes support all HTTP methods. A helper func to expand diff --git a/coderd/rbac/object.go b/coderd/rbac/object.go index 79dfd1b6194c4..1ee606a33cfe5 100644 --- a/coderd/rbac/object.go +++ b/coderd/rbac/object.go @@ -150,6 +150,11 @@ var ( ResourceReplicas = Object{ Type: "replicas", } + + // ResourceDebugInfo controls access to the debug routes `/api/v2/debug/*`. + ResourceDebugInfo = Object{ + Type: "debug_info", + } ) // Object is used to create objects for authz checks when you have none in diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 69d056f66da9c..0b28cc98333af 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -521,6 +521,16 @@ func (api *API) workspaceAgentCoordinate(rw http.ResponseWriter, r *http.Request }) return } + + workspace, err := api.Database.GetWorkspaceByID(ctx, build.WorkspaceID) + if err != nil { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "Internal error fetching workspace.", + Detail: err.Error(), + }) + return + } + // Ensure the resource is still valid! // We only accept agents for resources on the latest build. ensureLatestBuild := func() error { @@ -618,7 +628,7 @@ func (api *API) workspaceAgentCoordinate(rw http.ResponseWriter, r *http.Request closeChan := make(chan struct{}) go func() { defer close(closeChan) - err := (*api.TailnetCoordinator.Load()).ServeAgent(wsNetConn, workspaceAgent.ID) + err := (*api.TailnetCoordinator.Load()).ServeAgent(wsNetConn, workspaceAgent.ID, fmt.Sprintf("%s-%s", workspace.Name, workspaceAgent.Name)) if err != nil { api.Logger.Warn(ctx, "tailnet coordinator agent error", slog.Error(err)) _ = conn.Close(websocket.StatusInternalError, err.Error()) diff --git a/coderd/wsconncache/wsconncache_test.go b/coderd/wsconncache/wsconncache_test.go index a73e95e98947c..37ff4fc0b8900 100644 --- a/coderd/wsconncache/wsconncache_test.go +++ b/coderd/wsconncache/wsconncache_test.go @@ -207,7 +207,7 @@ func (c *client) ListenWorkspaceAgent(_ context.Context) (net.Conn, error) { <-closed }) go func() { - _ = c.coordinator.ServeAgent(serverConn, c.agentID) + _ = c.coordinator.ServeAgent(serverConn, c.agentID, "") close(closed) }() return clientConn, nil diff --git a/enterprise/tailnet/coordinator.go b/enterprise/tailnet/coordinator.go index c24107fe2a592..83def00ba1c92 100644 --- a/enterprise/tailnet/coordinator.go +++ b/enterprise/tailnet/coordinator.go @@ -5,8 +5,10 @@ import ( "context" "encoding/json" "errors" + "fmt" "io" "net" + "net/http" "sync" "time" @@ -174,7 +176,7 @@ func (c *haCoordinator) handleNextClientMessage(id, agent uuid.UUID, decoder *js // ServeAgent accepts a WebSocket connection to an agent that listens to // incoming connections and publishes node updates. -func (c *haCoordinator) ServeAgent(conn net.Conn, id uuid.UUID) error { +func (c *haCoordinator) ServeAgent(conn net.Conn, id uuid.UUID, _ string) error { // Tell clients on other instances to send a callmemaybe to us. err := c.publishAgentHello(id) if err != nil { @@ -573,3 +575,9 @@ func (c *haCoordinator) formatAgentUpdate(id uuid.UUID, node *agpl.Node) ([]byte return buf.Bytes(), nil } + +func (*haCoordinator) ServeHTTPDebug(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + fmt.Fprintf(w, "

coordinator

") + fmt.Fprintf(w, "

ha debug coming soon

") +} diff --git a/enterprise/tailnet/coordinator_test.go b/enterprise/tailnet/coordinator_test.go index 86cee94dbdf5b..cf85af4a5a565 100644 --- a/enterprise/tailnet/coordinator_test.go +++ b/enterprise/tailnet/coordinator_test.go @@ -60,7 +60,7 @@ func TestCoordinatorSingle(t *testing.T) { id := uuid.New() closeChan := make(chan struct{}) go func() { - err := coordinator.ServeAgent(server, id) + err := coordinator.ServeAgent(server, id, "") assert.NoError(t, err) close(closeChan) }() @@ -91,7 +91,7 @@ func TestCoordinatorSingle(t *testing.T) { agentID := uuid.New() closeAgentChan := make(chan struct{}) go func() { - err := coordinator.ServeAgent(agentServerWS, agentID) + err := coordinator.ServeAgent(agentServerWS, agentID, "") assert.NoError(t, err) close(closeAgentChan) }() @@ -142,7 +142,7 @@ func TestCoordinatorSingle(t *testing.T) { }) closeAgentChan = make(chan struct{}) go func() { - err := coordinator.ServeAgent(agentServerWS, agentID) + err := coordinator.ServeAgent(agentServerWS, agentID, "") assert.NoError(t, err) close(closeAgentChan) }() @@ -184,7 +184,7 @@ func TestCoordinatorHA(t *testing.T) { agentID := uuid.New() closeAgentChan := make(chan struct{}) go func() { - err := coordinator1.ServeAgent(agentServerWS, agentID) + err := coordinator1.ServeAgent(agentServerWS, agentID, "") assert.NoError(t, err) close(closeAgentChan) }() @@ -240,7 +240,7 @@ func TestCoordinatorHA(t *testing.T) { }) closeAgentChan = make(chan struct{}) go func() { - err := coordinator1.ServeAgent(agentServerWS, agentID) + err := coordinator1.ServeAgent(agentServerWS, agentID, "") assert.NoError(t, err) close(closeAgentChan) }() diff --git a/tailnet/coordinator.go b/tailnet/coordinator.go index 7c3f48c9ea060..0351eb2361dfe 100644 --- a/tailnet/coordinator.go +++ b/tailnet/coordinator.go @@ -4,10 +4,13 @@ import ( "context" "encoding/json" "errors" + "fmt" "io" "net" + "net/http" "net/netip" "sync" + "sync/atomic" "time" "github.com/google/uuid" @@ -22,6 +25,8 @@ import ( // └──────────────────┘ └────────────────────┘ └───────────────────┘ └──────────────────┘ // Coordinators have different guarantees for HA support. type Coordinator interface { + // ServeHTTPDebug + ServeHTTPDebug(w http.ResponseWriter, r *http.Request) // Node returns an in-memory node by ID. Node(id uuid.UUID) *Node // ServeClient accepts a WebSocket connection that wants to connect to an agent @@ -29,7 +34,8 @@ type Coordinator interface { ServeClient(conn net.Conn, id uuid.UUID, agent uuid.UUID) error // ServeAgent accepts a WebSocket connection to an agent that listens to // incoming connections and publishes node updates. - ServeAgent(conn net.Conn, id uuid.UUID) error + // Name is just used for debug information. It can be left blank. + ServeAgent(conn net.Conn, id uuid.UUID, name string) error // Close closes the coordinator. Close() error } @@ -104,8 +110,8 @@ func NewCoordinator() Coordinator { return &coordinator{ closed: false, nodes: map[uuid.UUID]*Node{}, - agentSockets: map[uuid.UUID]idConn{}, - agentToConnectionSockets: map[uuid.UUID]map[uuid.UUID]net.Conn{}, + agentSockets: map[uuid.UUID]*trackedConn{}, + agentToConnectionSockets: map[uuid.UUID]map[uuid.UUID]*trackedConn{}, } } @@ -117,23 +123,34 @@ func NewCoordinator() Coordinator { // This coordinator is incompatible with multiple Coder // replicas as all node data is in-memory. type coordinator struct { - mutex sync.Mutex + mutex sync.RWMutex closed bool // nodes maps agent and connection IDs their respective node. nodes map[uuid.UUID]*Node // agentSockets maps agent IDs to their open websocket. - agentSockets map[uuid.UUID]idConn + agentSockets map[uuid.UUID]*trackedConn // agentToConnectionSockets maps agent IDs to connection IDs of conns that // are subscribed to updates for that agent. - agentToConnectionSockets map[uuid.UUID]map[uuid.UUID]net.Conn + agentToConnectionSockets map[uuid.UUID]map[uuid.UUID]*trackedConn } -type idConn struct { +type trackedConn struct { + net.Conn + // id is an ephemeral UUID used to uniquely identify the owner of the // connection. - id uuid.UUID - conn net.Conn + id uuid.UUID + + name string + start int64 + lastWrite int64 + overwrites int64 +} + +func (t *trackedConn) Write(b []byte) (n int, err error) { + atomic.StoreInt64(&t.lastWrite, time.Now().Unix()) + return t.Conn.Write(b) } // Node returns an in-memory node by ID. @@ -182,12 +199,18 @@ func (c *coordinator) ServeClient(conn net.Conn, id uuid.UUID, agent uuid.UUID) c.mutex.Lock() connectionSockets, ok := c.agentToConnectionSockets[agent] if !ok { - connectionSockets = map[uuid.UUID]net.Conn{} + connectionSockets = map[uuid.UUID]*trackedConn{} c.agentToConnectionSockets[agent] = connectionSockets } + + now := time.Now().Unix() // Insert this connection into a map so the agent // can publish node updates. - connectionSockets[id] = conn + connectionSockets[id] = &trackedConn{ + Conn: conn, + start: now, + lastWrite: now, + } c.mutex.Unlock() defer func() { c.mutex.Lock() @@ -243,7 +266,7 @@ func (c *coordinator) handleNextClientMessage(id, agent uuid.UUID, decoder *json return xerrors.Errorf("marshal nodes: %w", err) } - _, err = agentSocket.conn.Write(data) + _, err = agentSocket.Write(data) if err != nil { if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, context.Canceled) { return nil @@ -256,7 +279,7 @@ func (c *coordinator) handleNextClientMessage(id, agent uuid.UUID, decoder *json // ServeAgent accepts a WebSocket connection to an agent that // listens to incoming connections and publishes node updates. -func (c *coordinator) ServeAgent(conn net.Conn, id uuid.UUID) error { +func (c *coordinator) ServeAgent(conn net.Conn, id uuid.UUID, name string) error { c.mutex.Lock() if c.closed { c.mutex.Unlock() @@ -289,6 +312,8 @@ func (c *coordinator) ServeAgent(conn net.Conn, id uuid.UUID) error { // This uniquely identifies a connection that belongs to this goroutine. unique := uuid.New() + now := time.Now().Unix() + overwrites := int64(0) // If an old agent socket is connected, we close it to avoid any leaks. This // shouldn't ever occur because we expect one agent to be running, but it's @@ -297,11 +322,17 @@ func (c *coordinator) ServeAgent(conn net.Conn, id uuid.UUID) error { // dead. oldAgentSocket, ok := c.agentSockets[id] if ok { - _ = oldAgentSocket.conn.Close() + overwrites = oldAgentSocket.overwrites + 1 + _ = oldAgentSocket.Close() } - c.agentSockets[id] = idConn{ + c.agentSockets[id] = &trackedConn{ id: unique, - conn: conn, + Conn: conn, + + name: name, + start: now, + lastWrite: now, + overwrites: overwrites, } c.mutex.Unlock() @@ -311,7 +342,7 @@ func (c *coordinator) ServeAgent(conn net.Conn, id uuid.UUID) error { // Only delete the connection if it's ours. It could have been // overwritten. - if idConn := c.agentSockets[id]; idConn.id == unique { + if idConn, ok := c.agentSockets[id]; ok && idConn.id == unique { delete(c.agentSockets, id) delete(c.nodes, id) } @@ -382,7 +413,7 @@ func (c *coordinator) Close() error { for _, socket := range c.agentSockets { socket := socket go func() { - _ = socket.conn.Close() + _ = socket.Close() wg.Done() }() } @@ -403,3 +434,71 @@ func (c *coordinator) Close() error { wg.Wait() return nil } + +func (c *coordinator) ServeHTTPDebug(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + now := time.Now() + + c.mutex.RLock() + defer c.mutex.RUnlock() + + fmt.Fprintln(w, "

in-memory wireguard coordinator debug

") + fmt.Fprintf(w, "

# agents: total %d

\n", len(c.agentSockets)) + fmt.Fprintln(w, "") + + missingAgents := map[uuid.UUID]map[uuid.UUID]*trackedConn{} + for agentID, conns := range c.agentToConnectionSockets { + if len(conns) == 0 { + continue + } + + if _, ok := c.agentSockets[agentID]; !ok { + missingAgents[agentID] = conns + } + } + + fmt.Fprintf(w, "

# missing agents: total %d

\n", len(missingAgents)) + fmt.Fprintln(w, "") +} diff --git a/tailnet/coordinator_test.go b/tailnet/coordinator_test.go index 60d909f7150b3..7dc90ff6f49f0 100644 --- a/tailnet/coordinator_test.go +++ b/tailnet/coordinator_test.go @@ -48,7 +48,7 @@ func TestCoordinator(t *testing.T) { id := uuid.New() closeChan := make(chan struct{}) go func() { - err := coordinator.ServeAgent(server, id) + err := coordinator.ServeAgent(server, id, "") assert.NoError(t, err) close(closeChan) }() @@ -76,7 +76,7 @@ func TestCoordinator(t *testing.T) { agentID := uuid.New() closeAgentChan := make(chan struct{}) go func() { - err := coordinator.ServeAgent(agentServerWS, agentID) + err := coordinator.ServeAgent(agentServerWS, agentID, "") assert.NoError(t, err) close(closeAgentChan) }() @@ -127,7 +127,7 @@ func TestCoordinator(t *testing.T) { }) closeAgentChan = make(chan struct{}) go func() { - err := coordinator.ServeAgent(agentServerWS, agentID) + err := coordinator.ServeAgent(agentServerWS, agentID, "") assert.NoError(t, err) close(closeAgentChan) }() @@ -160,7 +160,7 @@ func TestCoordinator(t *testing.T) { agentID := uuid.New() closeAgentChan1 := make(chan struct{}) go func() { - err := coordinator.ServeAgent(agentServerWS1, agentID) + err := coordinator.ServeAgent(agentServerWS1, agentID, "") assert.NoError(t, err) close(closeAgentChan1) }() @@ -205,7 +205,7 @@ func TestCoordinator(t *testing.T) { }) closeAgentChan2 := make(chan struct{}) go func() { - err := coordinator.ServeAgent(agentServerWS2, agentID) + err := coordinator.ServeAgent(agentServerWS2, agentID, "") assert.NoError(t, err) close(closeAgentChan2) }() From 69055eab601e5bb8c5c0ed411a6f42904a646376 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 25 Jan 2023 14:57:08 -0600 Subject: [PATCH 2/7] add swagger docs --- coderd/apidoc/docs.go | 22 ++++++++++++++++++++++ coderd/apidoc/swagger.json | 18 ++++++++++++++++++ coderd/coderd.go | 4 +--- coderd/debug.go | 14 ++++++++++++++ docs/api/debug.md | 21 +++++++++++++++++++++ docs/manifest.json | 4 ++++ 6 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 coderd/debug.go create mode 100644 docs/api/debug.md diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index a14ebd4ad5b70..85948f54880b3 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -362,6 +362,28 @@ const docTemplate = `{ } } }, + "/debug/coordinator": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "text/html" + ], + "tags": [ + "Debug" + ], + "summary": "Wireguard Coordinator Debug Info", + "operationId": "debuginfo-coordinator", + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/entitlements": { "get": { "security": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 53b5b41efd2bd..259e6f92f85c8 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -308,6 +308,24 @@ } } }, + "/debug/coordinator": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["text/html"], + "tags": ["Debug"], + "summary": "Wireguard Coordinator Debug Info", + "operationId": "debuginfo-coordinator", + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/entitlements": { "get": { "security": [ diff --git a/coderd/coderd.go b/coderd/coderd.go index 4b31b45b6b5f3..fa4a2d5453733 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -630,9 +630,7 @@ func New(options *Options) *API { }, ) - r.HandleFunc("/coordinator", func(w http.ResponseWriter, r *http.Request) { - (*api.TailnetCoordinator.Load()).ServeHTTPDebug(w, r) - }) + r.HandleFunc("/coordinator", api.debugCoordinator) }) }) diff --git a/coderd/debug.go b/coderd/debug.go new file mode 100644 index 0000000000000..ba265558cba61 --- /dev/null +++ b/coderd/debug.go @@ -0,0 +1,14 @@ +package coderd + +import "net/http" + +// @Summary Wireguard Coordinator Debug Info +// @ID debuginfo-coordinator +// @Security CoderSessionToken +// @Produce html +// @Tags Debug +// @Success 200 +// @Router /debug/coordinator [get] +func (api *API) debugCoordinator(rw http.ResponseWriter, r *http.Request) { + (*api.TailnetCoordinator.Load()).ServeHTTPDebug(rw, r) +} diff --git a/docs/api/debug.md b/docs/api/debug.md new file mode 100644 index 0000000000000..ca8592dabdb53 --- /dev/null +++ b/docs/api/debug.md @@ -0,0 +1,21 @@ +# Debug + +## Wireguard Coordinator Debug Info + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/debug/coordinator \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /debug/coordinator` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | ------ | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). diff --git a/docs/manifest.json b/docs/manifest.json index 25c72423e5fb3..0c38e57068491 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -364,6 +364,10 @@ "title": "Builds", "path": "./api/builds.md" }, + { + "title": "Debug", + "path": "./api/debug.md" + }, { "title": "Enterprise", "path": "./api/enterprise.md" From 1bec193e92ef0fb9769f02b374fd85c8fa5f278a Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 25 Jan 2023 14:58:34 -0600 Subject: [PATCH 3/7] fixup! add swagger docs --- coderd/coderd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/coderd.go b/coderd/coderd.go index fa4a2d5453733..c22da2be6b86c 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -630,7 +630,7 @@ func New(options *Options) *API { }, ) - r.HandleFunc("/coordinator", api.debugCoordinator) + r.Get("/coordinator", api.debugCoordinator) }) }) From 8720c2abab55af63847da0461506a571fb270b19 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 25 Jan 2023 15:08:07 -0600 Subject: [PATCH 4/7] fixup! add swagger docs --- coderd/apidoc/docs.go | 6 +++--- coderd/apidoc/swagger.json | 6 +++--- coderd/debug.go | 6 +++--- docs/api/debug.md | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 85948f54880b3..f42ca3f5df289 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -370,13 +370,13 @@ const docTemplate = `{ } ], "produces": [ - "text/html" + "text/html; charset=utf-8" ], "tags": [ "Debug" ], - "summary": "Wireguard Coordinator Debug Info", - "operationId": "debuginfo-coordinator", + "summary": "Debug Info Wireguard Coordinator", + "operationId": "debug-info-wireguard-coordinator", "responses": { "200": { "description": "OK" diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 259e6f92f85c8..fd19d0e351229 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -315,10 +315,10 @@ "CoderSessionToken": [] } ], - "produces": ["text/html"], + "produces": ["text/html; charset=utf-8"], "tags": ["Debug"], - "summary": "Wireguard Coordinator Debug Info", - "operationId": "debuginfo-coordinator", + "summary": "Debug Info Wireguard Coordinator", + "operationId": "debug-info-wireguard-coordinator", "responses": { "200": { "description": "OK" diff --git a/coderd/debug.go b/coderd/debug.go index ba265558cba61..8cc7fbd787b41 100644 --- a/coderd/debug.go +++ b/coderd/debug.go @@ -2,10 +2,10 @@ package coderd import "net/http" -// @Summary Wireguard Coordinator Debug Info -// @ID debuginfo-coordinator +// @Summary Debug Info Wireguard Coordinator +// @ID debug-info-wireguard-coordinator // @Security CoderSessionToken -// @Produce html +// @Produce text/html; charset=utf-8 // @Tags Debug // @Success 200 // @Router /debug/coordinator [get] diff --git a/docs/api/debug.md b/docs/api/debug.md index ca8592dabdb53..a32c9f6416a19 100644 --- a/docs/api/debug.md +++ b/docs/api/debug.md @@ -1,6 +1,6 @@ # Debug -## Wireguard Coordinator Debug Info +## Debug Info Wireguard Coordinator ### Code samples From 8d961d80108979e8d00a1e41bf0fa9bf8eb2d783 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 25 Jan 2023 15:14:09 -0600 Subject: [PATCH 5/7] fixup! add swagger docs --- coderd/coderdtest/swaggerparser.go | 5 +++-- coderd/debug.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/coderd/coderdtest/swaggerparser.go b/coderd/coderdtest/swaggerparser.go index c5d19cf088966..8ff5b78871692 100644 --- a/coderd/coderdtest/swaggerparser.go +++ b/coderd/coderdtest/swaggerparser.go @@ -327,7 +327,7 @@ func assertAccept(t *testing.T, comment SwaggerComment) { } } -var allowedProduceTypes = []string{"json", "text/event-stream"} +var allowedProduceTypes = []string{"json", "text/event-stream", "text/html"} func assertProduce(t *testing.T, comment SwaggerComment) { var hasResponseModel bool @@ -344,7 +344,8 @@ func assertProduce(t *testing.T, comment SwaggerComment) { } else { if (comment.router == "/workspaceagents/me/app-health" && comment.method == "post") || (comment.router == "/workspaceagents/me/version" && comment.method == "post") || - (comment.router == "/licenses/{id}" && comment.method == "delete") { + (comment.router == "/licenses/{id}" && comment.method == "delete") || + (comment.router == "/debug/coordinator" && comment.method == "get") { return // Exception: HTTP 200 is returned without response entity } diff --git a/coderd/debug.go b/coderd/debug.go index 8cc7fbd787b41..c22b77e564648 100644 --- a/coderd/debug.go +++ b/coderd/debug.go @@ -5,7 +5,7 @@ import "net/http" // @Summary Debug Info Wireguard Coordinator // @ID debug-info-wireguard-coordinator // @Security CoderSessionToken -// @Produce text/html; charset=utf-8 +// @Produce text/html // @Tags Debug // @Success 200 // @Router /debug/coordinator [get] From d4cce770d3b7a69c06c384388c6c2618b4bff4f5 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 25 Jan 2023 15:17:42 -0600 Subject: [PATCH 6/7] fixup! add swagger docs --- coderd/apidoc/docs.go | 2 +- coderd/apidoc/swagger.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index f42ca3f5df289..b288270655b25 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -370,7 +370,7 @@ const docTemplate = `{ } ], "produces": [ - "text/html; charset=utf-8" + "text/html" ], "tags": [ "Debug" diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index fd19d0e351229..ad3a30645142b 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -315,7 +315,7 @@ "CoderSessionToken": [] } ], - "produces": ["text/html; charset=utf-8"], + "produces": ["text/html"], "tags": ["Debug"], "summary": "Debug Info Wireguard Coordinator", "operationId": "debug-info-wireguard-coordinator", From 2c524984388103e3a55731b4373f8bd98a26b387 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Wed, 25 Jan 2023 15:22:15 -0600 Subject: [PATCH 7/7] fixup! add swagger docs --- tailnet/coordinator.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tailnet/coordinator.go b/tailnet/coordinator.go index 0351eb2361dfe..1373b370a5def 100644 --- a/tailnet/coordinator.go +++ b/tailnet/coordinator.go @@ -25,7 +25,8 @@ import ( // └──────────────────┘ └────────────────────┘ └───────────────────┘ └──────────────────┘ // Coordinators have different guarantees for HA support. type Coordinator interface { - // ServeHTTPDebug + // ServeHTTPDebug serves a debug webpage that shows the internal state of + // the coordinator. ServeHTTPDebug(w http.ResponseWriter, r *http.Request) // Node returns an in-memory node by ID. Node(id uuid.UUID) *Node