8000 Merge branch 'main' into danielle/container-logs-space · coder/coder@f368cc1 · GitHub
[go: up one dir, main page]

Skip to content

Commit f368cc1

Browse files
Merge branch 'main' into danielle/container-logs-space
2 parents d3d1b77 + 5ae320e commit f368cc1

File tree

23 files changed

+260
-93
lines changed

23 files changed

+260
-93
lines changed

.devcontainer/devcontainer.json

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"name": "Development environments on your infrastructure",
33
"image": "codercom/oss-dogfood:latest",
4-
54
"features": {
65
// See all possible options here https://github.com/devcontainers/features/tree/main/src/docker-in-docker
76
"ghcr.io/devcontainers/features/docker-in-docker:2": {
@@ -10,13 +9,52 @@
109
"ghcr.io/coder/devcontainer-features/code-server:1": {
1110
"auth": "none",
1211
"port": 13337
13-
}
12+
},
13+
"./filebrowser": {}
1414
},
1515
// SYS_PTRACE to enable go debugging
16-
"runArgs": ["--cap-add=SYS_PTRACE"],
16+
"runArgs": [
17+
"--cap-add=SYS_PTRACE"
18+
],
1719
"customizations": {
1820
"vscode": {
19-
"extensions": ["biomejs.biome"]
21+
"extensions": [
22+
"biomejs.biome"
23+
]
24+
},
25+
"coder": {
26+
"apps": [
27+
{
28+
"slug": "cursor",
29+
"displayName": "Cursor Desktop",
30+
"url": "cursor://coder.coder-remote/openDevContainer?owner=${localEnv:CODER_WORKSPACE_OWNER_NAME}&workspace=${localEnv:CODER_WORKSPACE_NAME}&agent=${localEnv:CODER_WORKSPACE_PARENT_AGENT_NAME}&url=${localEnv:CODER_URL}&token=$SESSION_TOKEN&devContainerName=${localEnv:CONTAINER_ID}&devContainerFolder=${containerWorkspaceFolder}",
31+
"external": true,
32+
"icon": "/icon/cursor.svg",
33+
"order": 1
34+
},
35+
{
36+
"slug": "windsurf",
< F438 /td>37+
"displayName": "Windsurf Editor",
38+
"url": "windsurf://coder.coder-remote/openDevContainer?owner=${localEnv:CODER_WORKSPACE_OWNER_NAME}&workspace=${localEnv:CODER_WORKSPACE_NAME}&agent=${localEnv:CODER_WORKSPACE_PARENT_AGENT_NAME}&url=${localEnv:CODER_URL}&token=$SESSION_TOKEN&devContainerName=${localEnv:CONTAINER_ID}&devContainerFolder=${containerWorkspaceFolder}",
39+
"external": true,
40+
"icon": "/icon/windsurf.svg",
41+
"order": 4
42+
},
43+
{
44+
"slug": "zed",
45+
"displayName": "Zed Editor",
46+
"url": "zed://ssh/${localEnv:CODER_WORKSPACE_AGENT_NAME}.${localEnv:CODER_WORKSPACE_NAME}.${localEnv:CODER_WORKSPACE_OWNER_NAME}.coder/${containerWorkspaceFolder}",
47+
"external": true,
48+
"icon": "/icon/zed.svg",
49+
"order": 5
50+
}
51+
]
2052
}
21-
}
53+
},
54+
"mounts": [
55+
// Mount the entire home because conditional mounts are not supported.
56+
// See: https://github.com/devcontainers/spec/issues/132
57+
"source=${localEnv:HOME},target=/mnt/home/coder,type=bind,readonly"
58+
],
59+
"postCreateCommand": "./.devcontainer/postCreateCommand.sh"
2260
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"id": "filebrowser",
3+
"version": "0.0.1",
4+
"name": "File Browser",
5+
"description": "A web-based file browser for your development container",
6+
"options": {
7+
"port": {
8+
"type": "string",
9+
"default": "13339",
10+
"description": "The port to run filebrowser on"
11+
},
12+
// "folder": {
13+
// "type": "string",
14+
// "default": "${containerWorkspaceFolder}",
15+
// "description": "The root directory for filebrowser to serve"
16+
// },
17+
"auth": {
18+
"type": "string",
19+
"enum": [
20+
"none",
21+
"password"
22+
],
23+
"default": "none",
24+
"description": "Authentication method (none or password)"
25+
}
26+
},
27+
"entrypoint": "/usr/local/bin/filebrowser-entrypoint",
28+
"dependsOn": {
29+
"ghcr.io/devcontainers/features/common-utils:2": {}
30+
},
31+
"customizations": {
32+
"coder": {
33+
"apps": [
34+
{
35+
"slug": "filebrowser",
36+
"displayName": "File Browser",
37+
"url": "http://localhost:${localEnv:FEATURE_FILEBROWSER_OPTION_PORT:13339}",
38+
"icon": "/icon/filebrowser.svg",
39+
"order": 3,
40+
"subdomain": true,
41+
"healthcheck": {
42+
"url": "http://localhost:${localEnv:FEATURE_FILEBROWSER_OPTION_PORT:13339}/health",
43+
"interval": 5,
44+
"threshold": 6
45+
}
46+
}
47+
]
48+
}
49+
}
50+
}

