Skip to content

Commit 02e079d

Browse files
committed
Merge branch 'main' into colin/pg-coordinate
2 parents bd82c5e + e8e095e commit 02e079d

File tree

394 files changed

+12022
-7031
lines changed

Some content is hidden

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

394 files changed

+12022
-7031
lines changed

.github/workflows/coder.yaml

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ on:
44
push:
55
branches:
66
- main
7-
tags:
8-
- "*"
97

108
pull_request:
119

@@ -36,7 +34,7 @@ jobs:
3634
- name: Checkout
3735
uses: actions/checkout@v2
3836
- name: typos-action
39-
uses: crate-ci/typos@master
37+
uses: crate-ci/typos@v1.12.8
4038
with:
4139
config: .github/workflows/typos.toml
4240
- name: Fix Helper
@@ -489,6 +487,7 @@ jobs:
489487
go mod download
490488
491489
version="$(./scripts/version.sh)"
490+
make gen/mark-fresh
492491
make -j \
493492
build/coder_"$version"_windows_amd64.zip \
494493
build/coder_"$version"_linux_amd64.{tar.gz,deb}

.github/workflows/dogfood.yaml

+1-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ on:
44
push:
55
branches:
66
- main
7-
tags:
8-
- "*"
97
paths:
108
- "dogfood/**"
119
pull_request:
@@ -19,7 +17,7 @@ jobs:
1917
steps:
2018
- name: Get branch name
2119
id: branch-name
22-
uses: tj-actions/branch-names@v5.4
20+
uses: tj-actions/branch-names@v6.1
2321

2422
- name: "Branch name to Docker tag name"
2523
id: docker-tag-name

.github/workflows/stale.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
steps:
1414
# v5.1.0 has a weird bug that makes stalebot add then remove its own label
1515
# https://github.com/actions/stale/pull/775
16-
- uses: actions/stale@v5.0.0
16+
- uses: actions/stale@v6.0.0
1717
with:
1818
stale-issue-label: stale
1919
stale-pr-label: stale

.github/workflows/welcome.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ on:
55
jobs:
66
test:
77
runs-on: ubuntu-latest
8+
permissions:
9+
pull-requests: write
810
steps:
911
- uses: wow-actions/welcome@v1
1012
with:

.gitignore

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ site/**/*.typegen.ts
3131
site/build-storybook.log
3232

3333
# Build
34-
build/
35-
dist/
34+
/build/
35+
/dist/
3636
site/out/
3737

3838
*.tfstate

.vscode/settings.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
"cliflag",
1010
"cliui",
1111
"codecov",
12-
"Codespaces",
1312
"coderd",
13+
"coderdenttest",
1414
"coderdtest",
1515
"codersdk",
1616
"cronstrue",
@@ -24,6 +24,7 @@
2424
"drpcmux",
2525
"drpcserver",
2626
"Dsts",
27+
"enablements",
2728
"fatih",
2829
"Formik",
2930
"gitsshkey",

Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ COPY --chown=coder:coder --chmod=700 empty-dir /home/coder
2525

2626
USER coder:coder
2727
ENV HOME=/home/coder
28+
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt
2829
WORKDIR /home/coder
2930

3031
ENTRYPOINT [ "/opt/coder", "server" ]

Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,6 @@ build/coder_helm_$(VERSION).tgz:
329329
site/out/index.html: $(shell find ./site -not -path './site/node_modules/*' -type f -name '*.tsx') $(shell find ./site -not -path './site/node_modules/*' -type f -name '*.ts') site/package.json
330330
./scripts/yarn_install.sh
331331
cd site
332-
yarn typegen
333332
yarn build
334333

335334
install: build/coder_$(VERSION)_$(GOOS)_$(GOARCH)$(GOOS_BIN_EXT)

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Once installed, you can start a production deployment<sup>1</sup> with a single
5858

