Skip to content

Commit ff6fd37

Browse files
authored
Merge branch 'coder:main' into rev-proxy-auto-tls
2 parents 77149bc + 5e4931e commit ff6fd37

File tree

116 files changed

+5974
-339
lines changed

Some content is hidden

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

116 files changed

+5974
-339
lines changed

agent/apphealth_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func TestAppHealth_NotSpamming(t *testing.T) {
158158
// Ensure we haven't made more than 2 (expected 1 + 1 for buffer) requests in the last second.
159159
// if there is a bug where we are spamming the healthcheck route this will catch it.
160160
time.Sleep(time.Second)
161-
require.LessOrEqual(t, *counter, int32(2))
161+
require.LessOrEqual(t, atomic.LoadInt32(counter), int32(2))
162162
}
163163

164164
func setupAppReporter(ctx context.Context, t *testing.T, apps []codersdk.WorkspaceApp, handlers []http.Handler) (agent.WorkspaceAgentApps, func()) {

cli/ping.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/spf13/cobra"
9+
"golang.org/x/xerrors"
10+
11+
"cdr.dev/slog"
12+
"cdr.dev/slog/sloggers/sloghuman"
13+
14+
"github.com/coder/coder/cli/cliui"
15+
"github.com/coder/coder/codersdk"
16+
)
17+
18+
func ping() *cobra.Command {
19+
var (
20+
pingNum int
21+
pingTimeout time.Duration
22+
pingWait time.Duration
23+
verbose bool
24+
)
25+
cmd := &cobra.Command{
26+
Annotations: workspaceCommand,
27+
Use: "ping <workspace>",
28+
Short: "Ping a workspace",
29+
Args: cobra.ExactArgs(1),
30+
RunE: func(cmd *cobra.Command, args []string) error {
31+
ctx, cancel := context.WithCancel(cmd.Context())
32+
defer cancel()
33+
34+
client, err := CreateClient(cmd)
35+
if err != nil {
36+
return err
37+
}
38+
39+
workspaceName := args[0]
40+
_, workspaceAgent, err := getWorkspaceAndAgent(ctx, cmd, client, codersdk.Me, workspaceName, false)
41+
if err != nil {
42+
return err
43+
}
44+
45+
var logger slog.Logger
46+
if verbose {
47+
logger = slog.Make(sloghuman.Sink(cmd.OutOrStdout())).Leveled(slog.LevelDebug)
48+
}
49+
50+
conn, err := client.DialWorkspaceAgent(ctx, workspaceAgent.ID, &codersdk.DialWorkspaceAgentOptions{Logger: logger})
51+
if err != nil {
52+
return err
53+
}
54+
defer conn.Close()
55+
56+
derpMap := conn.DERPMap()
57+
_ = derpMap
58+
59+
n := 0
60+
didP2p := false
61+
start := time.Now()
62+
for {
63+
if n > 0 {
64+
time.Sleep(time.Second)
65+
}
66+
n++
67+
68+
ctx, cancel := context.WithTimeout(ctx, pingTimeout)
69+
dur, p2p, pong, err := conn.Ping(ctx)
70+
cancel()
71+
if err != nil {
72+
if xerrors.Is(err, context.DeadlineExceeded) {
73+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "ping to %q timed out \n", workspaceName)
74+
if n == pingNum {
75+
return nil
76+
}
77+
continue
78+
}
79+
if xerrors.Is(err, context.Canceled) {
80+
return nil
81+
}
82+
83+
if err.Error() == "no matching peer" {
84+
continue
85+
}
86+
87+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "ping to %q failed %s\n", workspaceName, err.Error())
88+
if n == pingNum {
89+
return nil
90+
}
91+
continue
92+
}
93+
94+
dur = dur.Round(time.Millisecond)
95+
var via string
96+
if p2p {
97+
if !didP2p {
98+
_, _ = fmt.Fprintln(cmd.OutOrStdout(), "p2p connection established in",
99+
cliui.Styles.DateTimeStamp.Render(time.Since(start).Round(time.Millisecond).String()),
100+
)
101+
}
102+
didP2p = true
103+
104+
via = fmt.Sprintf("%s via %s",
105+
cliui.Styles.Fuchsia.Render("p2p"),
106+
cliui.Styles.Code.Render(pong.Endpoint),
107+
)
108+
} else {
109+
derpName := "unknown"
110+
derpRegion, ok := derpMap.Regions[pong.DERPRegionID]
111+
if ok {
112+
derpName = derpRegion.RegionName
113+
}
114+
via = fmt.Sprintf("%s via %s",
115+
cliui.Styles.Fuchsia.Render("proxied"),
116+
cliui.Styles.Code.Render(fmt.Sprintf("DERP(%s)", derpName)),
117+
)
118+
}
119+
120+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "pong from %s %s in %s\n",
121+
cliui.Styles.Keyword.Render(workspaceName),
122+
via,
123+
cliui.Styles.DateTimeStamp.Render(dur.String()),
124+
)
125+
126+
if n == pingNum {
127+
return nil
128+
}
129+
}
130+
},
131+
}
132+
133+
cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Enables verbose logging.")
134+
cmd.Flags().DurationVarP(&pingWait, "wait", "", time.Second, "Specifies how long to wait between pings.")
135+
cmd.Flags().DurationVarP(&pingTimeout, "timeout", "t", 5*time.Second, "Specifies how long to wait for a ping to complete.")
136+
cmd.Flags().IntVarP(&pingNum, "num", "n", 10, "Specifies the number of pings to perform.")
137+
return cmd
138+
}

