@@ -14,9 +14,11 @@ import (
14
14
"net/http"
15
15
"net/netip"
16
16
"os"
17
+ "os/exec"
17
18
"os/user"
18
19
"path/filepath"
19
20
"reflect"
21
+ "runtime"
20
22
"sort"
21
23
"strconv"
22
24
"strings"
@@ -35,6 +37,7 @@ import (
35
37
36
38
"cdr.dev/slog"
37
39
"github.com/coder/coder/agent/agentssh"
40
+ "github.com/coder/coder/agent/usershell"
38
41
"github.com/coder/coder/buildinfo"
39
42
"github.com/coder/coder/coderd/database"
40
43
"github.com/coder/coder/coderd/gitauth"
@@ -202,7 +205,34 @@ func (a *agent) runLoop(ctx context.Context) {
202
205
}
203
206
}
204
207
205
- func (a * agent ) collectMetadata (ctx context.Context , md codersdk.WorkspaceAgentMetadataDescription ) * codersdk.WorkspaceAgentMetadataResult {
208
+ func createMetadataCommand (ctx context.Context , script string ) (* exec.Cmd , error ) {
209
+ // This is largely copied from agentssh, but for some reason the command
210
+ // generated there always returns exit status 1 in Windows.
211
+ currentUser , err := user .Current ()
212
+ if err != nil {
213
+ return nil , xerrors .Errorf ("get current user: %w" , err )
214
+ }
215
+ username := currentUser .Username
216
+
217
+ shell , err := usershell .Get (username )
218
+ if err != nil {
219
+ return nil , xerrors .Errorf ("get user shell: %w" , err )
220
+ }
221
+
222
+ var caller string
223
+ switch {
224
+ case filepath .Base (shell ) == "pwsh.exe" :
225
+ caller = "-Command"
226
+ case runtime .GOOS == "windows" :
227
+ caller = "/c"
228
+ default :
229
+ caller = "-c"
230
+ }
231
+ args := []string {caller , "Get-Process" }
232
+ return exec .CommandContext (ctx , shell , args ... ), nil
233
+ }
234
+
235
+ func (* agent ) collectMetadata (ctx context.Context , md codersdk.WorkspaceAgentMetadataDescription ) * codersdk.WorkspaceAgentMetadataResult {
206
236
var out bytes.Buffer
207
237
result := & codersdk.WorkspaceAgentMetadataResult {
208
238
// CollectedAt is set here for testing purposes and overrode by
@@ -213,18 +243,32 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM
213
243
// if it is certain the clocks are in sync.
214
244
CollectedAt : time .Now (),
215
245
}
216
- cmd , err := a . sshServer . CreateCommand (ctx , md .Script , nil )
246
+ cmd , err := createMetadataCommand (ctx , md .Script )
217
247
if err != nil {
218
- result .Error = err . Error ( )
248
+ result .Error = fmt . Sprintf ( "create cmd: %+v" , err )
219
249
return result
220
250
}
221
251
252
+ // execPath, err := exec.LookPath("cmd.exe")
253
+ // if err != nil {
254
+ // result.Error = fmt.Sprintf("look path: %+v", err)
255
+ // return result
256
+ // }
257
+
258
+ // cmd = exec.CommandContext(ctx, execPath, "/c", "echo hello")
259
+
222
260
cmd .Stdout = & out
223
261
cmd .Stderr = & out
224
262
225
- // The error isn't mutually exclusive with useful output.
226
- err = cmd .Run ()
263
+ // We split up Start and Wait so that we can return a more useful error.
264
+ err = cmd .Start ()
265
+ if err != nil {
266
+ result .Error = fmt .Sprintf ("start cmd: %+v" , err )
267
+ return result
268
+ }
227
269
270
+ // This error isn't mutually exclusive with useful output.
271
+ err = cmd .Wait ()
228
272
const bufLimit = 10 << 10
229
273
if out .Len () > bufLimit {
230
274
err = errors .Join (
@@ -234,8 +278,10 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM
234
278
out .Truncate (bufLimit )
235
279
}
236
280
281
+ fmt .Printf ("ran %+v %+q: %v\n " , cmd .Path , cmd .Args , err )
282
+
237
283
if err != nil {
238
- result .Error = err . Error ( )
284
+ result .Error = fmt . Sprintf ( "run cmd: %+v" , err )
239
285
}
240
286
result .Value = out .String ()
241
287
return result
0 commit comments