@@ -93,10 +93,6 @@ func configSSH(configpath *string, remove *bool) func(cmd *cobra.Command, _ []st
93
93
return err
94
94
}
95
95
96
- if ! isSSHAvailable (ctx ) {
97
- return xerrors .New ("SSH is disabled or not available for your Coder Enterprise deployment." )
98
- }
99
-
100
96
user , err := client .Me (ctx )
101
97
if err != nil {
102
98
return xerrors .Errorf ("fetch username: %w" , err )
@@ -109,6 +105,16 @@ func configSSH(configpath *string, remove *bool) func(cmd *cobra.Command, _ []st
109
105
if len (envs ) < 1 {
110
106
return xerrors .New ("no environments found" )
111
107
}
108
+
109
+ if ! sshAvailable (envs ) {
110
+ return xerrors .New ("SSH is disabled or not available any environments in your Coder Enterprise deployment." )
111
+ }
112
+
113
+ err = canConnectSSH (ctx )
114
+ if err != nil {
115
+ return xerrors .Errorf ("check if SSH is available: unable to connect to SSH endpoint: %w" , err )
116
+ }
117
+
112
118
newConfig , err := makeNewConfigs (user .Username , envs , startToken , startMessage , endToken , privateKeyFilepath )
113
119
if err != nil {
114
120
return xerrors .Errorf ("make new ssh configurations: %w" , err )
@@ -145,6 +151,43 @@ func configSSH(configpath *string, remove *bool) func(cmd *cobra.Command, _ []st
145
151
}
146
152
}
147
153
154
+ // sshAvailable returns true if SSH is available for at least one environment.
155
+ func sshAvailable (envs []coder.Environment ) bool {
156
+ for _ , env := range envs {
157
+ if env .SSHAvailable {
158
+ return true
159
+ }
160
+ }
161
+
162
+ return false
163
+ }
164
+
165
+ // canConnectSSH returns an error if we cannot dial the SSH port.
166
+ func canConnectSSH (ctx context.Context ) error {
167
+ ctx , cancel := context .WithTimeout (ctx , 3 * time .Second )
168
+ defer cancel ()
169
+
170
+ host , err := configuredHostname ()
171
+ if err != nil {
172
+ return xerrors .Errorf ("get configured manager hostname: %w" , err )
173
+ }
174
+
175
+ var (
176
+ dialer net.Dialer
177
+ hostPort = net .JoinHostPort (host , "22" )
178
+ )
179
+ conn , err := dialer .DialContext (ctx , "tcp" , hostPort )
180
+ if err != nil {
181
+ if err == context .DeadlineExceeded {
182
+ err = xerrors .New ("timed out after 3 seconds" )
183
+ }
184
+ return xerrors .Errorf ("dial tcp://%v: %w" , hostPort , err )
185
+ }
186
+ conn .Close ()
187
+
188
+ return nil
189
+ }
190
+
148
191
func writeSSHKey (ctx context.Context , client * coder.Client , privateKeyPath string ) error {
149
192
key , err := client .SSHKey (ctx )
150
193
if err != nil {
@@ -161,6 +204,10 @@ func makeNewConfigs(userName string, envs []coder.Environment, startToken, start
161
204
162
205
newConfig := fmt .Sprintf ("\n %s\n %s\n \n " , startToken , startMsg )
163
206
for _ , env := range envs {
207
+ if ! env .SSHAvailable {
208
+ continue
209
+ }
210
+
164
211
newConfig += makeSSHConfig (hostname , userName , env .Name , privateKeyFilepath )
165
212
}
166
213
newConfig += fmt .Sprintf ("\n %s\n " , endToken )
@@ -181,20 +228,6 @@ func makeSSHConfig(host, userName, envName, privateKeyFilepath string) string {
181
228
` , envName , host , userName , envName , privateKeyFilepath )
182
229
}
183
230
184
- func isSSHAvailable (ctx context.Context ) bool {
185
- ctx , cancel := context .WithTimeout (ctx , 3 * time .Second )
186
- defer cancel ()
187
-
188
- host , err := configuredHostname ()
189
- if err != nil {
190
- return false
191
- }
192
-
193
- var dialer net.Dialer
194
- _ , err = dialer .DialContext (ctx , "tcp" , net .JoinHostPort (host , "22" ))
195
- return err == nil
196
- }
197
-
198
231
func configuredHostname () (string , error ) {
199
232
u , err := config .URL .Read ()
200
233
if err != nil {
0 commit comments