1
1
import { isAxiosError } from "axios"
2
2
import { Api } from "coder/site/src/api/api"
3
- import { Workspace } from "coder/site/src/api/typesGenerated"
3
+ import { SSHConfigResponse , Workspace } from "coder/site/src/api/typesGenerated"
4
4
import find from "find-process"
5
5
import * as fs from "fs/promises"
6
6
import * as jsonc from "jsonc-parser"
@@ -9,7 +9,14 @@ import * as path from "path"
9
9
import prettyBytes from "pretty-bytes"
10
10
import * as semver from "semver"
11
11
import * as vscode from "vscode"
12
- import { createHttpAgent , makeCoderSdk , needToken , startWorkspaceIfStoppedOrFailed , waitForBuild } from "./api"
12
+ import {
13
+ createHttpAgent ,
14
+ fetchSSHConfig ,
15
+ makeCoderSdk ,
16
+ needToken ,
17
+ startWorkspaceIfStoppedOrFailed ,
18
+ waitForBuild ,
19
+ } from "./api"
13
20
import { extractAgents } from "./api-helper"
14
21
import * as cli from "./cliManager"
15
22
import { Commands } from "./commands"
@@ -19,7 +26,7 @@ import { Inbox } from "./inbox"
19
26
import { SSHConfig , SSHValues , mergeSSHConfigValues } from "./sshConfig"
20
27
import { computeSSHProperties , sshSupportsSetEnv } from "./sshSupport"
21
28
import { Storage } from "./storage"
22
- import { AuthorityPrefix , expandPath , parseRemoteAuthority } from "./util"
29
+ import { AuthorityPrefix , expandPath , maybeCoderConnectAddr , parseRemoteAuthority } from "./util"
23
30
import { WorkspaceMonitor } from "./workspaceMonitor"
24
31
25
32
export interface RemoteDetails extends vscode . Disposable {
@@ -469,9 +476,19 @@ export class Remote {
469
476
//
470
477
// If we didn't write to the SSH config file, connecting would fail with
471
478
// "Host not found".
479
+ let sshConfigResponse : SSHConfigResponse
472
480
try {
473
481
this . storage . writeToCoderOutputChannel ( "Updating SSH config..." )
474
- await this . updateSSHConfig ( workspaceRestClient , parts . label , parts . host , binaryPath , logDir , featureSet )
482
+ sshConfigResponse = await fetchSSHConfig ( workspaceRestClient , this . vscodeProposed )
483
+ await this . updateSSHConfig (
484
+ workspaceRestClient ,
485
+ parts . label ,
486
+ parts . host ,
487
+ binaryPath ,
488
+ logDir ,
489
+ featureSet ,
490
+ sshConfigResponse ,
491
+ )
475
492
} catch ( error ) {
476
493
this . storage . writeToCoderOutputChannel ( `Failed to configure SSH: ${ error } ` )
477
494
throw error
@@ -503,6 +520,20 @@ export class Remote {
503
520
504
521
this . storage . writeToCoderOutputChannel ( "Remote setup complete" )
505
522
523
+ // If Coder Connect is available for this workspace, switch to that
524
+ const coderConnectAddr = await maybeCoderConnectAddr (
525
+ agent . name ,
526
+ parts . workspace ,
527
+ parts . username ,
528
+ sshConfigResponse . hostname_suffix ,
529
+ )
530
+ if ( coderConnectAddr ) {
531
+ await vscode . commands . executeCommand ( "vscode.newWindow" , {
532
+ remoteAuthority : `ssh-remote+${ coderConnectAddr } ` ,
533
+ reuseWindow : true ,
534
+ } )
535
+ }
536
+
506
537
// Returning the URL and token allows the plugin to authenticate its own
507
538
// client, for example to display the list of workspaces belonging to this
508
539
// deployment in the sidebar. We use our own client in here for reasons
@@ -550,30 +581,8 @@ export class Remote {
550
581
binaryPath : string ,
551
582
logDir : string ,
552
583
featureSet : FeatureSet ,
584
+ sshConfigResponse : SSHConfigResponse ,
553
585
) {
554
- let deploymentSSHConfig = { }
555
- try {
556
- const deploymentConfig = await restClient . getDeploymentSSHConfig ( )
557
- deploymentSSHConfig = deploymentConfig . ssh_config_options
558
- } catch ( error ) {
559
- if ( ! isAxiosError ( error ) ) {
560
- throw error
561
- }
562
- switch ( error . response ?. status ) {
563
- case 404 : {
564
- // Deployment does not support overriding ssh config yet. Likely an
565
- // older version, just use the default.
566
- break
567
- }
568
- case 401 : {
569
- await this . vscodeProposed . window . showErrorMessage ( "Your session expired..." )
570
- throw error
571
- }
572
- default :
573
- throw error
574
- }
575
- }
576
-
577
586
// deploymentConfig is now set from the remote coderd deployment.
578
587
// Now override with the user's config.
579
588
const userConfigSSH = vscode . workspace . getConfiguration ( "coder" ) . get < string [ ] > ( "sshConfig" ) || [ ]
@@ -596,7 +605,7 @@ export class Remote {
596
605
} ,
597
606
{ } as Record < string , string > ,
598
607
)
599
- const sshConfigOverrides = mergeSSHConfigValues ( deploymentSSHConfig , userConfig )
608
+ const sshConfigOverrides = mergeSSHConfigValues ( sshConfigResponse . ssh_config_options , userConfig )
600
609
601
610
let sshConfigFile = vscode . workspace . getConfiguration ( ) . get < string > ( "remote.SSH.configFile" )
602
611
if ( ! sshConfigFile ) {
0 commit comments