Skip to content

feat: coder connect integration #482

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

ethanndickson
Copy link
Member

@ethanndickson ethanndickson commented Apr 17, 2025

Closes #447.

On both macOS and Windows, with Coder Connect running, I've tested that:

  • Opening a workspace from the sidebar uses Coder Connect
  • Opening a workspace from the command palette uses Coder Connect
  • Opening a workspace from a vscode:// URI uses Coder Connect
  • Opening an unowned workspace fallsback to using the Coder CLI, as Connect doesn't support shared workspaces yet.
  • Opening a stopped workspace fallsback to using the Coder CLI in order to prompt the user to start the workspace first. If Coder Connect is available after the build, it'll switch to using that tunnel.
  • Opening a Coder extension workspace in the VSCode history, like so, image switches to the Connect tunnel.

Including the connection status indicator when using Connect is out of scope of the linked issue and this PR, as Coder Desktop does not currently expose those values in any way.

I recommend reviewing the PR with whitespace diffs disabled.

Copy link
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

src/commands.ts Outdated
@@ -491,12 +507,30 @@ export class Commands {
} else {
workspaceOwner = args[0] as string
workspaceName = args[1] as string
// workspaceAgent is reserved for args[2], but multiple agents aren't supported yet.
workspaceAgent = args[2] as string
Copy link
Member Author

@ethanndickson ethanndickson Apr 17, 2025

Choose a reason for hiding this comment

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

The URI handler does indeed populate the agent name in args[2], but it may be undefined.

vscode.commands.executeCommand("coder.open", owner, workspace, agent, folder, openRecent)

The original comment is years out of date.

@@ -353,7 +353,7 @@ export class WorkspaceTreeItem extends OpenableTreeItem {
showOwner ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.Expanded,
workspace.owner_name,
workspace.name,
undefined,
agents[0]?.name,
Copy link
Member Author

@ethanndickson ethanndickson Apr 17, 2025

Choose a reason for hiding this comment

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

This saves us needing to fetch the agent in openFromSidebar for a single-agent workspace.
openFromSidebar isn't callable on workspaces with multiple agents, so the undefined there is fine.
if the workspace is stopped, this will be undefined, prompting openWorkspace to always use the CLI instead of Connect.

@ethanndickson ethanndickson marked this pull request as ready for review April 17, 2025 03:02
@matifali
Copy link
Member

Including the connection status indicator when using Connect is out of scope of the linked issue and this PR, as Coder Desktop does not currently expose those values in any way.

This may be possible after we have coder/coder-desktop-macos#64

Opening an unowned workspace fallsback to using the Coder CLI, as Connect doesn't support shared workspaces yet.

Does this mean we only use the CLI to start the workspace and later again connect via Coder Connect?

@ethanndickson
Copy link
Member Author

ethanndickson commented Apr 17, 2025

This may be possible after we have coder/coder-desktop-macos#64

Unfortunately, getting connection stats from the network extension to the desktop app is just one part. We also need to expose them programmatically in order for the VSCode extension to read them.

Does this mean we only use the CLI to start the workspace and later again connect via Coder Connect?

As of my last commit, yep! You can start a workspace, watch it build in VSCode, and then once the build is finished VSCode will switch over to using the Connect tunnel.

@DanielleMaywood
Copy link
Collaborator

Connecting to a dev container inside a Coder workspace also makes use of SSH. Should that also be updated?

@matifali
Copy link
Member

What will happen if the Coder Connect tunnel breaks due to an upgrade, or is turned off, or whatever? DO we gracefully fall back to CLI?
Ideally, the user should not have to reconnect manually or reload the VS Code window.

Copy link
Member

@code-asher code-asher left a comment

Choose a reason for hiding this comment

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

I have not ran it yet but left some thoughts!

src/commands.ts Outdated
let sshConfig
try {
// Fetch (or get defaults) for the SSH config.
sshConfig = await fetchSSHConfig(this.restClient, this.vscodeProposed)
Copy link
Member

Choose a reason for hiding this comment

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

The extension has an SSH config section which I assume is not going apply to Coder Connect, is that right? As well as anything the user has added to their SSH config manually.

Wondering if we should update the setting description to say the variables will not apply if there is a Coder Connect session we can use.

Speaking of settings, should using Coder Connect be behind a setting as well? Or a prompt? "We see Coder Connect, do you want to use that?" or similar.

Copy link
Member Author

@ethanndickson ethanndickson Apr 18, 2025

Choose a reason for hiding this comment

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

Wondering if we should update the setting description to say the variables will not apply if there is a Coder Connect session we can use.

Will add.

As well as anything the user has added to their SSH config manually.

These will apply, as long as they're on the Coder Connect hostname (so, if they just specify those options when running coder config-ssh it'll get added to *.<hostnamesuffix>).

Speaking of settings, should using Coder Connect be behind a setting as well? Or a prompt? "We see Coder Connect, do you want to use that?" or similar.

I don't think this is necessary, I can't imagine a scenario where the user would have Coder Connect on and not want to use it?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is necessary, I can't imagine a scenario where the user would have Coder Connect on and not want to use it?

I agree.

Copy link
Member

@code-asher code-asher Apr 19, 2025

Choose a reason for hiding this comment

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

I think the tricky part is that the user might not realize it will use Connect. So, they have X11Forwarding yes in their VS Code config or in their SSH config under Host coder-vscode--*, they are trying out Connect, one day they update the plugin, and suddenly no more forwarding. Some days it does forward, some days does not, depending on whether Connect is up (idk if this is realistic usage/behavior though).

So there should be clear messaging what the plugin is going to do IMO, somewhere. Silently changing behavior feels bad to me. But, I am neither a VS Code nor Connect user, so take what I say with a grain of salt. 😆 Maybe the behavior change will be obvious to users.

If we could make the same SSH settings apply either way, then that would be a different story.

Copy link
Member Author

@ethanndickson ethanndickson Apr 21, 2025

Choose a reason for hiding this comment

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

If we could make the same SSH settings apply either way, then that would be a different story.

With the updated coder ssh-config, any options applied to that will also apply to Coder Connect via VSCode, at least.

Though if we change the approach to what I discussed below that solves this issue too ig

Copy link
Member

Choose a reason for hiding this comment

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

With the updated coder ssh-config, any options applied to that will also apply to Coder Connect via VSCode, at least.

That is quite nice!

sshConfig.hostname_suffix,
)
if (coderConnectAddr) {
remoteAuthority = `ssh-remote+${coderConnectAddr}`
Copy link
Member

Choose a reason for hiding this comment

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

Probably a dumb question, but this can result in multiple host names for the same workspace/agent? One for Connect, one for the fallback. Will that be potentially confusing, for example in the recents list I imagine it could show both? I know for the fallback we reopen with Connect if we can, but it does seem unfortunate to have both.

Is there any world where we use Connect if possible as part of the proxy command or does it have to be in the extension itself? That would make it trivial to implement for other IDEs and would let us reuse the same host name (and I suppose it would make it work for ssh <vscode host> on the command line too, although idk why someone would do that except for debugging). I would dread having to do this for Toolbox, if we even can. 😨

Copy link
Member Author

@ethanndickson ethanndickson Apr 18, 2025

Choose a reason for hiding this comment

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

I would dread having to do this for Toolbox, if we even can.

It looks like Toolbox & regular Jetbrains don't use wildcard SSH configs? I think that makes implementing this on those a lot easier:

Match host coder-jetbrains-toolbox-foo--test.coder.bar exec "/path/to/coder connect exists agent1.foo.owner.coder"
  HostName agent1.foo.owner.coder
Host coder-jetbrains-toolbox-foo--test.coder.bar
  ProxyCommand /path/to/coder ssh owner/foo.agent1
  ConnectTimeout 0
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  LogLevel ERROR
  SetEnv CODER_SSH_SESSION_TYPE=JetBrains

This is similar to how the new coder config-ssh works, we only use the ProxyCommand if the DNS record doesn't exist, which we check using coder connect exists.

Since we use wildcard configs for the VSCode extension, using just the SSH config is pretty complicated. We'd need coder connect exists to be able to handle an argument of the form <owner>--<workspace>.<agent>. Then, we'd need another command to translate <owner>--<workspace>.<agent> to <agent>.<workspace>.<owner>.<hostnamesuffix> if coder connect exists returned 0.

I assume it would look something like:

Host coder-vscode.dev.coder.com--* exec "/path/to/coder connect exists %h"
  ProxyCommand ssh "$(coder connect convert %h)

In both exists and convert, we'd need to auth with coderd to retrieve the hostname suffix, and then if the agent is missing from the authority string, we'd also need to resolve that somehow.

I think this approach is just too slow; two CLI invocations that need to init a codersdk.Client after reading from disk. Right now coder connect exists doesn't need to do that.

Alternatively, we could change the portion after coder-vscode.dev.coder.com--, to <agent>.<workspace>.<owner>.<hostnamesuffix>, but coder ssh doesn't support that right now, and we'd still need to fetch the hostnamesuffix in the extension.
This might be worth doing? We just only set the new hostname in the remote authority if the Coder CLI would support it.

However, it might be a big lift to ensure each plugin knows what agent it's connecting to before calling SSH. Right now the Coder CLI handles that if it's not supplied in the remote authority slug.

Will that be potentially confusing, for example in the recents list I imagine it could show both?

But yeah, it does show both unfortunately. WDYT about the alternatives?

Copy link
Member

Choose a reason for hiding this comment

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

Toolbox does use wildcard hostnames by default, with an option to opt out. see the sample config from my system

# --- START CODER JETBRAINS TOOLBOX dev.coder.com
Host coder-jetbrains-toolbox-dev.coder.com--*
  ProxyCommand "/Users/matifali/Library/Application Support/coder-toolbox/dev.coder.com/coder-darwin-arm64" --global-config "/Users/matifali/Library/Application Support/coder-toolbox/dev.coder.com/config" --url https://dev.coder.com ssh --stdio --disable-autostart --usage-app=jetbrains --ssh-host-prefix coder-jetbrains-toolbox-dev.coder.com-- %h
  ConnectTimeout 0
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  LogLevel ERROR
  SetEnv CODER_SSH_SESSION_TYPE=JetBrains

Host coder-jetbrains-toolbox-dev.coder.com-bg--*
  ProxyCommand "/Users/matifali/Library/Application Support/coder-toolbox/dev.coder.com/coder-darwin-arm64" --global-config "/Users/matifali/Library/Application Support/coder-toolbox/dev.coder.com/config" --url https://dev.coder.com ssh --stdio --disable-autostart --usage-app=disable --ssh-host-prefix coder-jetbrains-toolbox-dev.coder.com-bg-- %h
  ConnectTimeout 0
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  LogLevel ERROR
  SetEnv CODER_SSH_SESSION_TYPE=JetBrains
# --- END CODER JETBRAINS TOOLBOX dev.coder.com

Copy link
Member

@code-asher code-asher Apr 19, 2025

Choose a reason for hiding this comment

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

Yeah, we do use wildcards in Gateway and Toolbox now. I do not think we will be able to switch the hostname from out of under Toolbox like we can here in VS Code unfortunately (at least not the way it is currently implemented, maybe it can if we implement our own connector instead of using their SSH stuff but idk if that is possible). 😢 If we can implement purely in the SSH config and CLI, that would be ideal.

IDK the best way to do it, but my initial thought would be to make coder ssh handle it. Maybe it should be behind a --use-connect flag or something, but basically it would just do whatever coder connect convert is doing, right? It could even do the exists part as well, if we want to avoid writing new blocks.

IMO remote editing from the IDE's point of view should be more or less just ssh <hostname> and we can hide away and reuse all this logic in the CLI.

Copy link
Member

@code-asher code-asher Apr 19, 2025

Choose a reason for hiding this comment

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

But, I do like the example you have as well. How slow are we talking? Some extra seconds to connect may not be the worst thing, if it reduces complexity on our end and makes it possible to support Connect with Toolbox.

Copy link
Member

Choose a reason for hiding this comment

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

Not directly related but with toolbox JB uses the system ssh and support all SSH options. In gateway they had a built-in SSH implementation that didn't support all options.

Copy link
Member Author

@ethanndickson ethanndickson Apr 21, 2025

Choose a reason for hiding this comment

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

We decided against making it part of coder ssh because of the performance cost of a bicopy on the SSH connection. That's what led us to add coder connect exists for config-ssh.

How slow are we talking?

Honestly, it might be negligible on macOS and Linux. On the other hand, Spike discovered that coder connect exists takes almost 1.5s on Windows, and that's literally just to execute the binary and do a DNS lookup, so I'd expect this approach to be significantly slower there.

Copy link
Member

@code-asher code-asher Apr 21, 2025

Choose a reason for hiding this comment

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

Ahhh, fair. Was the performance cost of the bicopy measured? It does sound unfortunate.

1.5s for running exists is wild lol, I guess that is Windows for ya.

IMO we have a few paths forward, ideally we figure out which one before merging since this may inform how we should do it here as well:

  1. Do it somehow in the SSH config to support Toolbox
  2. Decide not to support Toolbox
  3. Figure out if there is a different way we can support Toolbox

But also do not let me just be a blocker if we need to move forward for now haha. I do think the doubled-up host names and the SSH settings have the potential to cause some discomfort though.

It occurs to me that if we had our own connection code instead of delegating to Microsoft's plugin, we could transparently use a different host name under the connection without doubling up on them. We could name the recent connections anything we wanted at that point. We could even add settings at that point too, I think?? 🤔

@ethanndickson
Copy link
Member Author

ethanndickson commented Apr 18, 2025

What will happen if the Coder Connect tunnel breaks due to an upgrade, or is turned off, or whatever? DO we gracefully fall back to CLI?

We don't currently. We'd need to watch for disconnect events from VSCode (assuming it exposes those via it's extension API), and react accordingly.

@matifali
Copy link
Member

We don't currently. We'd need to watch for disconnect events from VSCode (assuming it exposes those via it's extension API), and react accordingly.

I think this should be next in our priority, given how important it is to provide a seamless connection.

@deansheather deansheather removed their request for review April 22, 2025 01:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Coder Desktop Integration
5 participants