5959
```sh
6060
# Automatically sets up an external access URL on *.try.coder.app
61-
coder server --tunnel
61+
coder server
6262

6363
# Requires a PostgreSQL instance and external access URL
6464
coder server --postgres-url <url> --access-url <url>

agent/agent.go

+70-49
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fmt"
1111
"io"
1212
"net"
13+
"net/http"
1314
"net/netip"
1415
"os"
1516
"os/exec"
@@ -33,6 +34,7 @@ import (
3334

3435
"cdr.dev/slog"
3536
"github.com/coder/coder/agent/usershell"
37+
"github.com/coder/coder/codersdk"
3638
"github.com/coder/coder/pty"
3739
"github.com/coder/coder/tailnet"
3840
"github.com/coder/retry"
@@ -49,55 +51,41 @@ const (
4951
MagicSessionErrorCode = 229
5052
)
5153

52-
var (
53-
// tailnetIP is a static IPv6 address with the Tailscale prefix that is used to route
54-
// connections from clients to this node. A dynamic address is not required because a Tailnet
55-
// client only dials a single agent at a time.
56-
tailnetIP = netip.MustParseAddr("fd7a:115c:a1e0:49d6:b259:b7ac:b1b2:48f4")
57-
tailnetSSHPort = 1
58-
tailnetReconnectingPTYPort = 2
59-
tailnetSpeedtestPort = 3
60-
)
61-
6254
type Options struct {
63-
CoordinatorDialer CoordinatorDialer
64-
FetchMetadata FetchMetadata
65-
66-
StatsReporter StatsReporter
67-
ReconnectingPTYTimeout time.Duration
68-
EnvironmentVariables map[string]string
69-
Logger slog.Logger
70-
}
71-
72-
type Metadata struct {
73-
DERPMap *tailcfg.DERPMap `json:"derpmap"`
74-
EnvironmentVariables map[string]string `json:"environment_variables"`
75-
StartupScript string `json:"startup_script"`
76-
Directory string `json:"directory"`
55+
CoordinatorDialer CoordinatorDialer
56+
FetchMetadata FetchMetadata
57+
StatsReporter StatsReporter
58+
WorkspaceAgentApps WorkspaceAgentApps
59+
PostWorkspaceAgentAppHealth PostWorkspaceAgentAppHealth
60+
ReconnectingPTYTimeout time.Duration
61+
EnvironmentVariables map[string]string
62+
Logger slog.Logger
7763
}
7864

7965
// CoordinatorDialer is a function that constructs a new broker.
8066
// A dialer must be passed in to allow for reconnects.
81-
type CoordinatorDialer func(ctx context.Context) (net.Conn, error)
67+
type CoordinatorDialer func(context.Context) (net.Conn, error)
8268

8369
// FetchMetadata is a function to obtain metadata for the agent.
84-
type FetchMetadata func(ctx context.Context) (Metadata, error)
70+
type FetchMetadata func(context.Context) (codersdk.WorkspaceAgentMetadata, error)
8571

8672
func New(options Options) io.Closer {
8773
if options.ReconnectingPTYTimeout == 0 {
8874
options.ReconnectingPTYTimeout = 5 * time.Minute
8975
}
9076
ctx, cancelFunc := context.WithCancel(context.Background())
9177
server := &agent{
92-
reconnectingPTYTimeout: options.ReconnectingPTYTimeout,
93-
logger: options.Logger,
94-
closeCancel: cancelFunc,
95-
closed: make(chan struct{}),
96-
envVars: options.EnvironmentVariables,
97-
coordinatorDialer: options.CoordinatorDialer,
98-
fetchMetadata: options.FetchMetadata,
99-
stats: &Stats{},
100-
statsReporter: options.StatsReporter,
78+
reconnectingPTYTimeout: options.ReconnectingPTYTimeout,
79+
logger: options.Logger,
80+
closeCancel: cancelFunc,
81+
closed: make(chan struct{}),
82+
envVars: options.EnvironmentVariables,
83+
coordinatorDialer: options.CoordinatorDialer,
84+
fetchMetadata: options.FetchMetadata,
85+
stats: &Stats{},
86+
statsReporter: options.StatsReporter,
87+
workspaceAgentApps: options.WorkspaceAgentApps,
88+
postWorkspaceAgentAppHealth: options.PostWorkspaceAgentAppHealth,
10189
}
10290
server.init(ctx)
10391
return server
@@ -120,14 +108,16 @@ type agent struct {
120108
fetchMetadata FetchMetadata
121109
sshServer *ssh.Server
122110

123-
network *tailnet.Conn
124-
coordinatorDialer CoordinatorDialer
125-
stats *Stats
126-
statsReporter StatsReporter
111+
network *tailnet.Conn
112+
coordinatorDialer CoordinatorDialer
113+
stats *Stats
114+
statsReporter StatsReporter
115+
workspaceAgentApps WorkspaceAgentApps
116+
postWorkspaceAgentAppHealth PostWorkspaceAgentAppHealth
127117
}
128118

129119
func (a *agent) run(ctx context.Context) {
130-
var metadata Metadata
120+
var metadata codersdk.WorkspaceAgentMetadata
131121
var err error
132122
// An exponential back-off occurs when the connection is failing to dial.
133123
// This is to prevent server spam in case of a coderd outage.
@@ -168,6 +158,10 @@ func (a *agent) run(ctx context.Context) {
168158
if metadata.DERPMap != nil {
169159
go a.runTailnet(ctx, metadata.DERPMap)
170160
}
161+
162+
if a.workspaceAgentApps != nil && a.postWorkspaceAgentAppHealth != nil {
163+
go NewWorkspaceAppHealthReporter(a.logger, a.workspaceAgentApps, a.postWorkspaceAgentAppHealth)(ctx)
164+
}
171165
}
172166

173167
func (a *agent) runTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) {
@@ -182,7 +176,7 @@ func (a *agent) runTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) {
182176
}
183177
var err error
184178
a.network, err = tailnet.NewConn(&tailnet.Options{
185-
Addresses: []netip.Prefix{netip.PrefixFrom(tailnetIP, 128)},
179+
Addresses: []netip.Prefix{netip.PrefixFrom(codersdk.TailnetIP, 128)},
186180
DERPMap: derpMap,
187181
Logger: a.logger.Named("tailnet"),
188182
})
@@ -199,7 +193,7 @@ func (a *agent) runTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) {
199193
})
200194
go a.runCoordinator(ctx)
201195

202-
sshListener, err := a.network.Listen("tcp", ":"+strconv.Itoa(tailnetSSHPort))
196+
sshListener, err := a.network.Listen("tcp", ":"+strconv.Itoa(codersdk.TailnetSSHPort))
203197
if err != nil {
204198
a.logger.Critical(ctx, "listen for ssh", slog.Error(err))
205199
return
@@ -213,7 +207,8 @@ func (a *agent) runTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) {
213207
go a.sshServer.HandleConn(a.stats.wrapConn(conn))
214208
}
215209
}()
216-
reconnectingPTYListener, err := a.network.Listen("tcp", ":"+strconv.Itoa(tailnetReconnectingPTYPort))
210+
211+
reconnectingPTYListener, err := a.network.Listen("tcp", ":"+strconv.Itoa(codersdk.TailnetReconnectingPTYPort))
217212
if err != nil {
218213
a.logger.Critical(ctx, "listen for reconnecting pty", slog.Error(err))
219214
return
@@ -239,15 +234,16 @@ func (a *agent) runTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) {
239234
if err != nil {
240235
continue
241236
}
242-
var msg reconnectingPTYInit
237+
var msg codersdk.ReconnectingPTYInit
243238
err = json.Unmarshal(data, &msg)
244239
if err != nil {
245240
continue
246241
}
247242
go a.handleReconnectingPTY(ctx, msg, conn)
248243
}
249244
}()
250-
speedtestListener, err := a.network.Listen("tcp", ":"+strconv.Itoa(tailnetSpeedtestPort))
245+
246+
speedtestListener, err := a.network.Listen("tcp", ":"+strconv.Itoa(codersdk.TailnetSpeedtestPort))
251247
if err != nil {
252248
a.logger.Critical(ctx, "listen for speedtest", slog.Error(err))
253249
return
@@ -268,6 +264,31 @@ func (a *agent) runTailnet(ctx context.Context, derpMap *tailcfg.DERPMap) {
268264
}()
269265
}
270266
}()
267+
268+
statisticsListener, err := a.network.Listen("tcp", ":"+strconv.Itoa(codersdk.TailnetStatisticsPort))
269+
if err != nil {
270+
a.logger.Critical(ctx, "listen for statistics", slog.Error(err))
271+
return
272+
}
273+
go func() {
274+
defer statisticsListener.Close()
275+
server := &http.Server{
276+
Handler: a.statisticsHandler(),
277+
ReadTimeout: 20 * time.Second,
278+
ReadHeaderTimeout: 20 * time.Second,
279+
WriteTimeout: 20 * time.Second,
280+
ErrorLog: slog.Stdlib(ctx, a.logger.Named("statistics_http_server"), slog.LevelInfo),
281+
}
282+
go func() {
283+
<-ctx.Done()
284+
_ = server.Close()
285+
}()
286+
287+
err = server.Serve(statisticsListener)
288+
if err != nil && !xerrors.Is(err, http.ErrServerClosed) && !strings.Contains(err.Error(), "use of closed network connection") {
289+
a.logger.Critical(ctx, "serve statistics HTTP server", slog.Error(err))
290+
}
291+
}()
271292
}
272293

273294
// runCoordinator listens for nodes and updates the self-node as it changes.
@@ -443,7 +464,7 @@ func (a *agent) init(ctx context.Context) {
443464

444465
go a.run(ctx)
445466
if a.statsReporter != nil {
446-
cl, err := a.statsReporter(ctx, a.logger, func() *Stats {
467+
cl, err := a.statsReporter(ctx, a.logger, func() *codersdk.AgentStats {
447468
return a.stats.Copy()
448469
})
449470
if err != nil {
@@ -478,7 +499,7 @@ func (a *agent) createCommand(ctx context.Context, rawCommand string, env []stri
478499
if rawMetadata == nil {
479500
return nil, xerrors.Errorf("no metadata was provided: %w", err)
480501
}
481-
metadata, valid := rawMetadata.(Metadata)
502+
metadata, valid := rawMetadata.(codersdk.WorkspaceAgentMetadata)
482503
if !valid {
483504
return nil, xerrors.Errorf("metadata is the wrong type: %T", metadata)
484505
}
@@ -634,7 +655,7 @@ func (a *agent) handleSSHSession(session ssh.Session) (retErr error) {
634655
return cmd.Wait()
635656
}
636657

637-
func (a *agent) handleReconnectingPTY(ctx context.Context, msg reconnectingPTYInit, conn net.Conn) {
658+
func (a *agent) handleReconnectingPTY(ctx context.Context, msg codersdk.ReconnectingPTYInit, conn net.Conn) {
638659
defer conn.Close()
639660

640661
var rpty *reconnectingPTY
@@ -775,7 +796,7 @@ func (a *agent) handleReconnectingPTY(ctx context.Context, msg reconnectingPTYIn
775796
rpty.activeConnsMutex.Unlock()
776797
}()
777798
decoder := json.NewDecoder(conn)
778-
var req ReconnectingPTYRequest
799+
var req codersdk.ReconnectingPTYRequest
779800
for {
780801
err = decoder.Decode(&req)
781802
if xerrors.Is(err, io.EOF) {

0 commit comments

Comments
 (0)