Skip to content

Commit 366859b

Browse files
coadlermtojek
authored andcommitted
feat(agent): add http debug routes for magicsock (#7287)
1 parent 1e3eb06 commit 366859b

File tree

4 files changed

+58
-9
lines changed

4 files changed

+58
-9
lines changed

agent/agent.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ type Options struct {
5959
ReconnectingPTYTimeout time.Duration
6060
EnvironmentVariables map[string]string
6161
Logger slog.Logger
62-
AgentPorts map[int]string
62+
IgnorePorts map[int]string
6363
SSHMaxTimeout time.Duration
6464
TailnetListenPort uint16
6565
}
@@ -75,7 +75,12 @@ type Client interface {
7575
PatchStartupLogs(ctx context.Context, req agentsdk.PatchStartupLogs) error
7676
}
7777

78-
func New(options Options) io.Closer {
78+
type Agent interface {
79+
HTTPDebug() http.Handler
80+
io.Closer
81+
}
82+
83+
func New(options Options) Agent {
7984
if options.ReconnectingPTYTimeout == 0 {
8085
options.ReconnectingPTYTimeout = 5 * time.Minute
8186
}
@@ -111,7 +116,7 @@ func New(options Options) io.Closer {
111116
tempDir: options.TempDir,
112117
lifecycleUpdate: make(chan struct{}, 1),
113118
lifecycleReported: make(chan codersdk.WorkspaceAgentLifecycle, 1),
114-
ignorePorts: options.AgentPorts,
119+
ignorePorts: options.IgnorePorts,
115120
connStatsChan: make(chan *agentsdk.Stats, 1),
116121
sshMaxTimeout: options.SSHMaxTimeout,
117122
}
@@ -1263,6 +1268,27 @@ func (a *agent) isClosed() bool {
12631268
}
12641269
}
12651270

1271+
func (a *agent) HTTPDebug() http.Handler {
1272+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1273+
a.closeMutex.Lock()
1274+
network := a.network
1275+
a.closeMutex.Unlock()
1276+
1277+
if network == nil {
1278+
w.WriteHeader(http.StatusOK)
1279+
_, _ = w.Write([]byte("network is not ready yet"))
1280+
return
1281+
}
1282+
1283+
if r.URL.Path == "/debug/magicsock" {
1284+
network.MagicsockServeHTTPDebug(w, r)
1285+
} else {
1286+
w.WriteHeader(http.StatusNotFound)
1287+
_, _ = w.Write([]byte("404 not found"))
1288+
}
1289+
})
1290+
}
1291+
12661292
func (a *agent) Close() error {
12671293
a.closeMutex.Lock()
12681294
defer a.closeMutex.Unlock()

cli/agent.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
3838
sshMaxTimeout time.Duration
3939
tailnetListenPort int64
4040
prometheusAddress string
41+
debugAddress string
4142
)
4243
cmd := &clibase.Cmd{
4344
Use: "agent",
@@ -48,7 +49,7 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
4849
ctx, cancel := context.WithCancel(inv.Context())
4950
defer cancel()
5051

51-
agentPorts := map[int]string{}
52+
ignorePorts := map[int]string{}
5253

5354
isLinux := runtime.GOOS == "linux"
5455

@@ -125,14 +126,14 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
125126
defer pprofSrvClose()
126127
// Do a best effort here. If this fails, it's not a big deal.
127128
if port, err := urlPort(pprofAddress); err == nil {
128-
agentPorts[port] = "pprof"
129+
ignorePorts[port] = "pprof"
129130
}
130131

131132
prometheusSrvClose := ServeHandler(ctx, logger, prometheusMetricsHandler(), prometheusAddress, "prometheus")
132133
defer prometheusSrvClose()
133134
// Do a best effort here. If this fails, it's not a big deal.
134135
if port, err := urlPort(prometheusAddress); err == nil {
135-
agentPorts[port] = "prometheus"
136+
ignorePorts[port] = "prometheus"
136137
}
137138

138139
// exchangeToken returns a session token.
@@ -196,7 +197,7 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
196197
return xerrors.Errorf("add executable to $PATH: %w", err)
197198
}
198199

199-
closer := agent.New(agent.Options{
200+
agnt := agent.New(agent.Options{
200201
Client: client,
201202
Logger: logger,
202203
LogDir: logDir,
@@ -215,11 +216,19 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
215216
EnvironmentVariables: map[string]string{
216217
"GIT_ASKPASS": executablePath,
217218
},
218-
AgentPorts: agentPorts,
219+
IgnorePorts: ignorePorts,
219220
SSHMaxTimeout: sshMaxTimeout,
220221
})
222+
223+
debugSrvClose := ServeHandler(ctx, logger, agnt.HTTPDebug(), debugAddress, "debug")
224+
defer debugSrvClose()
225+
// Do a best effort here. If this fails, it's not a big deal.
226+
if port, err := urlPort(debugAddress); err == nil {
227+
ignorePorts[port] = "debug"
228+
}
229+
221230
<-ctx.Done()
222-
return closer.Close()
231+
return agnt.Close()
223232
},
224233
}
225234

@@ -273,6 +282,13 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd {
273282
Value: clibase.StringOf(&prometheusAddress),
274283
Description: "The bind address to serve Prometheus metrics.",
275284
},
285+
{
286+
Flag: "debug-address",
287+
Default: "127.0.0.1:2113",
288+
Env: "CODER_AGENT_DEBUG_ADDRESS",
289+
Value: clibase.StringOf(&debugAddress),
290+
Description: "The bind address to serve a debug HTTP server.",
291+
},
276292
}
277293

278294
return cmd

cli/testdata/coder_agent_--help.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Starts the Coder workspace agent.
66
--auth string, $CODER_AGENT_AUTH (default: token)
77
Specify the authentication type to use for the agent.
88

9+
--debug-address string, $CODER_AGENT_DEBUG_ADDRESS (default: 127.0.0.1:2113)
10+
The bind address to serve a debug HTTP server.
11+
912
--log-dir string, $CODER_AGENT_LOG_DIR (default: /tmp)
1013
Specify the location for the agent log files.
1114

tailnet/conn.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,10 @@ func (c *Conn) SetConnStatsCallback(maxPeriod time.Duration, maxConns int, dump
828828
c.tunDevice.SetStatistics(connStats)
829829
}
830830

831+
func (c *Conn) MagicsockServeHTTPDebug(w http.ResponseWriter, r *http.Request) {
832+
c.magicConn.ServeHTTPDebug(w, r)
833+
}
834+
831835
type listenKey struct {
832836
network string
833837
host string

0 commit comments

Comments
 (0)