Skip to content

Commit dfaf836

Browse files
committed
Merge branch 'main' into dean/hang-detector
2 parents a38e949 + 30a635a commit dfaf836

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1172
-200
lines changed

.github/workflows/nightly-gauntlet.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ on:
66
# Every day at midnight
77
- cron: "0 0 * * *"
88
workflow_dispatch:
9-
push:
10-
branch:
11-
- nightly-gauntlet
129
jobs:
1310
go-race:
1411
# While GitHub's toaster runners are likelier to flake, we want consistency

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,5 @@ site/stats/
5858
# Loadtesting
5959
./scaletest/terraform/.terraform
6060
./scaletest/terraform/.terraform.lock.hcl
61-
terraform.tfstate.*
62-
**/*.tfvars
61+
scaletest/terraform/secrets.tfvars
62+
.terraform.tfstate.*

.prettierignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ site/stats/
6161
# Loadtesting
6262
./scaletest/terraform/.terraform
6363
./scaletest/terraform/.terraform.lock.hcl
64-
terraform.tfstate.*
65-
**/*.tfvars
64+
scaletest/terraform/secrets.tfvars
65+
.terraform.tfstate.*
6666
# .prettierignore.include:
6767
# Helm templates contain variables that are invalid YAML and can't be formatted
6868
# by Prettier.

cli/cliui/agent.go

Lines changed: 5 additions & 5 deletions
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

Lines changed: 4 additions & 4 deletions
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/configssh.go

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ const (
4545
// sshConfigOptions represents options that can be stored and read
4646
// from the coder config in ~/.ssh/coder.
4747
type sshConfigOptions struct {
48-
sshOptions []string
48+
waitEnum string
49+
userHostPrefix string
50+
sshOptions []string
4951
}
5052

5153
// addOptions expects options in the form of "option=value" or "option value".
@@ -100,10 +102,19 @@ func (o sshConfigOptions) equal(other sshConfigOptions) bool {
100102
sort.Strings(opt1)
101103
opt2 := slices.Clone(other.sshOptions)
102104
sort.Strings(opt2)
103-
return slices.Equal(opt1, opt2)
105+
if !slices.Equal(opt1, opt2) {
106+
return false
107+
}
108+
return o.waitEnum == other.waitEnum && o.userHostPrefix == other.userHostPrefix
104109
}
105110

106111
func (o sshConfigOptions) asList() (list []string) {
112+
if o.waitEnum != "auto" {
113+
list = append(list, fmt.Sprintf("wait: %s", o.waitEnum))
114+
}
115+
if o.userHostPrefix != "" {
116+
list = append(list, fmt.Sprintf("ssh-host-prefix: %s", o.userHostPrefix))
117+
}
107118
for _, opt := range o.sshOptions {
108119
list = append(list, fmt.Sprintf("ssh-option: %s", opt))
109120
}
@@ -178,14 +189,14 @@ func sshPrepareWorkspaceConfigs(ctx context.Context, client *codersdk.Client) (r
178189
}
179190
}
180191

192+
//nolint:gocyclo
181193
func (r *RootCmd) configSSH() *clibase.Cmd {
182194
var (
183195
sshConfigFile string
184196
sshConfigOpts sshConfigOptions
185197
usePreviousOpts bool
186198
dryRun bool
187199
skipProxyCommand bool
188-
userHostPrefix string
189200
)
190201
client := new(codersdk.Client)
191202
cmd := &clibase.Cmd{
@@ -207,6 +218,12 @@ func (r *RootCmd) configSSH() *clibase.Cmd {
207218
r.InitClient(client),
208219
),
209220
Handler: func(inv *clibase.Invocation) error {
221+
if sshConfigOpts.waitEnum != "auto" && skipProxyCommand {
222+
// The wait option is applied to the ProxyCommand. If the user
223+
// specifies skip-proxy-command, then wait cannot be applied.
224+
return xerrors.Errorf("cannot specify both --skip-proxy-command and --wait")
225+
}
226+
210227
recvWorkspaceConfigs := sshPrepareWorkspaceConfigs(inv.Context(), client)
211228

212229
out := inv.Stdout
@@ -295,7 +312,7 @@ func (r *RootCmd) configSSH() *clibase.Cmd {
295312
// Selecting "no" will use the last config.
296313
sshConfigOpts = *lastConfig
297314
} else {
298-
changes = append(changes, "Use new SSH options")
315+
changes = append(changes, "Use new options")
299316
}
300317
// Only print when prompts are shown.
301318
if yes, _ := inv.ParsedFlags().GetBool("yes"); !yes {
@@ -336,9 +353,9 @@ func (r *RootCmd) configSSH() *clibase.Cmd {
336353
coderdConfig.HostnamePrefix = "coder."
337354
}
338355

339-
if userHostPrefix != "" {
356+
if sshConfigOpts.userHostPrefix != "" {
340357
// Override with user flag.
341-
coderdConfig.HostnamePrefix = userHostPrefix
358+
coderdConfig.HostnamePrefix = sshConfigOpts.userHostPrefix
342359
}
343360

344361
// Ensure stable sorting of output.
@@ -363,13 +380,20 @@ func (r *RootCmd) configSSH() *clibase.Cmd {
363380
}
364381

365382
if !skipProxyCommand {
383+
flags := ""
384+
if sshConfigOpts.waitEnum != "auto" {
385+
flags += " --wait=" + sshConfigOpts.waitEnum
386+
}
366387
defaultOptions = append(defaultOptions, fmt.Sprintf(
367-
"ProxyCommand %s --global-config %s ssh --stdio %s",
368-
escapedCoderBinary, escapedGlobalConfig, workspaceHostname,
388+
"ProxyCommand %s --global-config %s ssh --stdio%s %s",
389+
escapedCoderBinary, escapedGlobalConfig, flags, workspaceHostname,
369390
))
370391
}
371392

372-
var configOptions sshConfigOptions
393+
// Create a copy of the options so we can modify them.
394+
configOptions := sshConfigOpts
395+
configOptions.sshOptions = nil
396+
373397
// Add standard options.
374398
err := configOptions.addOptions(defaultOptions...)
375399
if err != nil {
@@ -505,9 +529,16 @@ func (r *RootCmd) configSSH() *clibase.Cmd {
505529
},
506530
{
507531
Flag: "ssh-host-prefix",
508-
Env: "",
532+
Env: "CODER_CONFIGSSH_SSH_HOST_PREFIX",
509533
Description: "Override the default host prefix.",
510-
Value: clibase.StringOf(&userHostPrefix),
534+
Value: clibase.StringOf(&sshConfigOpts.userHostPrefix),
535+
},
536+
{
537+
Flag: "wait",
538+
Env: "CODER_CONFIGSSH_WAIT", // Not to be mixed with CODER_SSH_WAIT.
539+
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.",
540+
Default: "auto",
541+
Value: clibase.EnumOf(&sshConfigOpts.waitEnum, "yes", "no", "auto"),
511542
},
512543
cliui.SkipPromptOption(),
513544
}
@@ -524,12 +555,22 @@ func sshConfigWriteSectionHeader(w io.Writer, addNewline bool, o sshConfigOption
524555
_, _ = fmt.Fprint(w, nl+sshStartToken+"\n")
525556
_, _ = fmt.Fprint(w, sshConfigSectionHeader)
526557
_, _ = fmt.Fprint(w, sshConfigDocsHeader)
527-
if len(o.sshOptions) > 0 {
558+
559+
var ow strings.Builder
560+
if o.waitEnum != "auto" {
561+
_, _ = fmt.Fprintf(&ow, "# :%s=%s\n", "wait", o.waitEnum)
562+
}
563+
if o.userHostPrefix != "" {
564+
_, _ = fmt.Fprintf(&ow, "# :%s=%s\n", "ssh-host-prefix", o.userHostPrefix)
565+
}
566+
for _, opt := range o.sshOptions {
567+
_, _ = fmt.Fprintf(&ow, "# :%s=%s\n", "ssh-option", opt)
568+
}
569+
if ow.Len() > 0 {
528570
_, _ = fmt.Fprint(w, sshConfigOptionsHeader)
529-
for _, opt := range o.sshOptions {
530-
_, _ = fmt.Fprintf(w, "# :%s=%s\n", "ssh-option", opt)
531-
}
571+
_, _ = fmt.Fprint(w, ow.String())
532572
}
573+
533574
_, _ = fmt.Fprint(w, "#\n")
534575
}
535576

@@ -538,13 +579,20 @@ func sshConfigWriteSectionEnd(w io.Writer) {
538579
}
539580

540581
func sshConfigParseLastOptions(r io.Reader) (o sshConfigOptions) {
582+
// Default values.
583+
o.waitEnum = "auto"
584+
541585
s := bufio.NewScanner(r)
542586
for s.Scan() {
543587
line := s.Text()
544588
if strings.HasPrefix(line, "# :") {
545589
line = strings.TrimPrefix(line, "# :")
546590
parts := strings.SplitN(line, "=", 2)
547591
switch parts[0] {
592+
case "wait":
593+
o.waitEnum = parts[1]
594+
case "ssh-host-prefix":
595+
o.userHostPrefix = parts[1]
548596
case "ssh-option":
549597
o.sshOptions = append(o.sshOptions, parts[1])
550598
default:

cli/configssh_test.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,12 +481,32 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
481481
},
482482
args: []string{"--yes"},
483483
},
484+
{
485+
name: "Serialize supported flags",
486+
wantConfig: wantConfig{
487+
ssh: strings.Join([]string{
488+
headerStart,
489+
"# Last config-ssh options:",
490+
"# :wait=yes",
491+
"# :ssh-host-prefix=coder-test.",
492+
"#",
493+
headerEnd,
494+
"",
495+
}, "\n"),
496+
},
497+
args: []string{
498+
"--yes",
499+
"--wait=yes",
500+
"--ssh-host-prefix", "coder-test.",
501+
},
502+
},
484503
{
485504
name: "Do not prompt for new options when prev opts flag is set",
486505
writeConfig: writeConfig{
487506
ssh: strings.Join([]string{
488507
headerStart,
489508
"# Last config-ssh options:",
509+
"# :wait=no",
490510
"# :ssh-option=ForwardAgent=yes",
491511
"#",
492512
headerEnd,
@@ -497,6 +517,7 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
497517
ssh: strings.Join([]string{
498518
headerStart,
499519
"# Last config-ssh options:",
520+
"# :wait=no",
500521
"# :ssh-option=ForwardAgent=yes",
501522
"#",
502523
headerEnd,
@@ -589,8 +610,7 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
589610
clitest.SetupConfig(t, client, root)
590611

591612
pty := ptytest.New(t)
592-
inv.Stdin = pty.Input()
593-
inv.Stdout = pty.Output()
613+
pty.Attach(inv)
594614
done := tGo(t, func() {
595615
err := inv.Run()
596616
if !tt.wantErr {

cli/help.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,31 @@ var usageTemplate = template.Must(
135135
"isDeprecated": func(opt clibase.Option) bool {
136136
return len(opt.UseInstead) > 0
137137
},
138+
"useInstead": func(opt clibase.Option) string {
139+
var sb strings.Builder
140+
for i, s := range opt.UseInstead {
141+
if i > 0 {
142+
if i == len(opt.UseInstead)-1 {
143+
_, _ = sb.WriteString(" and ")
144+
} else {
145+
_, _ = sb.WriteString(", ")
146+
}
147+
}
148+
if s.Flag != "" {
149+
_, _ = sb.WriteString("--")
150+
_, _ = sb.WriteString(s.Flag)
151+
} else if s.FlagShorthand != "" {
152+
_, _ = sb.WriteString("-")
153+
_, _ = sb.WriteString(s.FlagShorthand)
154+
} else if s.Env != "" {
155+
_, _ = sb.WriteString("$")
156+
_, _ = sb.WriteString(s.Env)
157+
} else {
158+
_, _ = sb.WriteString(s.Name)
159+
}
160+
}
161+
return sb.String()
162+
},
138163
"formatLong": func(long string) string {
139164
// We intentionally don't wrap here because it would misformat
140165
// examples, where the new line would start without the prior

cli/help.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Usage: {{.FullUsage}}
4343
{{- with $option.Description }}
4444
{{- $desc := $option.Description }}
4545
{{ indent $desc 10 }}
46-
{{- if isDeprecated $option }} DEPRECATED {{ end }}
46+
{{- if isDeprecated $option }}{{ indent (printf "DEPRECATED: Use %s instead." (useInstead $option)) 10 }}{{ end }}
4747
{{- end -}}
4848
{{- end }}
4949
{{- end }}

cli/portforward.go

Lines changed: 1 addition & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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)

0 commit comments

Comments
 (0)