-
Notifications
You must be signed in to change notification settings - Fork 901
feat: add one shot commands to the coder ssh command #17779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
594e4b5
bed4103
4026c07
55735fc
aaaab01
d4feb6c
19fa5f9
c25d27f
ca640b5
e0a3e7a
bfd941d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,15 +90,27 @@ func (r *RootCmd) ssh() *serpent.Command { | |
wsClient := workspacesdk.New(client) | ||
cmd := &serpent.Command{ | ||
Annotations: workspaceCommand, | ||
Use: "ssh <workspace>", | ||
Short: "Start a shell into a workspace", | ||
Use: "ssh <workspace> [command]", | ||
Short: "Start a shell into a workspace or run a command", | ||
Long: "This command does not have full parity with the standard SSH command. For users who need the full functionality of SSH, create an ssh configuration with `coder config-ssh`.", | ||
Middleware: serpent.Chain( | ||
serpent.RequireNArgs(1), | ||
// Require at least one arg for the workspace name | ||
func(next serpent.HandlerFunc) serpent.HandlerFunc { | ||
return func(i *serpent.Invocation) error { | ||
got := len(i.Args) | ||
if got < 1 { | ||
return xerrors.New("expected the name of a workspace") | ||
} | ||
|
||
return next(i) | ||
} | ||
}, | ||
Comment on lines
+104
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep this here, but we should add a serpent MW for |
||
r.InitClient(client), | ||
initAppearance(client, &appearanceConfig), | ||
), | ||
Handler: func(inv *serpent.Invocation) (retErr error) { | ||
command := strings.Join(inv.Args[1:], " ") | ||
|
||
// Before dialing the SSH server over TCP, capture Interrupt signals | ||
// so that if we are interrupted, we have a chance to tear down the | ||
// TCP session cleanly before exiting. If we don't, then the TCP | ||
|
@@ -548,40 +560,46 @@ func (r *RootCmd) ssh() *serpent.Command { | |
sshSession.Stdout = inv.Stdout | ||
sshSession.Stderr = inv.Stderr | ||
|
||
err = sshSession.Shell() | ||
if err != nil { | ||
return xerrors.Errorf("start shell: %w", err) | ||
} | ||
if command != "" { | ||
err := sshSession.Run(command) | ||
if err != nil { | ||
return xerrors.Errorf("run command: %w", err) | ||
} | ||
} else { | ||
err = sshSession.Shell() | ||
if err != nil { | ||
return xerrors.Errorf("start shell: %w", err) | ||
} | ||
|
||
// Put cancel at the top of the defer stack to initiate | ||
// shutdown of services. | ||
defer cancel() | ||
// Put cancel at the top of the defer stack to initiate | ||
// shutdown of services. | ||
defer cancel() | ||
|
||
if validOut { | ||
// Set initial window size. | ||
width, height, err := term.GetSize(int(stdoutFile.Fd())) | ||
if err == nil { | ||
_ = sshSession.WindowChange(height, width) | ||
if validOut { | ||
// Set initial window size. | ||
width, height, err := term.GetSize(int(stdoutFile.Fd())) | ||
if err == nil { | ||
_ = sshSession.WindowChange(height, width) | ||
} | ||
} | ||
} | ||
|
||
err = sshSession.Wait() | ||
conn.SendDisconnectedTelemetry() | ||
if err != nil { | ||
if exitErr := (&gossh.ExitError{}); errors.As(err, &exitErr) { | ||
// Clear the error since it's not useful beyond | ||
// reporting status. | ||
return ExitError(exitErr.ExitStatus(), nil) | ||
} | ||
// If the connection drops unexpectedly, we get an | ||
// ExitMissingError but no other error details, so try to at | ||
// least give the user a better message | ||
if errors.Is(err, &gossh.ExitMissingError{}) { | ||
return ExitError(255, xerrors.New("SSH connection ended unexpectedly")) | ||
err = sshSession.Wait() | ||
conn.SendDisconnectedTelemetry() | ||
if err != nil { | ||
if exitErr := (&gossh.ExitError{}); errors.As(err, &exitErr) { | ||
// Clear the error since it's not useful beyond | ||
// reporting status. | ||
return ExitError(exitErr.ExitStatus(), nil) | ||
} | ||
// If the connection drops unexpectedly, we get an | ||
// ExitMissingError but no other error details, so try to at | ||
// least give the user a better message | ||
if errors.Is(err, &gossh.ExitMissingError{}) { | ||
return ExitError(255, xerrors.New("SSH connection ended unexpectedly")) | ||
} | ||
return xerrors.Errorf("session ended: %w", err) | ||
} | ||
return xerrors.Errorf("session ended: %w", err) | ||
} | ||
|
||
return nil | ||
}, | ||
} | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ssh <workspace> ls -la
works, butcoder ssh <workspace> ls -la
does not. I don't think we have to fix this, but we should have an example on how to pass flags. It is common unix stuff, but worth throwing in here imo.