Skip to content

Commit 93958e9

Browse files
committed
Merge branch 'main' into provisioner-fixes
2 parents 269fe66 + c547591 commit 93958e9

File tree

344 files changed

+20072
-11210
lines changed

Some content is hidden

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

344 files changed

+20072
-11210
lines changed

.github/pull_request_template.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

.github/workflows/ci.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,9 @@ jobs:
186186

187187
- name: Install Protoc
188188
run: |
189-
# protoc must be in lockstep with our dogfood Dockerfile
190-
# or the version in the comments will differ.
189+
# protoc must be in lockstep with our dogfood Dockerfile or the
190+
# version in the comments will differ. This is also defined in
191+
# security.yaml
191192
set -x
192193
cd dogfood
193194
DOCKER_BUILDKIT=1 docker build . --target proto -t protoc
@@ -511,7 +512,7 @@ jobs:
511512
- name: Install node_modules
512513
run: ./scripts/yarn_install.sh
513514

514-
- run: yarn test:ci
515+
- run: yarn test:ci --max-workers ${{ steps.cpu-cores.outputs.count }}
515516
working-directory: site
516517

517518
- uses: codecov/codecov-action@v3

.github/workflows/contrib.yaml

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,6 @@ jobs:
2727
steps:
2828
- uses: hmarr/auto-approve-action@v3
2929
if: github.actor == 'dependabot[bot]'
30-
auto-approve-docs:
31-
runs-on: ubuntu-latest
32-
if: github.event_name == 'pull_request_target'
33-
permissions:
34-
pull-requests: write
35-
steps:
36-
- uses: actions/checkout@v3
37-
- name: Get changed files in the docs folder
38-
id: changed-files
39-
uses: tj-actions/changed-files@v35
40-
with:
41-
files: docs/*
42-
- uses: hmarr/auto-approve-action@v3
43-
if: github.actor == 'bpmct' && steps.changed-files.outputs.only_changed == 'true'
4430

4531
cla:
4632
runs-on: ubuntu-latest

.github/workflows/security.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,22 @@ jobs:
9999
100100
- name: Install yq
101101
run: go run github.com/mikefarah/yq/v4@v4.30.6
102+
- name: Install protoc-gen-go
103+
run: go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
104+
- name: Install protoc-gen-go-drpc
105+
run: go install storj.io/drpc/cmd/protoc-gen-go-drpc@v0.0.26
106+
- name: Install Protoc
107+
run: |
108+
# protoc must be in lockstep with our dogfood Dockerfile or the
109+
# version in the comments will differ. This is also defined in
110+
# ci.yaml.
111+
set -x
112+
cd dogfood
113+
DOCKER_BUILDKIT=1 docker build . --target proto -t protoc
114+
protoc_path=/usr/local/bin/protoc
115+
docker run --rm --entrypoint cat protoc /tmp/bin/protoc > $protoc_path
116+
chmod +x $protoc_path
117+
protoc --version
102118
103119
- name: Build Coder linux amd64 Docker image
104120
id: build

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ site/test-results/*
2727
site/e2e/test-results/*
2828
site/e2e/states/*.json
2929
site/playwright-report/*
30+
site/.swc
3031

3132
# Make target for updating golden files.
3233
cli/testdata/.gen-golden
34+
helm/tests/testdata/.gen-golden
3335

3436
# Build
3537
/build/

.golangci.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ linters:
215215
- asciicheck
216216
- bidichk
217217
- bodyclose
218-
- deadcode
219218
- dogsled
220219
- errcheck
221220
- errname
@@ -259,4 +258,3 @@ linters:
259258
- typecheck
260259
- unconvert
261260
- unused
262-
- varcheck

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ site/test-results/*
3030
site/e2e/test-results/*
3131
site/e2e/states/*.json
3232
site/playwright-report/*
33+
site/.swc
3334

3435
# Make target for updating golden files.
3536
cli/testdata/.gen-golden
37+
helm/tests/testdata/.gen-golden
3638

3739
# Build
3840
/build/

Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,8 @@ docs/admin/prometheus.md: scripts/metricsdocgen/main.go scripts/metricsdocgen/me
501501
yarn run format:write:only ../docs/admin/prometheus.md
502502

503503
docs/cli.md: scripts/clidocgen/main.go $(GO_SRC_FILES) docs/manifest.json
504-
rm -rf ./docs/cli/*.md
504+
# TODO(@ammario): re-enable server.md once we finish clibase migration.
505+
ls ./docs/cli/*.md | grep -vP "\/coder_server" | xargs rm
505506
BASE_PATH="." go run ./scripts/clidocgen
506507
cd site
507508
yarn run format:write:only ../docs/cli.md ../docs/cli/*.md ../docs/manifest.json
@@ -515,13 +516,17 @@ coderd/apidoc/swagger.json: $(shell find ./scripts/apidocgen $(FIND_EXCLUSIONS)
515516
./scripts/apidocgen/generate.sh
516517
yarn run --cwd=site format:write:only ../docs/api ../docs/manifest.json ../coderd/apidoc/swagger.json
517518

518-
update-golden-files: cli/testdata/.gen-golden
519+
update-golden-files: cli/testdata/.gen-golden helm/tests/testdata/.gen-golden
519520
.PHONY: update-golden-files
520521

521522
cli/testdata/.gen-golden: $(wildcard cli/testdata/*.golden) $(GO_SRC_FILES)
522523
go test ./cli -run=TestCommandHelp -update
523524
touch "$@"
524525

526+
helm/tests/testdata/.gen-golden: $(wildcard helm/tests/testdata/*.golden) $(GO_SRC_FILES)
527+
go test ./helm/tests -run=TestUpdateGoldenFiles -update
528+
touch "$@"
529+
525530
# Generate a prettierrc for the site package that uses relative paths for
526531
# overrides. This allows us to share the same prettier config between the
527532
# site and the root of the repo.

agent/agent.go

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"os/exec"
1818
"os/user"
1919
"path/filepath"
20+
"reflect"
2021
"runtime"
2122
"sort"
2223
"strconv"
@@ -60,7 +61,7 @@ const (
6061

6162
// MagicSSHSessionTypeEnvironmentVariable is used to track the purpose behind an SSH connection.
6263
// This is stripped from any commands being executed, and is counted towards connection stats.
63-
MagicSSHSessionTypeEnvironmentVariable = "__CODER_SSH_SESSION_TYPE"
64+
MagicSSHSessionTypeEnvironmentVariable = "CODER_SSH_SESSION_TYPE"
6465
// MagicSSHSessionTypeVSCode is set in the SSH config by the VS Code extension to identify itself.
6566
MagicSSHSessionTypeVSCode = "vscode"
6667
// MagicSSHSessionTypeJetBrains is set in the SSH config by the JetBrains extension to identify itself.
@@ -76,6 +77,7 @@ type Options struct {
7677
ReconnectingPTYTimeout time.Duration
7778
EnvironmentVariables map[string]string
7879
Logger slog.Logger
80+
AgentPorts map[int]string
7981
}
8082

8183
type Client interface {
@@ -122,9 +124,8 @@ func New(options Options) io.Closer {
122124
tempDir: options.TempDir,
123125
lifecycleUpdate: make(chan struct{}, 1),
124126
lifecycleReported: make(chan codersdk.WorkspaceAgentLifecycle, 1),
125-
// TODO: This is a temporary hack to make tests not flake.
126-
// @kylecarbs has a better solution in here: https://github.com/coder/coder/pull/6469
127-
connStatsChan: make(chan *agentsdk.Stats, 8),
127+
ignorePorts: options.AgentPorts,
128+
connStatsChan: make(chan *agentsdk.Stats, 1),
128129
}
129130
a.init(ctx)
130131
return a
@@ -137,6 +138,10 @@ type agent struct {
137138
filesystem afero.Fs
138139
logDir string
139140
tempDir string
141+
// ignorePorts tells the api handler which ports to ignore when
142+
// listing all listening ports. This is helpful to hide ports that
143+
// are used by the agent, that the user does not care about.
144+
ignorePorts map[int]string
140145

141146
reconnectingPTYs sync.Map
142147
reconnectingPTYTimeout time.Duration
@@ -159,11 +164,8 @@ type agent struct {
159164

160165
network *tailnet.Conn
161166
connStatsChan chan *agentsdk.Stats
167+
latestStat atomic.Pointer[agentsdk.Stats]
162168

163-
statRxPackets atomic.Int64
164-
statRxBytes atomic.Int64
165-
statTxPackets atomic.Int64
166-
statTxBytes atomic.Int64
167169
connCountVSCode atomic.Int64
168170
connCountJetBrains atomic.Int64
169171
connCountReconnectingPTY atomic.Int64
@@ -905,10 +907,13 @@ func (a *agent) handleSSHSession(session ssh.Session) (retErr error) {
905907
switch magicType {
906908
case MagicSSHSessionTypeVSCode:
907909
a.connCountVSCode.Add(1)
910+
defer a.connCountVSCode.Add(-1)
908911
case MagicSSHSessionTypeJetBrains:
909912
a.connCountJetBrains.Add(1)
913+
defer a.connCountJetBrains.Add(-1)
910914
case "":
911915
a.connCountSSHSession.Add(1)
916+
defer a.connCountSSHSession.Add(-1)
912917
default:
913918
a.logger.Warn(ctx, "invalid magic ssh session type specified", slog.F("type", magicType))
914919
}
@@ -1012,6 +1017,7 @@ func (a *agent) handleReconnectingPTY(ctx context.Context, logger slog.Logger, m
10121017
defer conn.Close()
10131018

10141019
a.connCountReconnectingPTY.Add(1)
1020+
defer a.connCountReconnectingPTY.Add(-1)
10151021

10161022
connectionID := uuid.NewString()
10171023
logger = logger.With(slog.F("id", msg.ID), slog.F("connection_id", connectionID))
@@ -1210,18 +1216,15 @@ func (a *agent) startReportingConnectionStats(ctx context.Context) {
12101216
ConnectionCount: int64(len(networkStats)),
12111217
ConnectionsByProto: map[string]int64{},
12121218
}
1213-
// Tailscale resets counts on every report!
1214-
// We'd rather have these compound, like Linux does!
12151219
for conn, counts := range networkStats {
12161220
stats.ConnectionsByProto[conn.Proto.String()]++
1217-
stats.RxBytes = a.statRxBytes.Add(int64(counts.RxBytes))
1218-
stats.RxPackets = a.statRxPackets.Add(int64(counts.RxPackets))
1219-
stats.TxBytes = a.statTxBytes.Add(int64(counts.TxBytes))
1220-
stats.TxPackets = a.statTxPackets.Add(int64(counts.TxPackets))
1221+
stats.RxBytes += int64(counts.RxBytes)
1222+
stats.RxPackets += int64(counts.RxPackets)
1223+
stats.TxBytes += int64(counts.TxBytes)
1224+
stats.TxPackets += int64(counts.TxPackets)
12211225
}
12221226

1223-
// Tailscale's connection stats are not cumulative, but it makes no sense to make
1224-
// ours temporary.
1227+
// The count of active sessions.
12251228
stats.SessionCountSSH = a.connCountSSHSession.Load()
12261229
stats.SessionCountVSCode = a.connCountVSCode.Load()
12271230
stats.SessionCountJetBrains = a.connCountJetBrains.Load()
@@ -1270,10 +1273,16 @@ func (a *agent) startReportingConnectionStats(ctx context.Context) {
12701273
// Convert from microseconds to milliseconds.
12711274
stats.ConnectionMedianLatencyMS /= 1000
12721275

1276+
lastStat := a.latestStat.Load()
1277+
if lastStat != nil && reflect.DeepEqual(lastStat, stats) {
1278+
a.logger.Info(ctx, "skipping stat because nothing changed")
1279+
return
1280+
}
1281+
a.latestStat.Store(stats)
1282+
12731283
select {
12741284
case a.connStatsChan <- stats:
1275-
default:
1276-
a.logger.Warn(ctx, "network stat dropped")
1285+
case <-a.closed:
12771286
}
12781287
}
12791288

agent/agent_test.go

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ func TestAgent_Stats_SSH(t *testing.T) {
6868
session, err := sshClient.NewSession()
6969
require.NoError(t, err)
7070
defer session.Close()
71-
require.NoError(t, session.Run("echo test"))
71+
stdin, err := session.StdinPipe()
72+
require.NoError(t, err)
73+
err = session.Shell()
74+
require.NoError(t, err)
7275

7376
var s *agentsdk.Stats
7477
require.Eventuallyf(t, func() bool {
@@ -78,6 +81,9 @@ func TestAgent_Stats_SSH(t *testing.T) {
7881
}, testutil.WaitLong, testutil.IntervalFast,
7982
"never saw stats: %+v", s,
8083
)
84+
_ = stdin.Close()
85+
err = session.Wait()
86+
require.NoError(t, err)
8187
}
8288

8389
func TestAgent_Stats_ReconnectingPTY(t *testing.T) {
@@ -112,43 +118,69 @@ func TestAgent_Stats_ReconnectingPTY(t *testing.T) {
112118

113119
func TestAgent_Stats_Magic(t *testing.T) {
114120
t.Parallel()
121+
t.Run("StripsEnvironmentVariable", func(t *testing.T) {
122+
t.Parallel()
123+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
124+
defer cancel()
125+
//nolint:dogsled
126+
conn, _, _, _, _ := setupAgent(t, agentsdk.Metadata{}, 0)
127+
sshClient, err := conn.SSHClient(ctx)
128+
require.NoError(t, err)
129+
defer sshClient.Close()
130+
session, err := sshClient.NewSession()
131+
require.NoError(t, err)
132+
session.Setenv(agent.MagicSSHSessionTypeEnvironmentVariable, agent.MagicSSHSessionTypeVSCode)
133+
defer session.Close()
115134

116-
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
117-
defer cancel()
118-
119-
//nolint:dogsled
120-
conn, _, stats, _, _ := setupAgent(t, agentsdk.Metadata{}, 0)
121-
sshClient, err := conn.SSHClient(ctx)
122-
require.NoError(t, err)
123-
defer sshClient.Close()
124-
session, err := sshClient.NewSession()
125-
require.NoError(t, err)
126-
session.Setenv(agent.MagicSSHSessionTypeEnvironmentVariable, agent.MagicSSHSessionTypeVSCode)
127-
defer session.Close()
128-
129-
command := "sh -c 'echo $" + agent.MagicSSHSessionTypeEnvironmentVariable + "'"
130-
expected := ""
131-
if runtime.GOOS == "windows" {
132-
expected = "%" + agent.MagicSSHSessionTypeEnvironmentVariable + "%"
133-
command = "cmd.exe /c echo " + expected
134-
}
135-
output, err := session.Output(command)
136-
require.NoError(t, err)
137-
require.Equal(t, expected, strings.TrimSpace(string(output)))
138-
var s *agentsdk.Stats
139-
require.Eventuallyf(t, func() bool {
140-
var ok bool
141-
s, ok = <-stats
142-
return ok && s.ConnectionCount > 0 && s.RxBytes > 0 && s.TxBytes > 0 &&
143-
// Ensure that the connection didn't count as a "normal" SSH session.
144-
// This was a special one, so it should be labeled specially in the stats!
145-
s.SessionCountVSCode == 1 &&
146-
// Ensure that connection latency is being counted!
147-
// If it isn't, it's set to -1.
148-
s.ConnectionMedianLatencyMS >= 0
149-
}, testutil.WaitLong, testutil.IntervalFast,
150-
"never saw stats: %+v", s,
151-
)
135+
command := "sh -c 'echo $" + agent.MagicSSHSessionTypeEnvironmentVariable + "'"
136+
expected := ""
137+
if runtime.GOOS == "windows" {
138+
expected = "%" + agent.MagicSSHSessionTypeEnvironmentVariable + "%"
139+
command = "cmd.exe /c echo " + expected
140+
}
141+
output, err := session.Output(command)
142+
require.NoError(t, err)
143+
require.Equal(t, expected, strings.TrimSpace(string(output)))
144+
})
145+
t.Run("Tracks", func(t *testing.T) {
146+
t.Parallel()
147+
if runtime.GOOS == "window" {
148+
t.Skip("Sleeping for infinity doesn't work on Windows")
149+
}
150+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
151+
defer cancel()
152+
//nolint:dogsled
153+
conn, _, stats, _, _ := setupAgent(t, agentsdk.Metadata{}, 0)
154+
sshClient, err := conn.SSHClient(ctx)
155+
require.NoError(t, err)
156+
defer sshClient.Close()
157+
session, err := sshClient.NewSession()
158+
require.NoError(t, err)
159+
session.Setenv(agent.MagicSSHSessionTypeEnvironmentVariable, agent.MagicSSHSessionTypeVSCode)
160+
defer session.Close()
161+
stdin, err := session.StdinPipe()
162+
require.NoError(t, err)
163+
err = session.Shell()
164+
require.NoError(t, err)
165+
var s *agentsdk.Stats
166+
require.Eventuallyf(t, func() bool {
167+
var ok bool
168+
s, ok = <-stats
169+
return ok && s.ConnectionCount > 0 && s.RxBytes > 0 && s.TxBytes > 0 &&
170+
// Ensure that the connection didn't count as a "normal" SSH session.
171+
// This was a special one, so it should be labeled specially in the stats!
172+
s.SessionCountVSCode == 1 &&
173+
// Ensure that connection latency is being counted!
174+
// If it isn't, it's set to -1.
175+
s.ConnectionMedianLatencyMS >= 0
176+
}, testutil.WaitLong, testutil.IntervalFast,
177+
"never saw stats: %+v", s,
178+
)
179+
// The shell will automatically exit if there is no stdin!
180+
_ = stdin.Close()
181+
err = session.Wait()
182+
require.NoError(t, err)
183+
})
152184
}
153185

154186
func TestAgent_SessionExec(t *testing.T) {

0 commit comments

Comments
 (0)