.devcontainer/filebrowser/install.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
BOLD='\033[0;1m'
6+
7+
printf "%sInstalling filebrowser\n\n" "${BOLD}"
8+
9+
# Check if filebrowser is installed.
10+
if ! command -v filebrowser &>/dev/null; then
11+
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
12+
fi
13+
14+
printf "🥳 Installation complete!\n\n"
15+
16+
# Create run script.
17+
cat >/usr/local/bin/filebrowser-entrypoint <<EOF
18+
#!/bin/bash
19+
20+
printf "🛠️ Configuring filebrowser\n\n"
21+
22+
AUTH="${AUTH}"
23+
PORT="${PORT}"
24+
FOLDER="$(pwd)"
25+
LOG_PATH=/tmp/filebrowser.log
26+
export FB_DATABASE="/tmp/filebrowser.db"
27+
28+
# Check if filebrowser db exists.
29+
if [[ ! -f "\${FB_DATABASE}" ]]; then
30+
filebrowser config init
31+
if [[ "\$AUTH" == "password" ]]; then
32+
filebrowser users add admin admin --perm.admin=true --viewMode=mosaic
33+
fi
34+
fi
35+
36+
# Configure filebrowser.
37+
if [[ "\$AUTH" == "none" ]]; then
38+
filebrowser config set --port="\${PORT}" --auth.method=noauth --root="\${FOLDER}"
39+
else
40+
filebrowser config set --port="\${PORT}" --auth.method=json --root="\${FOLDER}"
41+
fi
42+
43+
set -euo pipefail
44+
45+
printf "👷 Starting filebrowser...\n\n"
46+
printf "📂 Serving \${FOLDER} at http://localhost:\${PORT}\n\n"
47+
48+
filebrowser >>\${LOG_PATH} 2>&1 &
49+
50+
printf "📝 Logs at \${LOG_PATH}\n\n"
51+
EOF
52+
53+
chmod +x /usr/local/bin/filebrowser-entrypoint
54+
55+
printf "✅ File Browser installed!\n\n"
56+
printf "🚀 Run 'filebrowser-entrypoint' to start the service\n\n"

.devcontainer/postCreateCommand.sh

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/bin/sh
2+
3+
install_ssh_config() {
4+
echo "🔑 Installing SSH configuration..."
5+
rsync -a /mnt/home/coder/.ssh/ ~/.ssh/
6+
chmod 0700 ~/.ssh
7+
}
8+
9+
install_git_config() {
10+
echo "📂 Installing Git configuration..."
11+
if [ -f /mnt/home/coder/git/config ]; then
12+
rsync -a /mnt/home/coder/git/ ~/.config/git/
13+
elif [ -d /mnt/home/coder/.gitconfig ]; then
14+
rsync -a /mnt/home/coder/.gitconfig ~/.gitconfig
15+
else
16+
echo "⚠️ Git configuration directory not found."
17+
fi
18+
}
19+
20+
install_dotfiles() {
21+
if [ ! -d /mnt/home/coder/.config/coderv2/dotfiles ]; then
22+
echo "⚠️ Dotfiles directory not found."
23+
return
24+
fi
25+
26+
cd /mnt/home/coder/.config/coderv2/dotfiles || return
27+
for script in install.sh install bootstrap.sh bootstrap script/bootstrap setup.sh setup script/setup; do
28+
if [ -x $script ]; then
29+
echo "📦 Installing dotfiles..."
30+
./$script || {
31+
echo "❌ Error running $script. Please check the script for issues."
32+
return
33+
}
34+
echo "✅ Dotfiles installed successfully."
35+
return
36+
fi
37+
done
38+
echo "⚠️ No install script found in dotfiles directory."
39+
}
40+
41+
personalize() {
42+
# Allow script to continue as Coder dogfood utilizes a hack to
43+
# synchronize startup script execution.
44+
touch /tmp/.coder-startup-script.done
45+
46+
if [ -x /mnt/home/coder/personalize ]; then
47+
echo "🎨 Personalizing environment..."
48+
/mnt/home/coder/personalize
49+
fi
50+
}
51+
52+
install_ssh_config
53+
install_dotfiles
54+
personalize

