Skip to content

Commit 94aa9be

Browse files
authored
feat(cli/ssh): implement wait options and deprecate no-wait (#7894)
Fixes #7768 Refs #7893
1 parent b232432 commit 94aa9be

File tree

8 files changed

+69
-18
lines changed

8 files changed

+69
-18
lines changed

cli/cliui/agent.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type AgentOptions struct {
2727
Fetch func(context.Context) (codersdk.WorkspaceAgent, error)
2828
FetchInterval time.Duration
2929
WarnInterval time.Duration
30-
NoWait bool // If true, don't wait for the agent to be ready.
30+
Wait bool // If true, wait for the agent to be ready (startup script).
3131
}
3232

3333
// Agent displays a spinning indicator that waits for a workspace agent to connect.
@@ -96,7 +96,7 @@ func Agent(ctx context.Context, writer io.Writer, opts AgentOptions) error {
9696
// we do this just before starting the spinner to avoid needless
9797
// spinning.
9898
if agent.Status == codersdk.WorkspaceAgentConnected &&
99-
agent.StartupScriptBehavior == codersdk.WorkspaceAgentStartupScriptBehaviorBlocking && opts.NoWait {
99+
agent.StartupScriptBehavior == codersdk.WorkspaceAgentStartupScriptBehaviorBlocking && !opts.Wait {
100100
showMessage()
101101
return nil
102102
}
@@ -140,7 +140,7 @@ func Agent(ctx context.Context, writer io.Writer, opts AgentOptions) error {
140140
// NOTE(mafredri): Once we have access to the workspace agent's
141141
// startup script logs, we can show them here.
142142
// https://github.com/coder/coder/issues/2957
143-
if agent.StartupScriptBehavior == codersdk.WorkspaceAgentStartupScriptBehaviorBlocking && !opts.NoWait {
143+
if agent.StartupScriptBehavior == codersdk.WorkspaceAgentStartupScriptBehaviorBlocking && opts.Wait {
144144
switch agent.LifecycleState {
145145
case codersdk.WorkspaceAgentLifecycleReady:
146146
return nil
@@ -183,7 +183,7 @@ func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *messag
183183
Prompt: "Don't panic, your workspace is booting up!",
184184
}
185185
defer func() {
186-
if agent.Status == codersdk.WorkspaceAgentConnected && opts.NoWait {
186+
if agent.Status == codersdk.WorkspaceAgentConnected && !opts.Wait {
187187
m.Spin = ""
188188
}
189189
if m.Spin != "" {
@@ -225,7 +225,7 @@ func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *messag
225225
case codersdk.WorkspaceAgentConnected:
226226
m.Spin = fmt.Sprintf("Waiting for %s to become ready...", DefaultStyles.Field.Render(agent.Name))
227227
m.Prompt = "Don't panic, your workspace agent has connected and the workspace is getting ready!"
228-
if opts.NoWait {
228+
if !opts.Wait {
229229
m.Prompt = "Your workspace is still getting ready, it may be in an incomplete state."
230230
}
231231

cli/cliui/agent_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func TestAgent_StartupTimeout(t *testing.T) {
140140
},
141141
FetchInterval: time.Millisecond,
142142
WarnInterval: time.Millisecond,
143-
NoWait: false,
143+
Wait: true,
144144
})
145145
return err
146146
},
@@ -199,7 +199,7 @@ func TestAgent_StartErrorExit(t *testing.T) {
199199
},
200200
FetchInterval: time.Millisecond,
201201
WarnInterval: 60 * time.Second,
202-
NoWait: false,
202+
Wait: true,
203203
})
204204
return err
205205
},
@@ -255,7 +255,7 @@ func TestAgent_NoWait(t *testing.T) {
255255
},
256256
FetchInterval: time.Millisecond,
257257
WarnInterval: time.Second,
258-
NoWait: true,
258+
Wait: false,
259259
})
260260
return err
261261
},
@@ -325,7 +325,7 @@ func TestAgent_StartupScriptBehaviorNonBlocking(t *testing.T) {
325325
},
326326
FetchInterval: time.Millisecond,
327327
WarnInterval: time.Second,
328-
NoWait: false,
328+
Wait: true,
329329
})
330330
return err
331331
},

