Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0b4f333

Browse files
authored
chore: add http debug support to pgcoord (#8795)
1 parent a75346d commit 0b4f333

File tree

10 files changed

+361
-99
lines changed

10 files changed

+361
-99
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,20 @@ func (q *querier) GetActiveUserCount(ctx context.Context) (int64, error) {
784784
return q.db.GetActiveUserCount(ctx)
785785
}
786786

787+
func (q *querier) GetAllTailnetAgents(ctx context.Context) ([]database.TailnetAgent, error) {
788+
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceTailnetCoordinator); err != nil {
789+
return []database.TailnetAgent{}, err
790+
}
791+
return q.db.GetAllTailnetAgents(ctx)
792+
}
793+
794+
func (q *querier) GetAllTailnetClients(ctx context.Context) ([]database.TailnetClient, error) {
795+
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceTailnetCoordinator); err != nil {
796+
return []database.TailnetClient{}, err
797+
}
798+
return q.db.GetAllTailnetClients(ctx)
799+
}
800+
787801
func (q *querier) GetAppSecurityKey(ctx context.Context) (string, error) {
788802
// No authz checks
789803
return q.db.GetAppSecurityKey(ctx)

coderd/database/dbfake/dbfake.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,14 @@ func (q *FakeQuerier) GetActiveUserCount(_ context.Context) (int64, error) {
903903
return active, nil
904904
}
905905

906+
func (*FakeQuerier) GetAllTailnetAgents(_ context.Context) ([]database.TailnetAgent, error) {
907+
return nil, ErrUnimplemented
908+
}
909+
910+
func (*FakeQuerier) GetAllTailnetClients(_ context.Context) ([]database.TailnetClient, error) {
911+
return nil, ErrUnimplemented
912+
}
913+
906914
func (q *FakeQuerier) GetAppSecurityKey(_ context.Context) (string, error) {
907915
q.mutex.RLock()
908916
defer q.mutex.RUnlock()

coderd/database/dbmetrics/dbmetrics.go

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

coderd/database/dbmock/dbmock.go

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

coderd/database/querier.go

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

coderd/database/queries.sql.go

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

coderd/database/queries/tailnet.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,20 @@ SELECT *
5959
FROM tailnet_agents
6060
WHERE id = $1;
6161

62+
-- name: GetAllTailnetAgents :many
63+
SELECT *
64+
FROM tailnet_agents;
65+
6266
-- name: GetTailnetClientsForAgent :many
6367
SELECT *
6468
FROM tailnet_clients
6569
WHERE agent_id = $1;
6670

71+
-- name: GetAllTailnetClients :many
72+
SELECT *
73+
FROM tailnet_clients
74+
ORDER BY agent_id;
75+
6776
-- name: UpsertTailnetCoordinator :one
6877
INSERT INTO
6978
tailnet_coordinators (

enterprise/tailnet/coordinator.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,5 +704,7 @@ func (c *haCoordinator) ServeHTTPDebug(w http.ResponseWriter, r *http.Request) {
704704
c.mutex.RLock()
705705
defer c.mutex.RUnlock()
706706

707-
agpl.CoordinatorHTTPDebug(true, c.agentSockets, c.agentToConnectionSockets, c.nodes, c.agentNameCache)(w, r)
707+
agpl.CoordinatorHTTPDebug(
708+
agpl.HTTPDebugFromLocal(true, c.agentSockets, c.agentToConnectionSockets, c.nodes, c.agentNameCache),
709+
)(w, r)
708710
}

enterprise/tailnet/pgcoord.go

Lines changed: 116 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
"github.com/cenkalti/backoff/v4"
1515
"github.com/google/uuid"
16+
"golang.org/x/exp/slices"
1617
"golang.org/x/xerrors"
1718
"nhooyr.io/websocket"
1819

@@ -307,6 +308,9 @@ type binding struct {
307308
node *agpl.Node
308309
}
309310

311+
func (b *binding) isAgent() bool { return b.client == uuid.Nil }
312+
func (b *binding) isClient() bool { return b.client != uuid.Nil }
313+
310314
// binder reads node bindings from the channel and writes them to the database. It handles retries with a backoff.
311315
type binder struct {
312316
ctx context.Context
@@ -386,19 +390,19 @@ func (b *binder) writeOne(bnd binding) error {
386390
if err != nil {
387391
// this is very bad news, but it should never happen because the node was Unmarshalled by this process
388392
// earlier.
389-
b.logger.Error(b.ctx, "failed to marshall node", slog.Error(err))
393+
b.logger.Error(b.ctx, "failed to marshal node", slog.Error(err))
390394
return err
391395
}
392396
}
393397

394398
switch {
395-
case bnd.client == uuid.Nil && len(nodeRaw) > 0:
399+
case bnd.isAgent() && len(nodeRaw) > 0:
396400
_, err = b.store.UpsertTailnetAgent(b.ctx, database.UpsertTailnetAgentParams{
397401
ID: bnd.agent,
398402
CoordinatorID: b.coordinatorID,
399403
Node: nodeRaw,
400404
})
401-
case bnd.client == uuid.Nil && len(nodeRaw) == 0:
405+
case bnd.isAgent() && len(nodeRaw) == 0:
402406
_, err = b.store.DeleteTailnetAgent(b.ctx, database.DeleteTailnetAgentParams{
403407
ID: bnd.agent,
404408
CoordinatorID: b.coordinatorID,
@@ -407,14 +411,14 @@ func (b *binder) writeOne(bnd binding) error {
407411
// treat deletes as idempotent
408412
err = nil
409413
}
410-
case bnd.client != uuid.Nil && len(nodeRaw) > 0:
414+
case bnd.isClient() && len(nodeRaw) > 0:
411415
_, err = b.store.UpsertTailnetClient(b.ctx, database.UpsertTailnetClientParams{
412416
ID: bnd.client,
413417
CoordinatorID: b.coordinatorID,
414418
AgentID: bnd.agent,
415419
Node: nodeRaw,
416420
})
417-
case bnd.client != uuid.Nil && len(nodeRaw) == 0:
421+
case bnd.isClient() && len(nodeRaw) == 0:
418422
_, err = b.store.DeleteTailnetClient(b.ctx, database.DeleteTailnetClientParams{
419423
ID: bnd.client,
420424
CoordinatorID: b.coordinatorID,
@@ -927,6 +931,27 @@ func (q *querier) updateAll() {
927931
}
928932
}
929933

934+
func (q *querier) getAll(ctx context.Context) (map[uuid.UUID]database.TailnetAgent, map[uuid.UUID][]database.TailnetClient, error) {
935+
agents, err := q.store.GetAllTailnetAgents(ctx)
936+
if err != nil {
937+
return nil, nil, xerrors.Errorf("get all tailnet agents: %w", err)
938+
}
939+
agentsMap := map[uuid.UUID]database.TailnetAgent{}
940+
for _, agent := range agents {
941+
agentsMap[agent.ID] = agent
942+
}
943+
clients, err := q.store.GetAllTailnetClients(ctx)
944+
if err != nil {
945+
return nil, nil, xerrors.Errorf("get all tailnet clients: %w", err)
946+
}
947+
clientsMap := map[uuid.UUID][]database.TailnetClient{}
948+
for _, client := range clients {
949+
clientsMap[client.AgentID] = append(clientsMap[client.AgentID], client)
950+
}
951+
952+
return agentsMap, clientsMap, nil
953+
}
954+
930955
func parseClientUpdate(msg string) (client, agent uuid.UUID, err error) {
931956
parts := strings.Split(msg, ",")
932957
if len(parts) != 2 {
@@ -1289,8 +1314,90 @@ func (h *heartbeats) cleanup() {
12891314
h.logger.Debug(h.ctx, "cleaned up old coordinators")
12901315
}
12911316

1292-
func (*pgCoord) ServeHTTPDebug(w http.ResponseWriter, _ *http.Request) {
1293-
// TODO(spikecurtis) I'd like to hold off implementing this until after the rest of this is code reviewed.
1294-
w.WriteHeader(http.StatusOK)
1295-
_, _ = w.Write([]byte("Coder Enterprise PostgreSQL distributed tailnet coordinator"))
1317+
func (c *pgCoord) ServeHTTPDebug(w http.ResponseWriter, r *http.Request) {
1318+
ctx := r.Context()
1319+
debug, err := c.htmlDebug(ctx)
1320+
if err != nil {
1321+
w.WriteHeader(http.StatusInternalServerError)
1322+
_, _ = w.Write([]byte(err.Error()))
1323+
return
1324+
}
1325+
1326+
agpl.CoordinatorHTTPDebug(debug)(w, r)
1327+
}
1328+
1329+
func (c *pgCoord) htmlDebug(ctx context.Context) (agpl.HTMLDebug, error) {
1330+
now := time.Now()
1331+
data := agpl.HTMLDebug{}
1332+
agents, clients, err := c.querier.getAll(ctx)
1333+
if err != nil {
1334+
return data, xerrors.Errorf("get all agents and clients: %w", err)
1335+
}
1336+
1337+
for _, agent := range agents {
1338+
htmlAgent := &agpl.HTMLAgent{
1339+
ID: agent.ID,
1340+
// Name: ??, TODO: get agent names
1341+
LastWriteAge: now.Sub(agent.UpdatedAt).Round(time.Second),
1342+
}
1343+
for _, conn := range clients[agent.ID] {
1344+
htmlAgent.Connections = append(htmlAgent.Connections, &agpl.HTMLClient{
1345+
ID: conn.ID,
1346+
Name: conn.ID.String(),
1347+
LastWriteAge: now.Sub(conn.UpdatedAt).Round(time.Second),
1348+
})
1349+
data.Nodes = append(data.Nodes, &agpl.HTMLNode{
1350+
ID: conn.ID,
1351+
Node: conn.Node,
1352+
})
1353+
}
1354+
slices.SortFunc(htmlAgent.Connections, func(a, b *agpl.HTMLClient) bool {
1355+
return a.Name < b.Name
1356+
})
1357+
1358+
data.Agents = append(data.Agents, htmlAgent)
1359+
data.Nodes = append(data.Nodes, &agpl.HTMLNode{
1360+
ID: agent.ID,
1361+
// Name: ??, TODO: get agent names
1362+
Node: agent.Node,
1363+
})
1364+
}
1365+
slices.SortFunc(data.Agents, func(a, b *agpl.HTMLAgent) bool {
1366+
return a.Name < b.Name
1367+
})
1368+
1369+
for agentID, conns := range clients {
1370+
if len(conns) == 0 {
1371+
continue
1372+
}
1373+
1374+
if _, ok := agents[agentID]; ok {
1375+
continue
1376+
}
1377+
agent := &agpl.HTMLAgent{
1378+
Name: "unknown",
1379+
ID: agentID,
1380+
}
1381+
for _, conn := range conns {
1382+
agent.Connections = append(agent.Connections, &agpl.HTMLClient{
1383+
Name: conn.ID.String(),
1384+
ID: conn.ID,
1385+
LastWriteAge: now.Sub(conn.UpdatedAt).Round(time.Second),
1386+
})
1387+
data.Nodes = append(data.Nodes, &agpl.HTMLNode{
1388+
ID: conn.ID,
1389+
Node: conn.Node,
1390+
})
1391+
}
1392+
slices.SortFunc(agent.Connections, func(a, b *agpl.HTMLClient) bool {
1393+
return a.Name < b.Name
1394+
})
1395+
1396+
data.MissingAgents = append(data.MissingAgents, agent)
1397+
}
1398+
slices.SortFunc(data.MissingAgents, func(a, b *agpl.HTMLAgent) bool {
1399+
return a.Name < b.Name
1400+
})
1401+
1402+
return data, nil
12961403
}

0 commit comments

Comments
 (0)