cli/ping_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package cli_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
9+
"cdr.dev/slog/sloggers/slogtest"
10+
11+
"github.com/coder/coder/agent"
12+
"github.com/coder/coder/cli/clitest"
13+
"github.com/coder/coder/codersdk/agentsdk"
14+
"github.com/coder/coder/pty/ptytest"
15+
"github.com/coder/coder/testutil"
16+
)
17+
18+
func TestPing(t *testing.T) {
19+
t.Parallel()
20+
21+
t.Run("OK", func(t *testing.T) {
22+
t.Parallel()
23+
24+
client, workspace, agentToken := setupWorkspaceForAgent(t, nil)
25+
cmd, root := clitest.New(t, "ping", workspace.Name)
26+
clitest.SetupConfig(t, client, root)
27+
pty := ptytest.New(t)
28+
cmd.SetIn(pty.Input())
29+
cmd.SetErr(pty.Output())
30+
cmd.SetOut(pty.Output())
31+
32+
agentClient := agentsdk.New(client.URL)
33+
agentClient.SetSessionToken(agentToken)
34+
agentCloser := agent.New(agent.Options{
35+
Client: agentClient,
36+
Logger: slogtest.Make(t, nil).Named("agent"),
37+
})
38+
defer func() {
39+
_ = agentCloser.Close()
40+
}()
41+
42+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
43+
defer cancel()
44+
45+
cmdDone := tGo(t, func() {
46+
err := cmd.ExecuteContext(ctx)
47+
assert.NoError(t, err)
48+
})
49+
50+
pty.ExpectMatch("pong from " + workspace.Name)
51+
cancel()
52+
<-cmdDone
53+
})
54+
}