cli/portforward.go

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ func (r *RootCmd) portForward() *clibase.Cmd {
9292
Fetch: func(ctx context.Context) (codersdk.WorkspaceAgent, error) {
9393
return client.WorkspaceAgent(ctx, workspaceAgent.ID)
9494
},
95+
Wait: false,
9596
})
9697
if err != nil {
9798
return xerrors.Errorf("await agent: %w", err)

cli/speedtest.go

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func (r *RootCmd) speedtest() *clibase.Cmd {
4545
Fetch: func(ctx context.Context) (codersdk.WorkspaceAgent, error) {
4646
return client.WorkspaceAgent(ctx, workspaceAgent.ID)
4747
},
48+
Wait: false,
4849
})
4950
if err != nil && !xerrors.Is(err, cliui.AgentStartError) {
5051
return xerrors.Errorf("await agent: %w", err)

cli/ssh.go

+37-2
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ var (
4242
autostopNotifyCountdown = []time.Duration{30 * time.Minute}
4343
)
4444

45+
//nolint:gocyclo
4546
func (r *RootCmd) ssh() *clibase.Cmd {
4647
var (
4748
stdio bool
4849
forwardAgent bool
4950
forwardGPG bool
5051
identityAgent string
5152
wsPollInterval time.Duration
53+
waitEnum string
5254
noWait bool
5355
logDir string
5456
logToFile bool
@@ -105,6 +107,30 @@ func (r *RootCmd) ssh() *clibase.Cmd {
105107
return err
106108
}
107109

110+
// Select the startup script behavior based on template configuration or flags.
111+
var wait bool
112+
switch waitEnum {
113+
case "yes":
114+
wait = true
115+
case "no":
116+
wait = false
117+
case "auto":
118+
switch workspaceAgent.StartupScriptBehavior {
119+
case codersdk.WorkspaceAgentStartupScriptBehaviorBlocking:
120+
wait = true
121+
case codersdk.WorkspaceAgentStartupScriptBehaviorNonBlocking:
122+
wait = false
123+
default:
124+
return xerrors.Errorf("unknown startup script behavior %q", workspaceAgent.StartupScriptBehavior)
125+
}
126+
default:
127+
return xerrors.Errorf("unknown wait value %q", waitEnum)
128+
}
129+
// The `--no-wait` flag is deprecated, but for now, check it.
130+
if noWait {
131+
wait = false
132+
}
133+
108134
templateVersion, err := client.TemplateVersion(ctx, workspace.LatestBuild.TemplateVersionID)
109135
if err != nil {
110136
return err
@@ -134,7 +160,7 @@ func (r *RootCmd) ssh() *clibase.Cmd {
134160
Fetch: func(ctx context.Context) (codersdk.WorkspaceAgent, error) {
135161
return client.WorkspaceAgent(ctx, workspaceAgent.ID)
136162
},
137-
NoWait: noWait,
163+
Wait: wait,
138164
})
139165
if err != nil {
140166
if xerrors.Is(err, context.Canceled) {
@@ -313,6 +339,13 @@ func (r *RootCmd) ssh() *clibase.Cmd {
313339
return nil
314340
},
315341
}
342+
waitOption := clibase.Option{
343+
Flag: "wait",
344+
Env: "CODER_SSH_WAIT",
345+
Description: "Specifies whether or not to wait for the startup script to finish executing. Auto means that the agent startup script behavior configured in the workspace template is used.",
346+
Default: "auto",
347+
Value: clibase.EnumOf(&waitEnum, "yes", "no", "auto"),
348+
}
316349
cmd.Options = clibase.OptionSet{
317350
{
318351
Flag: "stdio",
@@ -347,11 +380,13 @@ func (r *RootCmd) ssh() *clibase.Cmd {
347380
Default: "1m",
348381
Value: clibase.DurationOf(&wsPollInterval),
349382
},
383+
waitOption,
350384
{
351385
Flag: "no-wait",
352386
Env: "CODER_SSH_NO_WAIT",
353-
Description: "Specifies whether to wait for a workspace to become ready before logging in (only applicable when the startup script behavior is blocking). Note that the workspace agent may still be in the process of executing the startup script and the workspace may be in an incomplete state.",
387+
Description: "Enter workspace immediately after the agent has connected. This is the default if the template has configured the agent startup script behavior as non-blocking.",
354388
Value: clibase.BoolOf(&noWait),
389+
UseInstead: []clibase.Option{waitOption},
355390
},
356391
{
357392
Flag: "log-dir",

cli/testdata/coder_ssh_--help.golden

+9-6
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,18 @@ Start a shell into a workspace
2525
Enable diagnostic logging to file.
2626

2727
--no-wait bool, $CODER_SSH_NO_WAIT
28-
Specifies whether to wait for a workspace to become ready before
29-
logging in (only applicable when the startup script behavior is
30-
blocking). Note that the workspace agent may still be in the process
31-
of executing the startup script and the workspace may be in an
32-
incomplete state.
33-
28+
Enter workspace immediately after the agent has connected. This is the
29+
default if the template has configured the agent startup script
30+
behavior as non-blocking.
31+
DEPRECATED
3432
--stdio bool, $CODER_SSH_STDIO
3533
Specifies whether to emit SSH output over stdin/stdout.
3634

35+
--wait yes|no|auto, $CODER_SSH_WAIT (default: auto)
36+
Specifies whether or not to wait for the startup script to finish
37+
executing. Auto means that the agent startup script behavior
38+
configured in the workspace template is used.
39+
3740
--workspace-poll-interval duration, $CODER_WORKSPACE_POLL_INTERVAL (default: 1m)
3841
Specifies how often to poll for workspace automated shutdown.
3942

coderd/database/dbfake/databasefake.go

+1
Original file line numberDiff line numberDiff line change
@@ -3060,6 +3060,7 @@ func (q *fakeQuerier) InsertWorkspaceAgent(_ context.Context, arg database.Inser
30603060
Architecture: arg.Architecture,
30613061
OperatingSystem: arg.OperatingSystem,
30623062
Directory: arg.Directory,
3063+
StartupScriptBehavior: arg.StartupScriptBehavior,
30633064
StartupScript: arg.StartupScript,
30643065
InstanceMetadata: arg.InstanceMetadata,
30653066
ResourceMetadata: arg.ResourceMetadata,

docs/cli/ssh.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Enable diagnostic logging to file.
6565
| Type | <code>bool</code> |
6666
| Environment | <code>$CODER_SSH_NO_WAIT</code> |
6767

68-
Specifies whether to wait for a workspace to become ready before logging in (only applicable when the startup script behavior is blocking). Note that the workspace agent may still be in the process of executing the startup script and the workspace may be in an incomplete state.
68+
Enter workspace immediately after the agent has connected. This is the default if the template has configured the agent startup script behavior as non-blocking.
6969

7070
### --stdio
7171

@@ -76,6 +76,16 @@ Specifies whether to wait for a workspace to become ready before logging in (onl
7676

7777
Specifies whether to emit SSH output over stdin/stdout.
7878

79+
### --wait
80+
81+
| | |
82+
| ----------- | ---------------------------- | --- | ------------ |
83+
| Type | <code>enum[yes | no | auto]</code> |
84+
| Environment | <code>$CODER_SSH_WAIT</code> |
85+
| Default | <code>auto</code> |
86+
87+
Specifies whether or not to wait for the startup script to finish executing. Auto means that the agent startup script behavior configured in the workspace template is used.
88+
7989
### --workspace-poll-interval
8090

8191
| | |

0 commit comments

Comments
 (0)