agent/agentcontainers/api.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,6 +1442,11 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
14421442
return xerrors.Errorf("set agent binary executable: %w", err)
14431443
}
14441444

1445+
// Make sure the agent binary is executable so we can run it.
1446+
if _, err := api.ccli.ExecAs(ctx, container.ID, "root", "/bin/sh", "-c", fmt.Sprintf("chown $(id -u):$(id -g) %s", coderPathInsideContainer)); err != nil {
1447+
return xerrors.Errorf("set agent binary ownership: %w", err)
1448+
}
1449+
14451450
// Attempt to add CAP_NET_ADMIN to the binary to improve network
14461451
// performance (optional, allow to fail). See `bootstrap_linux.sh`.
14471452
// TODO(mafredri): Disable for now until we can figure out why this

agent/agentcontainers/api_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,6 +1392,7 @@ func TestAPI(t *testing.T) {
13921392
mCCLI.EXPECT().ExecAs(gomock.Any(), "test-container-id", "root", "mkdir", "-p", "/.coder-agent").Return(nil, nil),
13931393
mCCLI.EXPECT().Copy(gomock.Any(), "test-container-id", coderBin, "/.coder-agent/coder").Return(nil),
13941394
mCCLI.EXPECT().ExecAs(gomock.Any(), "test-container-id", "root", "chmod", "0755", "/.coder-agent", "/.coder-agent/coder").Return(nil, nil),
1395+
mCCLI.EXPECT().ExecAs(gomock.Any(), "test-container-id", "root", "/bin/sh", "-c", "chown $(id -u):$(id -g) /.coder-agent/coder").Return(nil, nil),
13951396
)
13961397

13971398
mClock.Set(time.Now()).MustWait(ctx)
@@ -1480,6 +1481,7 @@ func TestAPI(t *testing.T) {
14801481
mCCLI.EXPECT().ExecAs(gomock.Any(), "test-container-id", "root", "mkdir", "-p", "/.coder-agent").Return(nil, nil),
14811482
mCCLI.EXPECT().Copy(gomock.Any(), "test-container-id", coderBin, "/.coder-agent/coder").Return(nil),
14821483
mCCLI.EXPECT().ExecAs(gomock.Any(), "test-container-id", "root", "chmod", "0755", "/.coder-agent", "/.coder-agent/coder").Return(nil, nil),
1484+
mCCLI.EXPECT().ExecAs(gomock.Any(), "test-container-id", "root", "/bin/sh", "-c", "chown $(id -u):$(id -g) /.coder-agent/coder").Return(nil, nil),
14831485
)
14841486

14851487
// Verify that the agent has started.
@@ -1540,6 +1542,7 @@ func TestAPI(t *testing.T) {
15401542
mCCLI.EXPECT().ExecAs(gomock.Any(), "new-test-container-id", "root", "mkdir", "-p", "/.coder-agent").Return(nil, nil),
15411543
mCCLI.EXPECT().Copy(gomock.Any(), "new-test-container-id", coderBin, "/.coder-agent/coder").Return(nil),
15421544
mCCLI.EXPECT().ExecAs(gomock.Any(), "new-test-container-id", "root", "chmod", "0755", "/.coder-agent", "/.coder-agent/coder").Return(nil, nil),
1545+
mCCLI.EXPECT().ExecAs(gomock.Any(), "new-test-container-id", "root", "/bin/sh", "-c", "chown $(id -u):$(id -g) /.coder-agent/coder").Return(nil, nil),
15431546
)
15441547

15451548
fakeDCCLI.readConfig.MergedConfiguration.Customizations.Coder = []agentcontainers.CoderCustomization{
@@ -1941,6 +1944,7 @@ func TestAPI(t *testing.T) {
19411944
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "mkdir", "-p", "/.coder-agent").Return(nil, nil),
19421945
mCCLI.EXPECT().Copy(gomock.Any(), testContainer.ID, coderBin, "/.coder-agent/coder").Return(nil),
19431946
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "chmod", "0755", "/.coder-agent", "/.coder-agent/coder").Return(nil, nil),
1947+
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "/bin/sh", "-c", "chown $(id -u):$(id -g) /.coder-agent/coder").Return(nil, nil),
19441948
)
19451949