cli/root.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,12 @@ func Core() []*cobra.Command {
8585
login(),
8686
logout(),
8787
parameters(),
88+
ping(),
8889
portForward(),
8990
publickey(),
9091
rename(),
9192
resetPassword(),
93+
restart(),
9294
scaletest(),
9395
schedules(),
9496
show(),
@@ -97,7 +99,6 @@ func Core() []*cobra.Command {
9799
start(),
98100
state(),
99101
stop(),
100-
restart(),
101102
templates(),
102103
tokens(),
103104
update(),

cli/speedtest.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func speedtest() *cobra.Command {
7171
return ctx.Err()
7272
case <-ticker.C:
7373
}
74-
dur, p2p, err := conn.Ping(ctx)
74+
dur, p2p, _, err := conn.Ping(ctx)
7575
if err != nil {
7676
continue
7777
}

cli/speedtest_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import (
55
"testing"
66

77
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
89

910
"cdr.dev/slog/sloggers/slogtest"
1011
"github.com/coder/coder/agent"
1112
"github.com/coder/coder/cli/clitest"
1213
"github.com/coder/coder/coderd/coderdtest"
14+
"github.com/coder/coder/codersdk"
1315
"github.com/coder/coder/codersdk/agentsdk"
1416
"github.com/coder/coder/pty/ptytest"
1517
"github.com/coder/coder/testutil"
@@ -30,13 +32,27 @@ func TestSpeedtest(t *testing.T) {
3032
defer agentCloser.Close()
3133
coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
3234

35+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
36+
defer cancel()
37+
38+
require.Eventually(t, func() bool {
39+
ws, err := client.Workspace(ctx, workspace.ID)
40+
if !assert.NoError(t, err) {
41+
return false
42+
}
43+
a := ws.LatestBuild.Resources[0].Agents[0]
44+
return a.Status == codersdk.WorkspaceAgentConnected &&
45+
a.LifecycleState == codersdk.WorkspaceAgentLifecycleReady
46+
}, testutil.WaitLong, testutil.IntervalFast, "agent is not ready")
47+
3348
cmd, root := clitest.New(t, "speedtest", workspace.Name)
3449
clitest.SetupConfig(t, client, root)
3550
pty := ptytest.New(t)
3651
cmd.SetOut(pty.Output())
3752

38-
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
53+
ctx, cancel = context.WithTimeout(context.Background(), testutil.WaitLong)
3954
defer cancel()
55+
4056
cmdDone := tGo(t, func() {
4157
err := cmd.ExecuteContext(ctx)
4258
assert.NoError(t, err)

cli/testdata/coder_--help.golden

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Workspace Commands:
3636
create Create a workspace
3737
delete Delete a workspace
3838
list List workspaces
39+
ping Ping a workspace
3940
rename Rename a workspace
4041
restart Restart a workspace
4142
schedule Schedule automated start and stop times for workspaces

cli/testdata/coder_ping_--help.golden

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Ping a workspace
2+
3+
Usage:
4+
coder ping <workspace> [flags]
5+
6+
Flags:
7+
-h, --help help for ping
8+
-n, --num int Specifies the number of pings to perform. (default 10)
9+
-t, --timeout duration Specifies how long to wait for a ping to complete. (default 5s)
10+
-v, --verbose Enables verbose logging.
11+
--wait duration Specifies how long to wait between pings. (default 1s)
12+
13+
Global Flags:
14+
--global-config coder Path to the global coder config directory.
15+
Consumes $CODER_CONFIG_DIR (default "~/.config/coderv2")
16+
--header stringArray HTTP headers added to all requests. Provide as "Key=Value".
17+
Consumes $CODER_HEADER
18+
--no-feature-warning Suppress warnings about unlicensed features.
19+
Consumes $CODER_NO_FEATURE_WARNING
20+
--no-version-warning Suppress warning when client and server versions do not match.
21+
Consumes $CODER_NO_VERSION_WARNING
22+
--token string Specify an authentication token. For security reasons setting
23+
CODER_SESSION_TOKEN is preferred.
24+
Consumes $CODER_SESSION_TOKEN
25+
--url string URL to a deployment.
26+
Consumes $CODER_URL

cli/vscodessh.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ type sshNetworkStats struct {
204204
}
205205

206206
func collectNetworkStats(ctx context.Context, agentConn *codersdk.WorkspaceAgentConn, start, end time.Time, counts map[netlogtype.Connection]netlogtype.Counts) (*sshNetworkStats, error) {
207-
latency, p2p, err := agentConn.Ping(ctx)
207+
latency, p2p, _, err := agentConn.Ping(ctx)
208208
if err != nil {
209209
return nil, err
210210
}

coderd/activitybump.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import (
1515

1616
// activityBumpWorkspace automatically bumps the workspace's auto-off timer
1717
// if it is set to expire soon.
18-
func activityBumpWorkspace(log slog.Logger, db database.Store, workspaceID uuid.UUID) {
18+
func activityBumpWorkspace(ctx context.Context, log slog.Logger, db database.Store, workspaceID uuid.UUID) {
1919
// We set a short timeout so if the app is under load, these
2020
// low priority operations fail first.
21-
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
21+
ctx, cancel := context.WithTimeout(ctx, time.Second*15)
2222
defer cancel()
2323

2424
err := db.InTx(func(s database.Store) error {
@@ -82,9 +82,12 @@ func activityBumpWorkspace(log slog.Logger, db database.Store, workspaceID uuid.
8282
return nil
8383
}, nil)
8484
if err != nil {
85-
log.Error(ctx, "bump failed", slog.Error(err),
86-
slog.F("workspace_id", workspaceID),
87-
)
85+
if !xerrors.Is(err, context.Canceled) {
86+
// Bump will fail if the context is cancelled, but this is ok.
87+
log.Error(ctx, "bump failed", slog.Error(err),
88+
slog.F("workspace_id", workspaceID),
89+
)
90+
}
8891
return
8992
}
9093

coderd/apidoc/docs.go

Lines changed: 7 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)