@@ -3,6 +3,7 @@ package cli
3
3
import (
4
4
"bufio"
5
5
"bytes"
6
+ "context"
6
7
"errors"
7
8
"fmt"
8
9
"io"
@@ -97,6 +98,67 @@ func (o sshCoderConfigOptions) asList() (list []string) {
97
98
return list
98
99
}
99
100
101
+ type sshWorkspaceConfig struct {
102
+ Name string
103
+ Hosts []string
104
+ }
105
+
106
+ func sshPrepareWorkspaceConfigs (ctx context.Context , client * codersdk.Client ) (receive func () ([]sshWorkspaceConfig , error )) {
107
+ wcC := make (chan []sshWorkspaceConfig , 1 )
108
+ errC := make (chan error , 1 )
109
+ go func () {
110
+ wc , err := func () ([]sshWorkspaceConfig , error ) {
111
+ workspaces , err := client .Workspaces (ctx , codersdk.WorkspaceFilter {
112
+ Owner : codersdk .Me ,
113
+ })
114
+ if err != nil {
115
+ return nil , err
116
+ }
117
+
118
+ var errGroup errgroup.Group
119
+ workspaceConfigs := make ([]sshWorkspaceConfig , len (workspaces ))
120
+ for i , workspace := range workspaces {
121
+ i := i
122
+ workspace := workspace
123
+ errGroup .Go (func () error {
124
+ resources , err := client .TemplateVersionResources (ctx , workspace .LatestBuild .TemplateVersionID )
125
+ if err != nil {
126
+ return err
127
+ }
128
+
129
+ wc := sshWorkspaceConfig {Name : workspace .Name }
130
+ for _ , resource := range resources {
131
+ if resource .Transition != codersdk .WorkspaceTransitionStart {
132
+ continue
133
+ }
134
+ for _ , agent := range resource .Agents {
135
+ hostname := workspace .Name
136
+ if len (resource .Agents ) > 1 {
137
+ hostname += "." + agent .Name
138
+ }
139
+ wc .Hosts = append (wc .Hosts , hostname )
140
+ }
141
+ }
142
+ workspaceConfigs [i ] = wc
143
+
144
+ return nil
145
+ })
146
+ }
147
+ err = errGroup .Wait ()
148
+ if err != nil {
149
+ return nil , err
150
+ }
151
+
152
+ return workspaceConfigs , nil
153
+ }()
154
+ wcC <- wc
155
+ errC <- err
156
+ }()
157
+ return func () ([]sshWorkspaceConfig , error ) {
158
+ return <- wcC , <- errC
159
+ }
160
+ }
161
+
100
162
func configSSH () * cobra.Command {
101
163
var (
102
164
coderConfig sshCoderConfigOptions
@@ -132,13 +194,7 @@ func configSSH() *cobra.Command {
132
194
return err
133
195
}
134
196
135
- // Early check for workspaces to ensure API key has not expired.
136
- workspaces , err := client .Workspaces (cmd .Context (), codersdk.WorkspaceFilter {
137
- Owner : codersdk .Me ,
138
- })
139
- if err != nil {
140
- return err
141
- }
197
+ recvWorkspaceConfigs := sshPrepareWorkspaceConfigs (cmd .Context (), client )
142
198
143
199
out := cmd .OutOrStdout ()
144
200
if showDiff {
@@ -172,6 +228,7 @@ func configSSH() *cobra.Command {
172
228
coderConfigExists := true
173
229
coderConfigRaw , err := os .ReadFile (coderConfigFile )
174
230
if err != nil {
231
+ //nolint: revive // Inverting this if statement doesn't improve readability.
175
232
if errors .Is (err , fs .ErrNotExist ) {
176
233
coderConfigExists = false
177
234
} else {
@@ -232,43 +289,6 @@ func configSSH() *cobra.Command {
232
289
}
233
290
234
291
root := createConfig (cmd )
235
- var errGroup errgroup.Group
236
- type workspaceConfig struct {
237
- Name string
238
- Hosts []string
239
- }
240
- workspaceConfigs := make ([]workspaceConfig , len (workspaces ))
241
- for i , workspace := range workspaces {
242
- i := i
243
- workspace := workspace
244
- errGroup .Go (func () error {
245
- resources , err := client .TemplateVersionResources (cmd .Context (), workspace .LatestBuild .TemplateVersionID )
246
- if err != nil {
247
- return err
248
- }
249
-
250
- wc := workspaceConfig {Name : workspace .Name }
251
- for _ , resource := range resources {
252
- if resource .Transition != codersdk .WorkspaceTransitionStart {
253
- continue
254
- }
255
- for _ , agent := range resource .Agents {
256
- hostname := workspace .Name
257
- if len (resource .Agents ) > 1 {
258
- hostname += "." + agent .Name
259
- }
260
- wc .Hosts = append (wc .Hosts , hostname )
261
- }
262
- }
263
- workspaceConfigs [i ] = wc
264
-
265
- return nil
266
- })
267
- }
268
- err = errGroup .Wait ()
269
- if err != nil {
270
- return err
271
- }
272
292
273
293
buf := & bytes.Buffer {}
274
294
@@ -279,8 +299,12 @@ func configSSH() *cobra.Command {
279
299
return xerrors .Errorf ("write coder config header failed: %w" , err )
280
300
}
281
301
302
+ workspaceConfigs , err := recvWorkspaceConfigs ()
303
+ if err != nil {
304
+ return xerrors .Errorf ("fetch workspace configs failed: %w" , err )
305
+ }
282
306
// Ensure stable sorting of output.
283
- slices .SortFunc (workspaceConfigs , func (a , b workspaceConfig ) bool {
307
+ slices .SortFunc (workspaceConfigs , func (a , b sshWorkspaceConfig ) bool {
284
308
return a .Name < b .Name
285
309
})
286
310
for _ , wc := range workspaceConfigs {
@@ -377,9 +401,9 @@ func configSSH() *cobra.Command {
377
401
}
378
402
}
379
403
380
- if len (workspaces ) > 0 {
404
+ if len (workspaceConfigs ) > 0 {
381
405
_ , _ = fmt .Fprintln (out , "You should now be able to ssh into your workspace." )
382
- _ , _ = fmt .Fprintf (out , "For example, try running:\n \n \t $ ssh coder.%s\n \n " , workspaces [0 ].Name )
406
+ _ , _ = fmt .Fprintf (out , "For example, try running:\n \n \t $ ssh coder.%s\n \n " , workspaceConfigs [0 ].Name )
383
407
} else {
384
408
_ , _ = fmt .Fprint (out , "You don't have any workspaces yet, try creating one with:\n \n \t $ coder create <workspace>\n \n " )
385
409
}
0 commit comments