@@ -4,10 +4,12 @@ import (
4
4
"context"
5
5
"fmt"
6
6
"io/ioutil"
7
+ "net"
7
8
"net/url"
8
9
"os"
9
10
"path/filepath"
10
11
"strings"
12
+ "time"
11
13
12
14
"cdr.dev/coder-cli/internal/config"
13
15
"cdr.dev/coder-cli/internal/entclient"
@@ -32,7 +34,7 @@ func (cmd *configSSHCmd) Spec() cli.CommandSpec {
32
34
return cli.CommandSpec {
33
35
Name : "config-ssh" ,
34
36
Usage : "" ,
35
- Desc : "adds your Coder Enterprise environments to ~/.ssh/config" ,
37
+ Desc : "add your Coder Enterprise environments to ~/.ssh/config" ,
36
38
}
37
39
}
38
40
@@ -82,6 +84,11 @@ func (cmd *configSSHCmd) Run(fl *pflag.FlagSet) {
82
84
83
85
entClient := requireAuth ()
84
86
87
+ sshAvailable := cmd .ensureSSHAvailable (ctx )
88
+ if ! sshAvailable {
89
+ flog .Fatal ("SSH is disabled or not available for your Coder Enterprise deployment." )
90
+ }
91
+
85
92
me , err := entClient .Me ()
86
93
if err != nil {
87
94
flog .Fatal ("failed to fetch username: %v" , err )
@@ -129,18 +136,14 @@ func writeSSHKey(ctx context.Context, client *entclient.Client) error {
129
136
}
130
137
131
138
func (cmd * configSSHCmd ) makeNewConfigs (userName string , envs []entclient.Environment ) (string , error ) {
132
- u , err := config . URL . Read ()
139
+ hostname , err := configuredHostname ()
133
140
if err != nil {
134
- return "" , err
135
- }
136
- url , err := url .Parse (u )
137
- if err != nil {
138
- return "" , err
141
+ return "" , nil
139
142
}
140
143
141
144
newConfig := fmt .Sprintf ("\n %s\n %s\n \n " , cmd .startToken , cmd .startMessage )
142
145
for _ , env := range envs {
143
- newConfig += cmd .makeConfig (url . Hostname () , userName , env .Name )
146
+ newConfig += cmd .makeConfig (hostname , userName , env .Name )
144
147
}
145
148
newConfig += fmt .Sprintf ("\n %s\n " , cmd .endToken )
146
149
@@ -158,6 +161,32 @@ func (cmd *configSSHCmd) makeConfig(host, userName, envName string) string {
158
161
` , envName , host , userName , envName , privateKeyFilepath )
159
162
}
160
163
164
+ func (cmd * configSSHCmd ) ensureSSHAvailable (ctx context.Context ) bool {
165
+ ctx , cancel := context .WithTimeout (ctx , 3 * time .Second )
166
+ defer cancel ()
167
+
168
+ host , err := configuredHostname ()
169
+ if err != nil {
170
+ return false
171
+ }
172
+
173
+ var dialer net.Dialer
174
+ _ , err = dialer .DialContext (ctx , "tcp" , net .JoinHostPort (host , "22" ))
175
+ return err == nil
176
+ }
177
+
178
+ func configuredHostname () (string , error ) {
179
+ u , err := config .URL .Read ()
180
+ if err != nil {
181
+ return "" , err
182
+ }
183
+ url , err := url .Parse (u )
184
+ if err != nil {
185
+ return "" , err
186
+ }
187
+ return url .Hostname (), nil
188
+ }
189
+
161
190
func writeStr (filename , data string ) error {
162
191
return ioutil .WriteFile (filename , []byte (data ), 0777 )
163
192
}
0 commit comments