Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitebf86fa

Browse files
committed
Use wildcard SSH config Host entries
This simplifies the written SSH config and avoids the need to make anAPI request for every workspace the filter returns. This can removeminutes from the "Configuring Coder CLI..." step when the user hasaccess to many workspaces (for example, an admin who wants the option ofconnecting to anyone's workspace on a large deployment).Depends oncoder/coder#16088
1 parentfaddd24 commitebf86fa

File tree

5 files changed

+124
-44
lines changed

5 files changed

+124
-44
lines changed

‎src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt

Lines changed: 84 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ fun ensureCLI(
115115
data classFeatures(
116116
valdisableAutostart:Boolean =false,
117117
valreportWorkspaceUsage:Boolean =false,
118+
valwildcardSSH:Boolean =false,
118119
)
119120

120121
/**
@@ -285,37 +286,57 @@ class CoderCLIManager(
285286
}else {
286287
""
287288
}
289+
val sshOpts="""
290+
ConnectTimeout 0
291+
StrictHostKeyChecking no
292+
UserKnownHostsFile /dev/null
293+
LogLevel ERROR
294+
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
295+
""".trimIndent()
288296
val blockContent=
297+
if (feats.wildcardSSH) {
298+
startBlock+System.lineSeparator()+
299+
"""
300+
Host${getHostPrefix()}--*
301+
ProxyCommand${proxyArgs.joinToString("")} --ssh-host-prefix${getHostPrefix()}-- %h
302+
""".trimIndent()
303+
.plus("\n"+ sshOpts.prependIndent(""))
304+
.plus(extraConfig)
305+
.plus("\n\n")
306+
.plus(
307+
"""
308+
Host${getHostPrefix()}-bg--*
309+
ProxyCommand${backgroundProxyArgs.joinToString("")} --ssh-host-prefix${getHostPrefix()}-bg-- %h
310+
""".trimIndent()
311+
.plus("\n"+ sshOpts.prependIndent(""))
312+
.plus(extraConfig),
313+
).replace("\n",System.lineSeparator())+
314+
System.lineSeparator()+ endBlock
315+
316+
}else {
289317
workspaceNames.joinToString(
290318
System.lineSeparator(),
291319
startBlock+System.lineSeparator(),
292320
System.lineSeparator()+ endBlock,
293321
transform= {
294322
"""
295-
Host${getHostName(deploymentURL,it.first, currentUser, it.second)}
323+
Host${getHostName(it.first, currentUser, it.second)}
296324
ProxyCommand${proxyArgs.joinToString("")}${getWorkspaceParts(it.first, it.second)}
297-
ConnectTimeout 0
298-
StrictHostKeyChecking no
299-
UserKnownHostsFile /dev/null
300-
LogLevel ERROR
301-
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
302325
""".trimIndent()
326+
.plus("\n"+ sshOpts.prependIndent(""))
303327
.plus(extraConfig)
304328
.plus("\n")
305329
.plus(
306330
"""
307-
Host${getBackgroundHostName(deploymentURL,it.first, currentUser, it.second)}
331+
Host${getBackgroundHostName(it.first, currentUser, it.second)}
308332
ProxyCommand${backgroundProxyArgs.joinToString("")}${getWorkspaceParts(it.first, it.second)}
309-
ConnectTimeout 0
310-
StrictHostKeyChecking no
311-
UserKnownHostsFile /dev/null
312-
LogLevel ERROR
313-
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
314333
""".trimIndent()
334+
.plus("\n"+ sshOpts.prependIndent(""))
315335
.plus(extraConfig),
316336
).replace("\n",System.lineSeparator())
317337
},
318338
)
339+
}
319340

320341
if (contents==null) {
321342
logger.info("No existing SSH config to modify")
@@ -489,40 +510,53 @@ class CoderCLIManager(
489510
Features(
490511
disableAutostart= version>=SemVer(2,5,0),
491512
reportWorkspaceUsage= version>=SemVer(2,13,0),
513+
wildcardSSH= version>=SemVer(2,19,0),
492514
)
493515
}
494516
}
495517

518+
/*
519+
* This function returns the ssh-host-prefix used for Host entries.
520+
*/
521+
fungetHostPrefix():String=
522+
"coder-jetbrains-${deploymentURL.safeHost()}"
523+
524+
/**
525+
* This function returns the ssh host name generated for connecting to the workspace.
526+
*/
527+
fungetHostName(
528+
workspace:Workspace,
529+
currentUser:User,
530+
agent:WorkspaceAgent,
531+
):String=
532+
if (features.wildcardSSH) {
533+
"${getHostPrefix()}--${workspace.ownerName}--${workspace.name}.${agent.name}"
534+
}else {
535+
// For a user's own workspace, we use the old syntax without a username for backwards compatibility,
536+
// since the user might have recent connections that still use the old syntax.
537+
if (currentUser.username== workspace.ownerName) {
538+
"coder-jetbrains--${workspace.name}.${agent.name}--${deploymentURL.safeHost()}"
539+
}else {
540+
"coder-jetbrains--${workspace.ownerName}--${workspace.name}.${agent.name}--${deploymentURL.safeHost()}"
541+
}
542+
}
543+
544+
fungetBackgroundHostName(
545+
workspace:Workspace,
546+
currentUser:User,
547+
agent:WorkspaceAgent,
548+
):String=
549+
if (features.wildcardSSH) {
550+
"${getHostPrefix()}-bg--${workspace.ownerName}--${workspace.name}.${agent.name}"
551+
}else {
552+
getHostName(workspace, currentUser, agent)+"--bg"
553+
}
554+
496555
companionobject {
497556
val logger=Logger.getInstance(CoderCLIManager::class.java.simpleName)
498557

499558
privateval tokenRegex="--token [^ ]+".toRegex()
500559

501-
/**
502-
* This function returns the ssh host name generated for connecting to the workspace.
503-
*/
504-
@JvmStatic
505-
fungetHostName(
506-
url:URL,
507-
workspace:Workspace,
508-
currentUser:User,
509-
agent:WorkspaceAgent,
510-
):String=
511-
// For a user's own workspace, we use the old syntax without a username for backwards compatibility,
512-
// since the user might have recent connections that still use the old syntax.
513-
if (currentUser.username== workspace.ownerName) {
514-
"coder-jetbrains--${workspace.name}.${agent.name}--${url.safeHost()}"
515-
}else {
516-
"coder-jetbrains--${workspace.ownerName}--${workspace.name}.${agent.name}--${url.safeHost()}"
517-
}
518-
519-
fungetBackgroundHostName(
520-
url:URL,
521-
workspace:Workspace,
522-
currentUser:User,
523-
agent:WorkspaceAgent,
524-
):String= getHostName(url, workspace, currentUser, agent)+"--bg"
525-
526560
/**
527561
* This function returns the identifier for the workspace to pass to the
528562
* coder ssh proxy command.
@@ -536,6 +570,18 @@ class CoderCLIManager(
536570
@JvmStatic
537571
fungetBackgroundHostName(
538572
hostname:String,
539-
):String= hostname+"--bg"
573+
):String {
574+
val parts= hostname.split("--").toMutableList()
575+
if (parts.size<2) {
576+
throwSSHConfigFormatException("Invalid hostname:$hostname")
577+
}
578+
// non-wildcard case
579+
if (parts[0]=="coder-jetbrains") {
580+
return hostname+"--bg"
581+
}
582+
// wildcard case
583+
parts[0]+="-bg"
584+
return parts.joinToString("--")
585+
}
540586
}
541587
}

‎src/main/kotlin/com/coder/gateway/util/LinkHandler.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,11 @@ open class LinkHandler(
111111
}
112112

113113
indicator?.invoke("Configuring Coder CLI...")
114-
cli.configSsh(workspacesAndAgents= client.withAgents(workspaces), currentUser= client.me)
114+
if (cli.features.wildcardSSH) {
115+
cli.configSsh(workspacesAndAgents= emptySet(), currentUser= client.me)
116+
}else {
117+
cli.configSsh(workspacesAndAgents= client.withAgents(workspaces), currentUser= client.me)
118+
}
115119

116120
val openDialog=
117121
parameters.ideProductCode().isNullOrBlank()||
@@ -127,7 +131,7 @@ open class LinkHandler(
127131
verifyDownloadLink(parameters)
128132
WorkspaceProjectIDE.fromInputs(
129133
name=CoderCLIManager.getWorkspaceParts(workspace, agent),
130-
hostname=CoderCLIManager.getHostName(deploymentURL.toURL(), workspace, client.me, agent),
134+
hostname=CoderCLIManager(deploymentURL.toURL(),settings).getHostName(workspace, client.me, agent),
131135
projectPath= parameters.folder(),
132136
ideProductCode= parameters.ideProductCode(),
133137
ideBuildNumber= parameters.ideBuildNumber(),

‎src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspaceProjectIDEStepView.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,11 @@ class CoderWorkspaceProjectIDEStepView(
199199
logger.info("Configuring Coder CLI...")
200200
cbIDE.renderer=IDECellRenderer("Configuring Coder CLI...")
201201
withContext(Dispatchers.IO) {
202-
data.cliManager.configSsh(data.client.withAgents(data.workspaces), data.client.me)
202+
if (data.cliManager.features.wildcardSSH) {
203+
data.cliManager.configSsh(emptySet(), data.client.me)
204+
}else {
205+
data.cliManager.configSsh(data.client.withAgents(data.workspaces), data.client.me)
206+
}
203207
}
204208

205209
val ides=
@@ -214,7 +218,7 @@ class CoderWorkspaceProjectIDEStepView(
214218
}else {
215219
IDECellRenderer(CoderGatewayBundle.message("gateway.connector.view.coder.connect-ssh"))
216220
}
217-
val executor= createRemoteExecutor(CoderCLIManager.getBackgroundHostName(data.client.url,data.workspace, data.client.me, data.agent))
221+
val executor= createRemoteExecutor(CoderCLIManager(data.client.url).getBackgroundHostName(data.workspace, data.client.me, data.agent))
218222

219223
if (ComponentValidator.getInstance(tfProject).isEmpty) {
220224
logger.info("Installing remote path validator...")
@@ -404,7 +408,7 @@ class CoderWorkspaceProjectIDEStepView(
404408
overridefundata():WorkspaceProjectIDE= withoutNull(cbIDE.selectedItem, state) { selectedIDE, state->
405409
selectedIDE.withWorkspaceProject(
406410
name=CoderCLIManager.getWorkspaceParts(state.workspace, state.agent),
407-
hostname=CoderCLIManager.getHostName(state.client.url,state.workspace, state.client.me, state.agent),
411+
hostname=CoderCLIManager(state.client.url).getHostName(state.workspace, state.client.me, state.agent),
408412
projectPath= tfProject.text,
409413
deploymentURL= state.client.url,
410414
)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# --- START CODER JETBRAINS test.coder.invalid
2+
Host coder-jetbrains-test.coder.invalid--*
3+
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --url https://test.coder.invalid ssh --stdio --ssh-host-prefix coder-jetbrains-test.coder.invalid-- %h
4+
ConnectTimeout 0
5+
StrictHostKeyChecking no
6+
UserKnownHostsFile /dev/null
7+
LogLevel ERROR
8+
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
9+
10+
Host coder-jetbrains-test.coder.invalid-bg--*
11+
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config --url https://test.coder.invalid ssh --stdio --ssh-host-prefix coder-jetbrains-test.coder.invalid-bg-- %h
12+
ConnectTimeout 0
13+
StrictHostKeyChecking no
14+
UserKnownHostsFile /dev/null
15+
LogLevel ERROR
16+
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
17+
# --- END CODER JETBRAINS test.coder.invalid

‎src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,15 @@ internal class CoderCLIManagerTest {
419419
output="multiple-agents",
420420
remove="blank",
421421
),
422+
SSHTest(
423+
listOf(workspace),
424+
input=null,
425+
output="wildcard",
426+
remove="blank",
427+
features=Features(
428+
wildcardSSH=true,
429+
),
430+
),
422431
)
423432

424433
val newlineRe="\r?\n".toRegex()
@@ -804,7 +813,7 @@ internal class CoderCLIManagerTest {
804813
listOf(
805814
Pair("2.5.0",Features(true)),
806815
Pair("2.13.0",Features(true,true)),
807-
Pair("4.9.0",Features(true,true)),
816+
Pair("4.9.0",Features(true,true,true)),
808817
Pair("2.4.9",Features(false)),
809818
Pair("1.0.1",Features(false)),
810819
)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp