Skip to content

Commit 1d4d4d7

Browse files
committed
Merge branch 'main' into mes/workspace-clone-feat
2 parents 0947031 + 3200b85 commit 1d4d4d7

File tree

135 files changed

+6308
-1461
lines changed

Some content is hidden

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

135 files changed

+6308
-1461
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ jobs:
136136
137137
# Check for any typos
138138
- name: Check for typos
139-
uses: crate-ci/typos@v1.16.19
139+
uses: crate-ci/typos@v1.16.21
140140
with:
141141
config: .github/workflows/typos.toml
142142

.github/workflows/security.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ jobs:
122122
image_name: ${{ steps.build.outputs.image }}
123123

124124
- name: Run Trivy vulnerability scanner
125-
uses: aquasecurity/trivy-action@fbd16365eb88e12433951383f5e99bd901fc618f
125+
uses: aquasecurity/trivy-action@b77b85c0254bba6789e787844f0585cde1e56320
126126
with:
127127
image-ref: ${{ steps.build.outputs.image }}
128128
format: sarif

.github/workflows/stale.yaml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,15 @@ jobs:
5252
with:
5353
token: ${{ github.token }}
5454
repository: ${{ github.repository }}
55-
retain_days: 1
56-
keep_minimum_runs: 1
55+
retain_days: 30
56+
keep_minimum_runs: 30
5757
delete_workflow_pattern: pr-cleanup.yaml
5858

5959
- name: Delete PR Deploy workflow skipped runs
6060
uses: Mattraks/delete-workflow-runs@v2
6161
with:
6262
token: ${{ github.token }}
6363
repository: ${{ github.repository }}
64-
retain_days: 0
65-
keep_minimum_runs: 0
66-
delete_run_by_conclusion_pattern: skipped
64+
retain_days: 30
65+
keep_minimum_runs: 30
6766
delete_workflow_pattern: pr-deploy.yaml

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"codersdk",
2121
"cronstrue",
2222
"databasefake",
23-
"dbfake",
23+
"dbmem",
2424
"dbgen",
2525
"dbtype",
2626
"DERP",

Makefile

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,13 +448,15 @@ lint/helm:
448448
DB_GEN_FILES := \
449449
coderd/database/querier.go \
450450
coderd/database/unique_constraint.go \
451-
coderd/database/dbfake/dbfake.go \
451+
coderd/database/dbmem/dbmem.go \
452452
coderd/database/dbmetrics/dbmetrics.go \
453453
coderd/database/dbauthz/dbauthz.go \
454454
coderd/database/dbmock/dbmock.go
455455

456456
# all gen targets should be added here and to gen/mark-fresh
457457
gen: \
458+
tailnet/proto/tailnet.pb.go \
459+
agent/proto/agent.pb.go \
458460
provisionersdk/proto/provisioner.pb.go \
459461
provisionerd/proto/provisionerd.pb.go \
460462
coderd/database/dump.sql \
@@ -479,6 +481,8 @@ gen: \
479481
# used during releases so we don't run generation scripts.
480482
gen/mark-fresh:
481483
files="\
484+
tailnet/proto/tailnet.pb.go \
485+
agent/proto/agent.pb.go \
482486
provisionersdk/proto/provisioner.pb.go \
483487
provisionerd/proto/provisionerd.pb.go \
484488
coderd/database/dump.sql \
@@ -524,6 +528,22 @@ coderd/database/querier.go: coderd/database/sqlc.yaml coderd/database/dump.sql $
524528
coderd/database/dbmock/dbmock.go: coderd/database/db.go coderd/database/querier.go
525529
go generate ./coderd/database/dbmock/
526530

531+
tailnet/proto/tailnet.pb.go: tailnet/proto/tailnet.proto
532+
protoc \
533+
--go_out=. \
534+
--go_opt=paths=source_relative \
535+
--go-drpc_out=. \
536+
--go-drpc_opt=paths=source_relative \
537+
./tailnet/proto/tailnet.proto
538+
539+
agent/proto/agent.pb.go: agent/proto/agent.proto
540+
protoc \
541+
--go_out=. \
542+
--go_opt=paths=source_relative \
543+
--go-drpc_out=. \
544+
--go-drpc_opt=paths=source_relative \
545+
./agent/proto/agent.proto
546+
527547
provisionersdk/proto/provisioner.pb.go: provisionersdk/proto/provisioner.proto
528548
protoc \
529549
--go_out=. \

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ curl -L https://coder.com/install.sh | sh
7070

7171
You can run the install script with `--dry-run` to see the commands that will be used to install without executing them. You can modify the installation process by including flags. Run the install script with `--help` for reference.
7272

73-
> See [install](docs/install) for additional methods.
73+
> See [install](https://coder.com/docs/v2/latest/install) for additional methods.
7474
7575
Once installed, you can start a production deployment<sup>1</sup> with a single command:
7676

agent/agent.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,14 @@ func (a *agent) reportMetadataLoop(ctx context.Context) {
536536
continue
537537
case <-report:
538538
if len(updatedMetadata) > 0 {
539+
select {
540+
case <-reportSemaphore:
541+
default:
542+
// If there's already a report in flight, don't send
543+
// another one, wait for next tick instead.
544+
continue
545+
}
546+
539547
metadata := make([]agentsdk.Metadata, 0, len(updatedMetadata))
540548
for key, result := range updatedMetadata {
541549
metadata = append(metadata, agentsdk.Metadata{
@@ -545,14 +553,6 @@ func (a *agent) reportMetadataLoop(ctx context.Context) {
545553
delete(updatedMetadata, key)
546554
}
547555

548-
select {
549-
case <-reportSemaphore:
550-
default:
551-
// If there's already a report in flight, don't send
552-
// another one, wait for next tick instead.
553-
continue
554-
}
555-
556556
go func() {
557557
ctx, cancel := context.WithTimeout(ctx, reportTimeout)
558558
defer func() {
@@ -743,7 +743,7 @@ func (a *agent) run(ctx context.Context) error {
743743
return script.RunOnStart
744744
})
745745
if err != nil {
746-
a.logger.Warn(ctx, "startup script failed", slog.Error(err))
746+
a.logger.Warn(ctx, "startup script(s) failed", slog.Error(err))
747747
if errors.Is(err, agentscripts.ErrTimeout) {
748748
a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStartTimeout)
749749
} else {
@@ -1465,6 +1465,7 @@ func (a *agent) Close() error {
14651465
return script.RunOnStop
14661466
})
14671467
if err != nil {
1468+
a.logger.Warn(ctx, "shutdown script(s) failed", slog.Error(err))
14681469
if errors.Is(err, agentscripts.ErrTimeout) {
14691470
lifecycleState = codersdk.WorkspaceAgentLifecycleShutdownTimeout
14701471
} else {

agent/agent_test.go

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,13 @@ func TestAgent_Session_TTY_MOTD(t *testing.T) {
350350
unexpected: []string{},
351351
},
352352
{
353-
name: "Trim",
354-
manifest: agentsdk.Manifest{},
353+
name: "Trim",
354+
// Enable motd since it will be printed after the banner,
355+
// this ensures that we can test for an exact mount of
356+
// newlines.
357+
manifest: agentsdk.Manifest{
358+
MOTDFile: name,
359+
},
355360
banner: codersdk.ServiceBannerConfig{
356361
Enabled: true,
357362
Message: "\n\n\n\n\n\nbanner\n\n\n\n\n\n",
@@ -375,6 +380,7 @@ func TestAgent_Session_TTY_MOTD(t *testing.T) {
375380
}
376381
}
377382

383+
//nolint:tparallel // Sub tests need to run sequentially.
378384
func TestAgent_Session_TTY_MOTD_Update(t *testing.T) {
379385
t.Parallel()
380386
if runtime.GOOS == "windows" {
@@ -434,33 +440,38 @@ func TestAgent_Session_TTY_MOTD_Update(t *testing.T) {
434440
}
435441
//nolint:dogsled // Allow the blank identifiers.
436442
conn, client, _, _, _ := setupAgent(t, agentsdk.Manifest{}, 0, setSBInterval)
437-
for _, test := range tests {
443+
444+
sshClient, err := conn.SSHClient(ctx)
445+
require.NoError(t, err)
446+
t.Cleanup(func() {
447+
_ = sshClient.Close()
448+
})
449+
450+
//nolint:paralleltest // These tests need to swap the banner func.
451+
for i, test := range tests {
438452
test := test
439-
// Set new banner func and wait for the agent to call it to update the
440-
// banner.
441-
ready := make(chan struct{}, 2)
442-
client.SetServiceBannerFunc(func() (codersdk.ServiceBannerConfig, error) {
443-
select {
444-
case ready <- struct{}{}:
445-
default:
446-
}
447-
return test.banner, nil
448-
})
449-
<-ready
450-
<-ready // Wait for two updates to ensure the value has propagated.
453+
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
454+
// Set new banner func and wait for the agent to call it to update the
455+
// banner.
456+
ready := make(chan struct{}, 2)
457+
client.SetServiceBannerFunc(func() (codersdk.ServiceBannerConfig, error) {
458+
select {
459+
case ready <- struct{}{}:
460+
default:
461+
}
462+
return test.banner, nil
463+
})
464+
<-ready
465+
<-ready // Wait for two updates to ensure the value has propagated.
451466

452-
sshClient, err := conn.SSHClient(ctx)
453-
require.NoError(t, err)
454-
t.Cleanup(func() {
455-
_ = sshClient.Close()
456-
})
457-
session, err := sshClient.NewSession()
458-
require.NoError(t, err)
459-
t.Cleanup(func() {
460-
_ = session.Close()
461-
})
467+
session, err := sshClient.NewSession()
468+
require.NoError(t, err)
469+
t.Cleanup(func() {
470+
_ = session.Close()
471+
})
462472

463-
testSessionOutput(t, session, test.expected, test.unexpected, nil)
473+
testSessionOutput(t, session, test.expected, test.unexpected, nil)
474+
})
464475
}
465476
}
466477

agent/agentscripts/agentscripts.go

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ import (
2727
var (
2828
// ErrTimeout is returned when a script times out.
2929
ErrTimeout = xerrors.New("script timed out")
30+
// ErrOutputPipesOpen is returned when a script exits leaving the output
31+
// pipe(s) (stdout, stderr) open. This happens because we set WaitDelay on
32+
// the command, which gives us two things:
33+
//
34+
// 1. The ability to ensure that a script exits (this is important for e.g.
35+
// blocking login, and avoiding doing so indefinitely)
36+
// 2. Improved command cancellation on timeout
37+
ErrOutputPipesOpen = xerrors.New("script exited without closing output pipes")
3038

3139
parser = cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.DowOptional)
3240
)
@@ -97,7 +105,15 @@ func (r *Runner) Init(scripts []codersdk.WorkspaceAgentScript) error {
97105
// StartCron starts the cron scheduler.
98106
// This is done async to allow for the caller to execute scripts prior.
99107
func (r *Runner) StartCron() {
100-
r.cron.Start()
108+
// cron.Start() and cron.Stop() does not guarantee that the cron goroutine
109+
// has exited by the time the `cron.Stop()` context returns, so we need to
110+
// track it manually.
111+
err := r.trackCommandGoroutine(func() {
112+
r.cron.Run()
113+
})
114+
if err != nil {
115+
r.Logger.Warn(context.Background(), "start cron failed", slog.Error(err))
116+
}
101117
}
102118

103119
// Execute runs a set of scripts according to a filter.
@@ -240,7 +256,22 @@ func (r *Runner) run(ctx context.Context, script codersdk.WorkspaceAgentScript)
240256
err = cmdCtx.Err()
241257
case err = <-cmdDone:
242258
}
243-
if errors.Is(err, context.DeadlineExceeded) {
259+
switch {
260+
case errors.Is(err, exec.ErrWaitDelay):
261+
err = ErrOutputPipesOpen
262+
message := fmt.Sprintf("script exited successfully, but output pipes were not closed after %s", cmd.WaitDelay)
263+
details := fmt.Sprint(
264+
"This usually means a child process was started with references to stdout or stderr. As a result, this " +
265+
"process may now have been terminated. Consider redirecting the output or using a separate " +
266+
"\"coder_script\" for the process, see " +
267+
"https://coder.com/docs/v2/latest/templates/troubleshooting#startup-script-issues for more information.",
268+
)
269+
// Inform the user by propagating the message via log writers.
270+
_, _ = fmt.Fprintf(cmd.Stderr, "WARNING: %s. %s\n", message, details)
271+
// Also log to agent logs for ease of debugging.
272+
r.Logger.Warn(ctx, message, slog.F("details", details), slog.Error(err))
273+
274+
case errors.Is(err, context.DeadlineExceeded):
244275
err = ErrTimeout
245276
}
246277
return err
@@ -254,7 +285,7 @@ func (r *Runner) Close() error {
254285
}
255286
close(r.closed)
256287
r.cronCtxCancel()
257-
r.cron.Stop()
288+
<-r.cron.Stop().Done()
258289
r.cmdCloseWait.Wait()
259290
return nil
260291
}

0 commit comments

Comments
 (0)