@@ -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,36 @@ 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
+ args := []string {"-NoProfile" , "-NonInteractive" }
233
+ _ = caller
234
+ return exec .CommandContext (ctx , "pwsh.exe" , args ... ), nil
235
+ }
236
+
237
+ func (* agent ) collectMetadata (ctx context.Context , md codersdk.WorkspaceAgentMetadataDescription ) * codersdk.WorkspaceAgentMetadataResult {
206
238
var out bytes.Buffer
207
239
result := & codersdk.WorkspaceAgentMetadataResult {
208
240
// CollectedAt is set here for testing purposes and overrode by
@@ -213,18 +245,33 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM
213
245
// if it is certain the clocks are in sync.
214
246
CollectedAt : time .Now (),
215
247
}
216
- cmd , err := a . sshServer . CreateCommand (ctx , md .Script , nil )
248
+ cmd , err := createMetadataCommand (ctx , md .Script )
217
249
if err != nil {
218
- result .Error = err . Error ( )
250
+ result .Error = fmt . Sprintf ( "create cmd: %+v" , err )
219
251
return result
220
252
}
221
253
254
+ // execPath, err := exec.LookPath("cmd.exe")
255
+ // if err != nil {
256
+ // result.Error = fmt.Sprintf("look path: %+v", err)
257
+ // return result
258
+ // }
259
+
260
+ // cmd = exec.CommandContext(ctx, execPath, "/c", "echo hello")
261
+
222
262
cmd .Stdout = & out
223
263
cmd .Stderr = & out
264
+ cmd .Stdin = io .LimitReader (nil , 0 )
224
265
225
- // The error isn't mutually exclusive with useful output.
226
- err = cmd .Run ()
266
+ // We split up Start and Wait so that we can return a more useful error.
267
+ err = cmd .Start ()
268
+ if err != nil {
269
+ result .Error = fmt .Sprintf ("start cmd: %+v" , err )
270
+ return result
271
+ }
227
272
273
+ // This error isn't mutually exclusive with useful output.
274
+ err = cmd .Wait ()
228
275
const bufLimit = 10 << 10
229
276
if out .Len () > bufLimit {
230
277
err = errors .Join (
@@ -234,8 +281,10 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM
234
281
out .Truncate (bufLimit )
235
282
}
236
283
284
+ fmt .Printf ("ran %+v %+q: %v\n " , cmd .Path , cmd .Args , err )
285
+
237
286
if err != nil {
238
- result .Error = err . Error ( )
287
+ result .Error = fmt . Sprintf ( "run cmd: %+v" , err )
239
288
}
240
289
result .Value = out .String ()
241
290
return result
0 commit comments