Skip to content

Commit c5c1850

Browse files
committed
impl: identify the PID for the SSH command
Toolbox spawns a native process running the SSH client. The ssh client then spawns another process which associated to the coder proxy command. SSH network metrics are saved into json file with the name equal to the pid of the ssh command (not to be confused with the proxy command's name)
1 parent 46a58bd commit c5c1850

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.coder.toolbox.cli
2+
3+
import com.coder.toolbox.CoderToolboxContext
4+
import com.coder.toolbox.sdk.v2.models.Workspace
5+
import com.coder.toolbox.sdk.v2.models.WorkspaceAgent
6+
import kotlin.jvm.optionals.getOrNull
7+
8+
/**
9+
* Identifies the PID for the SSH Coder command spawned by Toolbox.
10+
*/
11+
class SshCommandProcessHandle(private val ctx: CoderToolboxContext) {
12+
13+
/**
14+
* Finds the PID of a Coder (not the proxy command) ssh cmd associated with the specified workspace and agent.
15+
* Null is returned when no ssh command process was found.
16+
*
17+
* Implementation Notes:
18+
* An iterative DFS approach where we start with Toolbox's direct children, grep the command
19+
* and if nothing is found we continue with the processes children. Toolbox spawns an ssh command
20+
* as a separate command which in turns spawns another child for the proxy command.
21+
*/
22+
fun findByWorkspaceAndAgent(ws: Workspace, agent: WorkspaceAgent): Long? {
23+
val stack = ArrayDeque<ProcessHandle>(ProcessHandle.current().children().toList())
24+
while (stack.isNotEmpty()) {
25+
val processHandle = stack.removeLast()
26+
val cmdLine = processHandle.info().commandLine().getOrNull()
27+
ctx.logger.debug("SSH command PID: ${processHandle.pid()} Command: $cmdLine")
28+
if (cmdLine != null && cmdLine.isSshCommandFor(ws, agent)) {
29+
ctx.logger.debug("SSH command with PID: ${processHandle.pid()} and Command: $cmdLine matches ${ws.name}.${agent.name}")
30+
return processHandle.pid()
31+
} else {
32+
stack.addAll(processHandle.children().toList())
33+
}
34+
}
35+
return null
36+
}
37+
38+
private fun String.isSshCommandFor(ws: Workspace, agent: WorkspaceAgent): Boolean {
39+
// usage-app is present only in the ProxyCommand
40+
return !this.contains("--usage-app=jetbrains") && this.contains("${ws.name}.${agent.name}")
41+
}
42+
}

0 commit comments

Comments
 (0)