@@ -467,20 +467,27 @@ export class Remote {
467
467
// "Host not found".
468
468
try {
469
469
this . storage . writeToCoderOutputChannel ( "Updating SSH config..." )
470
- await this . updateSSHConfig ( workspaceRestClient , parts . label , parts . host , binaryPath , logDir )
470
+ await this . updateSSHConfig ( workspaceRestClient , parts . label , parts . host , binaryPath , logDir , featureSet )
471
471
} catch ( error ) {
472
472
this . storage . writeToCoderOutputChannel ( `Failed to configure SSH: ${ error } ` )
473
473
throw error
474
474
}
475
475
476
476
// TODO: This needs to be reworked; it fails to pick up reconnects.
477
- this . findSSHProcessID ( ) . then ( ( pid ) => {
477
+ this . findSSHProcessID ( ) . then ( async ( pid ) => {
478
478
if ( ! pid ) {
479
479
// TODO: Show an error here!
480
480
return
481
481
}
482
482
disposables . push ( this . showNetworkUpdates ( pid ) )
483
- this . commands . workspaceLogPath = logDir ? path . join ( logDir , `${ pid } .log` ) : undefined
483
+ if ( logDir ) {
484
+ const logFiles = await fs . readdir ( logDir )
485
+ this . commands . workspaceLogPath = logFiles
486
+ . reverse ( )
487
+ . find ( ( file ) => file === `${ pid } .log` || file . endsWith ( `-${ pid } .log` ) )
488
+ } else {
489
+ this . commands . workspaceLogPath = undefined
490
+ }
484
491
} )
485
492
486
493
// Register the label formatter again because SSH overrides it!
@@ -532,7 +539,14 @@ export class Remote {
532
539
533
540
// updateSSHConfig updates the SSH configuration with a wildcard that handles
534
541
// all Coder entries.
535
- private async updateSSHConfig ( restClient : Api , label : string , hostName : string , binaryPath : string , logDir : string ) {
542
+ private async updateSSHConfig (
543
+ restClient : Api ,
544
+ label : string ,
545
+ hostName : string ,
546
+ binaryPath : string ,
547
+ logDir : string ,
548
+ featureSet : FeatureSet ,
549
+ ) {
536
550
let deploymentSSHConfig = { }
537
551
try {
538
552
const deploymentConfig = await restClient . getDeploymentSSHConfig ( )
@@ -610,13 +624,21 @@ export class Remote {
610
624
headerArg = ` --header-command ${ escapeSubcommand ( headerCommand ) } `
611
625
}
612
626
627
+ const hostPrefix = label ? `${ AuthorityPrefix } .${ label } --` : `${ AuthorityPrefix } --`
628
+
629
+ const proxyCommand = featureSet . wildcardSSH
630
+ ? `${ escape ( binaryPath ) } ${ headerArg } --global-config ${ escape (
631
+ path . dirname ( this . storage . getSessionTokenPath ( label ) ) ,
632
+ ) } ssh --stdio --network-info-dir ${ escape ( this . storage . getNetworkInfoPath ( ) ) } ${ await this . formatLogArg ( logDir ) } --ssh-host-prefix ${ hostPrefix } %h`
633
+ : `${ escape ( binaryPath ) } ${ headerArg } vscodessh --network-info-dir ${ escape (
634
+ this . storage . getNetworkInfoPath ( ) ,
635
+ ) } ${ await this . formatLogArg ( logDir ) } --session-token-file ${ escape ( this . storage . getSessionTokenPath ( label ) ) } --url-file ${ escape (
636
+ this . storage . getUrlPath ( label ) ,
637
+ ) } %h`
638
+
613
639
const sshValues : SSHValues = {
614
- Host : label ? `${ AuthorityPrefix } .${ label } --*` : `${ AuthorityPrefix } --*` ,
615
- ProxyCommand : `${ escape ( binaryPath ) } ${ headerArg } vscodessh --network-info-dir ${ escape (
616
- this . storage . getNetworkInfoPath ( ) ,
617
- ) } ${ await this . formatLogArg ( logDir ) } --session-token-file ${ escape ( this . storage . getSessionTokenPath ( label ) ) } --url-file ${ escape (
618
- this . storage . getUrlPath ( label ) ,
619
- ) } %h`,
640
+ Host : hostPrefix + `*` ,
641
+ ProxyCommand : proxyCommand ,
620
642
ConnectTimeout : "0" ,
621
643
StrictHostKeyChecking : "no" ,
622
644
UserKnownHostsFile : "/dev/null" ,
0 commit comments