19461950
mClock.Set(time.Now()).MustWait(ctx)
@@ -2034,6 +2038,7 @@ func TestAPI(t *testing.T) {
20342038
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "mkdir", "-p", "/.coder-agent").Return(nil, nil),
20352039
mCCLI.EXPECT().Copy(gomock.Any(), testContainer.ID, coderBin, "/.coder-agent/coder").Return(nil),
20362040
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "chmod", "0755", "/.coder-agent", "/.coder-agent/coder").Return(nil, nil),
2041+
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "/bin/sh", "-c", "chown $(id -u):$(id -g) /.coder-agent/coder").Return(nil, nil),
20372042
)
20382043

20392044
mClock.Set(time.Now()).MustWait(ctx)
@@ -2138,6 +2143,7 @@ func TestAPI(t *testing.T) {
21382143
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "mkdir", "-p", "/.coder-agent").Return(nil, nil),
21392144
mCCLI.EXPECT().Copy(gomock.Any(), testContainer.ID, coderBin, "/.coder-agent/coder").Return(nil),
21402145
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "chmod", "0755", "/.coder-agent", "/.coder-agent/coder").Return(nil, nil),
2146+
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "/bin/sh", "-c", "chown $(id -u):$(id -g) /.coder-agent/coder").Return(nil, nil),
21412147
)
21422148

21432149
mClock.Set(time.Now()).MustWait(ctx)

cli/testdata/coder_server_--help.golden

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,12 @@ workspaces stopping during the day due to template scheduling.
677677
must be *. Only one hour and minute can be specified (ranges or comma
678678
separated values are not supported).
679679

680+
WORKSPACE PREBUILDS OPTIONS:
681+
Configure how workspace prebuilds behave.
682+
683+
--workspace-prebuilds-reconciliation-interval duration, $CODER_WORKSPACE_PREBUILDS_RECONCILIATION_INTERVAL (default: 15s)
684+
How often to reconcile workspace prebuilds state.
685+
680686
⚠️ DANGEROUS OPTIONS:
681687
--dangerous-allow-path-app-sharing bool, $CODER_DANGEROUS_ALLOW_PATH_APP_SHARING
682688
Allow workspace apps that are not served from subdomains to be shared.

coderd/apidoc/docs.go

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

coderd/apidoc/swagger.json

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

coderd/database/dbauthz/dbauthz_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5059,8 +5059,7 @@ func (s *MethodTestSuite) TestPrebuilds() {
50595059
}))
50605060
s.Run("GetPrebuildMetrics", s.Subtest(func(_ database.Store, check *expects) {
50615061
check.Args().
5062-
Asserts(rbac.ResourceWorkspace.All(), policy.ActionRead).
5063-
ErrorsWithInMemDB(dbmem.ErrUnimplemented)
5062+
Asserts(rbac.ResourceWorkspace.All(), policy.ActionRead)
50645063
}))
50655064
s.Run("CountInProgressPrebuilds", s.Subtest(func(_ database.Store, check *expects) {
50665065
check.Args().

coderd/database/dbmem/dbmem.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4270,7 +4270,7 @@ func (q *FakeQuerier) GetParameterSchemasByJobID(_ context.Context, jobID uuid.U
42704270
}
42714271

42724272
func (*FakeQuerier) GetPrebuildMetrics(_ context.Context) ([]database.GetPrebuildMetricsRow, error) {
4273-
return nil, ErrUnimplemented
4273+
return make([]database.GetPrebuildMetricsRow, 0), nil
42744274
}
42754275

42764276
func (q *FakeQuerier) GetPresetByID(ctx context.Context, presetID uuid.UUID) (database.GetPresetByIDRow, error) {

coderd/telemetry/telemetry.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -687,10 +687,6 @@ func (r *remoteReporter) createSnapshot() (*Snapshot, error) {
687687
return nil
688688
})
689689
eg.Go(func() error {
690-
if !r.options.Experiments.Enabled(codersdk.ExperimentWorkspacePrebuilds) {
691-
return nil
692-
}
693-
694690
metrics, err := r.options.Database.GetPrebuildMetrics(ctx)
695691
if err != nil {
696692
return xerrors.Errorf("get prebuild metrics: %w", err)

0 commit comments

Comments
 (0)
0