@@ -43,6 +43,11 @@ const (
43
43
ProtocolReconnectingPTY = "reconnecting-pty"
44
44
ProtocolSSH = "ssh"
45
45
ProtocolDial = "dial"
46
+
47
+ // MagicSessionErrorCode indicates that something went wrong with the session, rather than the
48
+ // command just returning a nonzero exit code, and is chosen as an arbitrary, high number
49
+ // unlikely to shadow other exit codes, which are typically 1, 2, 3, etc.
50
+ MagicSessionErrorCode = 229
46
51
)
47
52
48
53
type Options struct {
@@ -273,9 +278,17 @@ func (a *agent) init(ctx context.Context) {
273
278
},
274
279
Handler : func (session ssh.Session ) {
275
280
err := a .handleSSHSession (session )
281
+ var exitError * exec.ExitError
282
+ if xerrors .As (err , & exitError ) {
283
+ a .logger .Debug (ctx , "ssh session returned" , slog .Error (exitError ))
284
+ _ = session .Exit (exitError .ExitCode ())
285
+ return
286
+ }
276
287
if err != nil {
277
288
a .logger .Warn (ctx , "ssh session failed" , slog .Error (err ))
278
- _ = session .Exit (1 )
289
+ // This exit code is designed to be unlikely to be confused for a legit exit code
290
+ // from the process.
291
+ _ = session .Exit (MagicSessionErrorCode )
279
292
return
280
293
}
281
294
},
@@ -403,7 +416,7 @@ func (a *agent) createCommand(ctx context.Context, rawCommand string, env []stri
403
416
return cmd , nil
404
417
}
405
418
406
- func (a * agent ) handleSSHSession (session ssh.Session ) error {
419
+ func (a * agent ) handleSSHSession (session ssh.Session ) ( retErr error ) {
407
420
cmd , err := a .createCommand (session .Context (), session .RawCommand (), session .Environ ())
408
421
if err != nil {
409
422
return err
@@ -426,14 +439,24 @@ func (a *agent) handleSSHSession(session ssh.Session) error {
426
439
if err != nil {
427
440
return xerrors .Errorf ("start command: %w" , err )
428
441
}
442
+ defer func () {
443
+ closeErr := ptty .Close ()
444
+ if closeErr != nil {
445
+ a .logger .Warn (context .Background (), "failed to close tty" ,
446
+ slog .Error (closeErr ))
447
+ if retErr == nil {
448
+ retErr = closeErr
449
+ }
450
+ }
451
+ }()
429
452
err = ptty .Resize (uint16 (sshPty .Window .Height ), uint16 (sshPty .Window .Width ))
430
453
if err != nil {
431
454
return xerrors .Errorf ("resize ptty: %w" , err )
432
455
}
433
456
go func () {
434
457
for win := range windowSize {
435
- err = ptty .Resize (uint16 (win .Height ), uint16 (win .Width ))
436
- if err != nil {
458
+ resizeErr : = ptty .Resize (uint16 (win .Height ), uint16 (win .Width ))
459
+ if resizeErr != nil {
437
460
a .logger .Warn (context .Background (), "failed to resize tty" , slog .Error (err ))
438
461
}
439
462
}
@@ -444,9 +467,15 @@ func (a *agent) handleSSHSession(session ssh.Session) error {
444
467
go func () {
445
468
_ , _ = io .Copy (session , ptty .Output ())
446
469
}()
447
- _ , _ = process .Wait ()
448
- _ = ptty .Close ()
449
- return nil
470
+ err = process .Wait ()
471
+ var exitErr * exec.ExitError
472
+ // ExitErrors just mean the command we run returned a non-zero exit code, which is normal
473
+ // and not something to be concerned about. But, if it's something else, we should log it.
474
+ if err != nil && ! xerrors .As (err , & exitErr ) {
475
+ a .logger .Warn (context .Background (), "wait error" ,
476
+ slog .Error (err ))
477
+ }
478
+ return err
450
479
}
451
480
452
481
cmd .Stdout = session
@@ -549,7 +578,7 @@ func (a *agent) handleReconnectingPTY(ctx context.Context, rawID string, conn ne
549
578
go func () {
550
579
// If the process dies randomly, we should
551
580
// close the pty.
552
- _ , _ = process .Wait ()
581
+ _ = process .Wait ()
553
582
rpty .Close ()
554
583
}()
555
584
go func () {
0 commit comments