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

Use wildcard SSH config Host entries#521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
bcpeinhardt merged 3 commits intocoder:mainfromaaronlehmann:wildcard-ssh
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletionsCHANGELOG.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,10 @@

##Unreleased

###Changed

- Simplifies the written SSH config and avoids the need to make an API request for every workspace the filter returns.
Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

LGTM


##2.17.0 - 2025-01-27

###Added
Expand Down
122 changes: 84 additions & 38 deletionssrc/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -115,6 +115,7 @@
data class Features(
val disableAutostart: Boolean = false,
val reportWorkspaceUsage: Boolean = false,
val wildcardSSH: Boolean = false,
)

/**
Expand DownExpand Up@@ -285,37 +286,57 @@
} else {
""
}
val sshOpts = """
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel ERROR
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
""".trimIndent()
val blockContent =
if (feats.wildcardSSH) {
startBlock + System.lineSeparator() +
"""
Host ${getHostPrefix()}--*
ProxyCommand ${proxyArgs.joinToString(" ")} --ssh-host-prefix ${getHostPrefix()}-- %h
""".trimIndent()
.plus("\n" + sshOpts.prependIndent(" "))
.plus(extraConfig)
.plus("\n\n")
.plus(
"""
Host ${getHostPrefix()}-bg--*
ProxyCommand ${backgroundProxyArgs.joinToString(" ")} --ssh-host-prefix ${getHostPrefix()}-bg-- %h
""".trimIndent()
.plus("\n" + sshOpts.prependIndent(" "))
.plus(extraConfig),
).replace("\n", System.lineSeparator()) +
System.lineSeparator() + endBlock

} else {
workspaceNames.joinToString(
System.lineSeparator(),
startBlock + System.lineSeparator(),
System.lineSeparator() + endBlock,
transform = {
"""
Host ${getHostName(deploymentURL,it.first, currentUser, it.second)}
Host ${getHostName(it.first, currentUser, it.second)}
ProxyCommand ${proxyArgs.joinToString(" ")} ${getWorkspaceParts(it.first, it.second)}
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel ERROR
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
""".trimIndent()
.plus("\n" + sshOpts.prependIndent(" "))
.plus(extraConfig)
.plus("\n")
.plus(
"""
Host ${getBackgroundHostName(deploymentURL,it.first, currentUser, it.second)}
Host ${getBackgroundHostName(it.first, currentUser, it.second)}
ProxyCommand ${backgroundProxyArgs.joinToString(" ")} ${getWorkspaceParts(it.first, it.second)}
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel ERROR
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
""".trimIndent()
.plus("\n" + sshOpts.prependIndent(" "))
.plus(extraConfig),
).replace("\n", System.lineSeparator())
},
)
}

if (contents == null) {
logger.info("No existing SSH config to modify")
Expand DownExpand Up@@ -462,7 +483,7 @@
coderConfigPath.toString(),
"start",
"--yes",
workspaceOwner+"/"+workspaceName,

Check notice on line 486 in src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt

View workflow job for this annotation

GitHub Actions/ Build

String concatenation that can be converted to string template

'String' concatenation can be converted to a template
)
}

Expand All@@ -489,40 +510,53 @@
Features(
disableAutostart = version >= SemVer(2, 5, 0),
reportWorkspaceUsage = version >= SemVer(2, 13, 0),
wildcardSSH = version >= SemVer(2, 19, 0),
)
}
}

/*
* This function returns the ssh-host-prefix used for Host entries.
*/
fun getHostPrefix(): String =

Check notice on line 521 in src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt

View workflow job for this annotation

GitHub Actions/ Build

Class member can have 'private' visibility

Function 'getHostPrefix' could be private
"coder-jetbrains-${deploymentURL.safeHost()}"

/**
* This function returns the ssh host name generated for connecting to the workspace.
*/
fun getHostName(
workspace: Workspace,
currentUser: User,
agent: WorkspaceAgent,
): String =
if (features.wildcardSSH) {
"${getHostPrefix()}--${workspace.ownerName}--${workspace.name}.${agent.name}"
} else {
// For a user's own workspace, we use the old syntax without a username for backwards compatibility,
// since the user might have recent connections that still use the old syntax.
if (currentUser.username == workspace.ownerName) {
"coder-jetbrains--${workspace.name}.${agent.name}--${deploymentURL.safeHost()}"
} else {
"coder-jetbrains--${workspace.ownerName}--${workspace.name}.${agent.name}--${deploymentURL.safeHost()}"
}
}

fun getBackgroundHostName(
workspace: Workspace,
currentUser: User,
agent: WorkspaceAgent,
): String =
if (features.wildcardSSH) {
"${getHostPrefix()}-bg--${workspace.ownerName}--${workspace.name}.${agent.name}"
} else {
getHostName(workspace, currentUser, agent) + "--bg"
}

companion object {
val logger = Logger.getInstance(CoderCLIManager::class.java.simpleName)

private val tokenRegex = "--token [^ ]+".toRegex()

/**
* This function returns the ssh host name generated for connecting to the workspace.
*/
@JvmStatic
fun getHostName(
url: URL,
workspace: Workspace,
currentUser: User,
agent: WorkspaceAgent,
): String =
// For a user's own workspace, we use the old syntax without a username for backwards compatibility,
// since the user might have recent connections that still use the old syntax.
if (currentUser.username == workspace.ownerName) {
"coder-jetbrains--${workspace.name}.${agent.name}--${url.safeHost()}"
} else {
"coder-jetbrains--${workspace.ownerName}--${workspace.name}.${agent.name}--${url.safeHost()}"
}

fun getBackgroundHostName(
url: URL,
workspace: Workspace,
currentUser: User,
agent: WorkspaceAgent,
): String = getHostName(url, workspace, currentUser, agent) + "--bg"

/**
* This function returns the identifier for the workspace to pass to the
* coder ssh proxy command.
Expand All@@ -536,6 +570,18 @@
@JvmStatic
fun getBackgroundHostName(
hostname: String,
): String = hostname + "--bg"
): String {
val parts = hostname.split("--").toMutableList()
if (parts.size < 2) {
throw SSHConfigFormatException("Invalid hostname: $hostname")
}
// non-wildcard case
if (parts[0] == "coder-jetbrains") {
return hostname + "--bg"

Check notice on line 580 in src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt

View workflow job for this annotation

GitHub Actions/ Build

String concatenation that can be converted to string template

'String' concatenation can be converted to a template
}
// wildcard case
parts[0] += "-bg"
return parts.joinToString("--")
}
}
}
8 changes: 6 additions & 2 deletionssrc/main/kotlin/com/coder/gateway/util/LinkHandler.kt
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,11 @@ open class LinkHandler(
}

indicator?.invoke("Configuring Coder CLI...")
cli.configSsh(workspacesAndAgents = client.withAgents(workspaces), currentUser = client.me)
if (cli.features.wildcardSSH) {
cli.configSsh(workspacesAndAgents = emptySet(), currentUser = client.me)
} else {
cli.configSsh(workspacesAndAgents = client.withAgents(workspaces), currentUser = client.me)
}

val openDialog =
parameters.ideProductCode().isNullOrBlank() ||
Expand All@@ -127,7 +131,7 @@ open class LinkHandler(
verifyDownloadLink(parameters)
WorkspaceProjectIDE.fromInputs(
name = CoderCLIManager.getWorkspaceParts(workspace, agent),
hostname = CoderCLIManager.getHostName(deploymentURL.toURL(), workspace, client.me, agent),
hostname = CoderCLIManager(deploymentURL.toURL(),settings).getHostName(workspace, client.me, agent),
projectPath = parameters.folder(),
ideProductCode = parameters.ideProductCode(),
ideBuildNumber = parameters.ideBuildNumber(),
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,7 +208,11 @@
logger.info("Configuring Coder CLI...")
cbIDE.renderer = IDECellRenderer("Configuring Coder CLI...")
withContext(Dispatchers.IO) {
data.cliManager.configSsh(data.client.withAgents(data.workspaces), data.client.me)
if (data.cliManager.features.wildcardSSH) {
data.cliManager.configSsh(emptySet(), data.client.me)
} else {
data.cliManager.configSsh(data.client.withAgents(data.workspaces), data.client.me)
}
}

val ides =
Expand All@@ -223,7 +227,7 @@
} else {
IDECellRenderer(CoderGatewayBundle.message("gateway.connector.view.coder.connect-ssh"))
}
val executor = createRemoteExecutor(CoderCLIManager.getBackgroundHostName(data.client.url,data.workspace, data.client.me, data.agent))
val executor = createRemoteExecutor(CoderCLIManager(data.client.url).getBackgroundHostName(data.workspace, data.client.me, data.agent))

if (ComponentValidator.getInstance(tfProject).isEmpty) {
logger.info("Installing remote path validator...")
Expand DownExpand Up@@ -269,7 +273,7 @@
)

// Check the provided setting to see if there's a default IDE to set.
val defaultIde = ides.find { it ->

Check notice on line 276 in src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspaceProjectIDEStepView.kt

View workflow job for this annotation

GitHub Actions/ Build

Redundant lambda arrow

Redundant lambda arrow
// Using contains on the displayable version of the ide means they can be as specific or as vague as they want
// CL 2023.3.6 233.15619.8 -> a specific Clion build
// CL 2023.3.6 -> a specific Clion version
Expand DownExpand Up@@ -428,7 +432,7 @@
override fun data(): WorkspaceProjectIDE = withoutNull(cbIDE.selectedItem, state) { selectedIDE, state ->
selectedIDE.withWorkspaceProject(
name = CoderCLIManager.getWorkspaceParts(state.workspace, state.agent),
hostname = CoderCLIManager.getHostName(state.client.url,state.workspace, state.client.me, state.agent),
hostname = CoderCLIManager(state.client.url).getHostName(state.workspace, state.client.me, state.agent),
projectPath = tfProject.text,
deploymentURL = state.client.url,
)
Expand Down
17 changes: 17 additions & 0 deletionssrc/test/fixtures/outputs/wildcard.conf
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains-test.coder.invalid--*
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
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel ERROR
SetEnv CODER_SSH_SESSION_TYPE=JetBrains

Host coder-jetbrains-test.coder.invalid-bg--*
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
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel ERROR
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
# --- END CODER JETBRAINS test.coder.invalid
11 changes: 10 additions & 1 deletionsrc/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -419,6 +419,15 @@ internal class CoderCLIManagerTest {
output = "multiple-agents",
remove = "blank",
),
SSHTest(
listOf(workspace),
input = null,
output = "wildcard",
remove = "blank",
features = Features(
wildcardSSH = true,
),
),
)

val newlineRe = "\r?\n".toRegex()
Expand DownExpand Up@@ -804,7 +813,7 @@ internal class CoderCLIManagerTest {
listOf(
Pair("2.5.0", Features(true)),
Pair("2.13.0", Features(true, true)),
Pair("4.9.0", Features(true, true)),
Pair("4.9.0", Features(true, true, true)),
Pair("2.4.9", Features(false)),
Pair("1.0.1", Features(false)),
)
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp