mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
chore: remove the migrated dogfood template sources (#29469)
Deletes the dogfood template sources that were migrated to the infrastructure repository, leaving only the image build inputs in this repo. Stacked on #29400 (which removes the `deploy_template` job and `dogfood/main.tf`); depends on coder/dogfood#551 being applied first. #29468 stacks on top of this branch. ## Changes - Delete `dogfood/coder/main.tf`, `dogfood/coder-envbuilder/`, `dogfood/vscode-coder/main.tf`, and the template READMEs and guide - Delete `dogfood/coder/devcontainer.json`: its only reader was the retired `coder-envbuilder` template, and it referenced a `Dockerfile` removed in #24267 - Add `dogfood/README.md` documenting what remains here and where template changes go - Drop the now-empty dependabot entries (`/dogfood/coder-envbuilder` docker, `dogfood/*/` terraform) Kept: `dogfood/coder/ubuntu-22.04/`, `dogfood/coder/ubuntu-26.04/`, `dogfood/coder/Makefile`, and `dogfood/vscode-coder/Dockerfile`. Image builds, tags, and `scripts/dogfood/*` are unchanged; the contract with the templates is the published Docker tag. Checks: `actionlint`, `shellcheck`, `compute-base-sha.sh`/`compute-final-sha.sh` still resolve, docs lint and `make lint/emdash` clean. --- Generated by Coder Agents on behalf of @jdomeracki-coder. --------- Co-authored-by: McKayla はな <kayla@tree.camp>
This commit is contained in:
co-authored by
McKayla はな
parent
0ea777a341
commit
95a3f01ecc
@@ -40,7 +40,6 @@ updates:
|
||||
- package-ecosystem: "docker"
|
||||
directories:
|
||||
- "/dogfood/coder"
|
||||
- "/dogfood/coder-envbuilder"
|
||||
- "/scripts"
|
||||
- "/examples/templates/docker/build"
|
||||
- "/examples/parameters/build"
|
||||
@@ -101,7 +100,6 @@ updates:
|
||||
|
||||
- package-ecosystem: "terraform"
|
||||
directories:
|
||||
- "dogfood/*/"
|
||||
- "examples/templates/*/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
@@ -77,7 +77,7 @@ The Coder backend is organized into multiple packages and directories, each with
|
||||
* [queries](../../../coderd/database/queries): contains SQL files with queries, `sqlc` compiles them to [Go functions](../../../coderd/database/queries.sql.go)
|
||||
* [sqlc.yaml](../../../coderd/database/sqlc.yaml): defines mappings between SQL types and custom Go structures
|
||||
* [codersdk](../../../codersdk): user-facing API entities used by CLI and site to communicate with `coderd` endpoints
|
||||
* [dogfood](../../../dogfood): Terraform definition of the dogfood cluster deployment
|
||||
* [dogfood](../../../dogfood): build inputs for the images used by Coder's dogfood workspaces. The workspace templates that consume these images live in an internal Coder infrastructure repository.
|
||||
* [enterprise](../../../enterprise): enterprise-only features, notice similar file structure to repository root (`audit`, `cli`, `cmd`, `coderd`, etc.)
|
||||
* [coderd](../../../enterprise/coderd)
|
||||
* [prebuilds](../../../enterprise/coderd/prebuilds): core logic of prebuilt workspaces - reconciliation loop
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Dogfood workspace images
|
||||
|
||||
This directory holds the build inputs for the images used by Coder's own
|
||||
dogfood workspaces:
|
||||
|
||||
| Path | Image |
|
||||
| ------------------------- | ------------------------------------------ |
|
||||
| `coder/ubuntu-26.04/` | `codercom/oss-dogfood:26.04`, `:latest` |
|
||||
| `vscode-coder/Dockerfile` | `codercom/oss-dogfood-vscode-coder:latest` |
|
||||
|
||||
`.github/workflows/dogfood.yaml` builds each base image, layers the tools from
|
||||
the repository's `mise.toml` and `mise.lock` with `mise oci build`, validates the
|
||||
result by running `make gen`, `fmt`, `lint`, and a Linux build inside it, and
|
||||
pushes to Docker Hub on `main`. Use `coder/Makefile` to build locally.
|
||||
|
||||
The workspace templates that consume these images live in an internal Coder
|
||||
infrastructure repository, not here. The only contract between the two is the
|
||||
published image tag, which the templates resolve to a digest. Template changes
|
||||
therefore go to the internal infrastructure repository; image changes go here.
|
||||
@@ -1,15 +0,0 @@
|
||||
# envbuilder dogfood template
|
||||
|
||||
This template uses the same image as the [dogfood](../dogfood) template, but
|
||||
builds it on-demand using the latest _preview_ version of [envbuilder](https://github.com/coder/envbuilder).
|
||||
|
||||
In theory, it should work with any Git repository containing a `devcontainer.json`.
|
||||
The Git repository specified by `devcontainer_repo` is cloned into `/workspaces` upon startup and the container is built from the devcontainer located under the path specified by `devcontainer_dir`.
|
||||
The `region` parameters are the same as for the [dogfood](../dogfood) template.
|
||||
|
||||
The `/workspaces` directory is persisted as a Docker volume, so any changes you make to the dogfood Dockerfile or devcontainer.json will be applied upon restarting your workspace.
|
||||
|
||||
## Personalization
|
||||
|
||||
The startup script runs your `~/personalize` file if it exists.
|
||||
You also have a persistent home directory under `/home/coder`.
|
||||
@@ -1,443 +0,0 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~> 4.0"
|
||||
}
|
||||
envbuilder = {
|
||||
source = "coder/envbuilder"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
// These are cluster service addresses mapped to Tailscale nodes.
|
||||
// Ask #dogfood-admins for help.
|
||||
// NOTE: keep these up to date with those in ../coder/main.tf!
|
||||
docker_host = {
|
||||
"" = "tcp://rubinsky-pit-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
"us-pittsburgh" = "tcp://rubinsky-pit-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
// For legacy reasons, this host is labelled `eu-helsinki` but it's
|
||||
// actually in Germany now.
|
||||
"eu-helsinki" = "tcp://katerose-fsn-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
"ap-sydney" = "tcp://wolfgang-syd-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
"za-jnb" = "tcp://greenhill-jnb-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
}
|
||||
|
||||
envbuilder_repo = "ghcr.io/coder/envbuilder-preview"
|
||||
container_name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
// Envbuilder clones repos to /workspaces by default.
|
||||
repo_dir = "/workspaces/coder"
|
||||
}
|
||||
|
||||
data "coder_parameter" "devcontainer_repo" {
|
||||
type = "string"
|
||||
name = "Devcontainer Repository"
|
||||
default = "https://github.com/coder/coder"
|
||||
description = "Repo containing a devcontainer.json. This is only cloned once."
|
||||
mutable = false
|
||||
}
|
||||
|
||||
data "coder_parameter" "devcontainer_dir" {
|
||||
type = "string"
|
||||
name = "Devcontainer Directory"
|
||||
default = "dogfood/coder/"
|
||||
description = "Directory containing a devcontainer.json relative to the repository root"
|
||||
mutable = true
|
||||
}
|
||||
|
||||
data "coder_parameter" "region" {
|
||||
type = "string"
|
||||
name = "Region"
|
||||
icon = "/emojis/1f30e.png"
|
||||
default = "us-pittsburgh"
|
||||
option {
|
||||
icon = "/emojis/1f1fa-1f1f8.png"
|
||||
name = "Pittsburgh"
|
||||
value = "us-pittsburgh"
|
||||
}
|
||||
option {
|
||||
icon = "/emojis/1f1e9-1f1ea.png"
|
||||
name = "Falkenstein"
|
||||
// For legacy reasons, this host is labelled `eu-helsinki` but it's
|
||||
// actually in Germany now.
|
||||
value = "eu-helsinki"
|
||||
}
|
||||
option {
|
||||
icon = "/emojis/1f1e6-1f1fa.png"
|
||||
name = "Sydney"
|
||||
value = "ap-sydney"
|
||||
}
|
||||
option {
|
||||
icon = "/emojis/1f1ff-1f1e6.png"
|
||||
name = "Johannesburg"
|
||||
value = "za-jnb"
|
||||
}
|
||||
}
|
||||
|
||||
# This file is mounted as a Kubernetes secret on provisioner pods.
|
||||
# It contains the required credentials for the envbuilder cache repo.
|
||||
variable "envbuilder_cache_dockerconfigjson_path" {
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
provider "docker" {
|
||||
host = lookup(local.docker_host, data.coder_parameter.region.value)
|
||||
registry_auth {
|
||||
address = "us-central1-docker.pkg.dev"
|
||||
config_file = pathexpand(var.envbuilder_cache_dockerconfigjson_path)
|
||||
}
|
||||
}
|
||||
|
||||
provider "coder" {}
|
||||
|
||||
data "coder_external_auth" "github" {
|
||||
id = "github"
|
||||
}
|
||||
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
module "slackme" {
|
||||
source = "dev.registry.coder.com/coder/slackme/coder"
|
||||
version = "1.0.33"
|
||||
agent_id = coder_agent.dev.id
|
||||
auth_provider_id = "slack"
|
||||
}
|
||||
|
||||
module "dotfiles" {
|
||||
source = "dev.registry.coder.com/coder/dotfiles/coder"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.dev.id
|
||||
}
|
||||
|
||||
module "personalize" {
|
||||
source = "dev.registry.coder.com/coder/personalize/coder"
|
||||
version = "1.0.33"
|
||||
agent_id = coder_agent.dev.id
|
||||
}
|
||||
|
||||
module "code-server" {
|
||||
source = "dev.registry.coder.com/coder/code-server/coder"
|
||||
version = "1.5.2"
|
||||
agent_id = coder_agent.dev.id
|
||||
folder = local.repo_dir
|
||||
auto_install_extensions = true
|
||||
}
|
||||
|
||||
module "jetbrains" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "dev.registry.coder.com/coder/jetbrains/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.dev.id
|
||||
agent_name = "dev"
|
||||
folder = local.repo_dir
|
||||
}
|
||||
|
||||
module "filebrowser" {
|
||||
source = "dev.registry.coder.com/coder/filebrowser/coder"
|
||||
version = "1.1.6"
|
||||
agent_id = coder_agent.dev.id
|
||||
}
|
||||
|
||||
module "coder-login" {
|
||||
source = "dev.registry.coder.com/coder/coder-login/coder"
|
||||
version = "1.1.1"
|
||||
agent_id = coder_agent.dev.id
|
||||
}
|
||||
|
||||
resource "coder_agent" "dev" {
|
||||
arch = "amd64"
|
||||
os = "linux"
|
||||
dir = local.repo_dir
|
||||
env = {
|
||||
OIDC_TOKEN : data.coder_workspace_owner.me.oidc_access_token,
|
||||
}
|
||||
startup_script_behavior = "blocking"
|
||||
|
||||
# The following metadata blocks are optional. They are used to display
|
||||
# information about your workspace in the dashboard. You can remove them
|
||||
# if you don't want to display any information.
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "cpu_usage"
|
||||
order = 0
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "ram_usage"
|
||||
order = 1
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage (Host)"
|
||||
key = "cpu_usage_host"
|
||||
order = 2
|
||||
script = "coder stat cpu --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage (Host)"
|
||||
key = "ram_usage_host"
|
||||
order = 3
|
||||
script = "coder stat mem --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Swap Usage (Host)"
|
||||
key = "swap_usage_host"
|
||||
order = 4
|
||||
script = <<EOT
|
||||
#!/bin/bash
|
||||
echo "$(free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }') GiB"
|
||||
EOT
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Load Average (Host)"
|
||||
key = "load_host"
|
||||
order = 5
|
||||
# get load avg scaled by number of cores
|
||||
script = <<EOT
|
||||
#!/bin/bash
|
||||
echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }'
|
||||
EOT
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Disk Usage (Host)"
|
||||
key = "disk_host"
|
||||
order = 6
|
||||
script = "coder stat disk --path /"
|
||||
interval = 600
|
||||
timeout = 10
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Word of the Day"
|
||||
key = "word"
|
||||
order = 7
|
||||
script = <<EOT
|
||||
#!/bin/bash
|
||||
curl -o - --silent https://www.merriam-webster.com/word-of-the-day 2>&1 | awk ' $0 ~ "Word of the Day: [A-z]+" { print $5; exit }'
|
||||
EOT
|
||||
interval = 86400
|
||||
timeout = 5
|
||||
}
|
||||
|
||||
startup_script = <<-EOT
|
||||
set -eux -o pipefail
|
||||
|
||||
# Allow synchronization between scripts.
|
||||
trap 'touch /tmp/.coder-startup-script.done' EXIT
|
||||
|
||||
# BUG: Kaniko does not symlink /run => /var/run properly, resulting in
|
||||
# /var/run/ owned by root:root
|
||||
# WORKAROUND: symlink it manually
|
||||
sudo ln -s /run /var/run
|
||||
# Start Docker service
|
||||
sudo service docker start
|
||||
|
||||
# Chown /var/run/docker.sock as even though we are a member of the Docker group
|
||||
# it did not exist at the start of the workspace. This can be worked around with
|
||||
# `newgrp docker` but this is annoying to have to do manually.
|
||||
for attempt in $(seq 1 10); do
|
||||
if sudo docker info > /dev/null; then break; fi
|
||||
sleep 1
|
||||
done
|
||||
sudo chmod a+rw /var/run/docker.sock
|
||||
|
||||
# Install playwright dependencies
|
||||
# We want to use the playwright version from site/package.json
|
||||
# Check if the directory exists At workspace creation as the coder_script runs in parallel so clone might not exist yet.
|
||||
while ! [[ -f "${local.repo_dir}/site/package.json" ]]; do
|
||||
sleep 1
|
||||
done
|
||||
cd "${local.repo_dir}/site" && pnpm install && pnpm playwright:install
|
||||
EOT
|
||||
}
|
||||
|
||||
resource "docker_volume" "home_volume" {
|
||||
name = "coder-${data.coder_workspace.me.id}-home"
|
||||
# Protect the volume from being deleted due to changes in attributes.
|
||||
lifecycle {
|
||||
ignore_changes = all
|
||||
}
|
||||
# Add labels in Docker to keep track of orphan resources.
|
||||
labels {
|
||||
label = "coder.owner"
|
||||
value = data.coder_workspace_owner.me.name
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner_id"
|
||||
value = data.coder_workspace_owner.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_id"
|
||||
value = data.coder_workspace.me.id
|
||||
}
|
||||
# This field becomes outdated if the workspace is renamed but can
|
||||
# be useful for debugging or cleaning out dangling volumes.
|
||||
labels {
|
||||
label = "coder.workspace_name_at_creation"
|
||||
value = data.coder_workspace.me.name
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_volume" "workspaces" {
|
||||
name = "coder-${data.coder_workspace.me.id}"
|
||||
# Protect the volume from being deleted due to changes in attributes.
|
||||
lifecycle {
|
||||
ignore_changes = all
|
||||
}
|
||||
# Add labels in Docker to keep track of orphan resources.
|
||||
labels {
|
||||
label = "coder.owner"
|
||||
value = data.coder_workspace_owner.me.name
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner_id"
|
||||
value = data.coder_workspace_owner.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_id"
|
||||
value = data.coder_workspace.me.id
|
||||
}
|
||||
# This field becomes outdated if the workspace is renamed but can
|
||||
# be useful for debugging or cleaning out dangling volumes.
|
||||
labels {
|
||||
label = "coder.workspace_name_at_creation"
|
||||
value = data.coder_workspace.me.name
|
||||
}
|
||||
}
|
||||
|
||||
# This file is mounted as a Kubernetes secret on provisioner pods.
|
||||
# It contains the required credentials for the envbuilder cache repo.
|
||||
data "local_sensitive_file" "envbuilder_cache_dockerconfigjson" {
|
||||
filename = var.envbuilder_cache_dockerconfigjson_path
|
||||
}
|
||||
|
||||
data "docker_registry_image" "envbuilder" {
|
||||
name = "${local.envbuilder_repo}:latest"
|
||||
}
|
||||
|
||||
resource "docker_image" "envbuilder" {
|
||||
name = "${local.envbuilder_repo}@${data.docker_registry_image.envbuilder.sha256_digest}"
|
||||
pull_triggers = [data.docker_registry_image.envbuilder.sha256_digest]
|
||||
keep_locally = true
|
||||
}
|
||||
|
||||
locals {
|
||||
cache_repo = "us-central1-docker.pkg.dev/coder-dogfood-v2/envbuilder-cache/coder-dogfood"
|
||||
envbuilder_env = {
|
||||
"CODER_AGENT_TOKEN" : coder_agent.dev.token,
|
||||
"CODER_AGENT_URL" : data.coder_workspace.me.access_url,
|
||||
"ENVBUILDER_GIT_USERNAME" : data.coder_external_auth.github.access_token,
|
||||
# "ENVBUILDER_GIT_URL" : data.coder_parameter.devcontainer_repo.value, # The provider sets this via the `git_url` property.
|
||||
"ENVBUILDER_DEVCONTAINER_DIR" : data.coder_parameter.devcontainer_dir.value,
|
||||
"ENVBUILDER_INIT_SCRIPT" : coder_agent.dev.init_script,
|
||||
"ENVBUILDER_FALLBACK_IMAGE" : "codercom/oss-dogfood:latest", # This image runs if builds fail
|
||||
"ENVBUILDER_PUSH_IMAGE" : "true", # Push the image to the remote cache
|
||||
# "ENVBUILDER_CACHE_REPO" : local.cache_repo, # The provider sets this via the `cache_repo` property.
|
||||
"ENVBUILDER_DOCKER_CONFIG_BASE64" : data.local_sensitive_file.envbuilder_cache_dockerconfigjson.content_base64,
|
||||
"USE_CAP_NET_ADMIN" : "true",
|
||||
# Set git commit details correctly
|
||||
"GIT_AUTHOR_NAME" : coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name),
|
||||
"GIT_AUTHOR_EMAIL" : data.coder_workspace_owner.me.email,
|
||||
"GIT_COMMITTER_NAME" : coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name),
|
||||
"GIT_COMMITTER_EMAIL" : data.coder_workspace_owner.me.email,
|
||||
}
|
||||
}
|
||||
|
||||
# Check for the presence of a prebuilt image in the cache repo
|
||||
# that we can use instead.
|
||||
resource "envbuilder_cached_image" "cached" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
builder_image = docker_image.envbuilder.name
|
||||
git_url = data.coder_parameter.devcontainer_repo.value
|
||||
cache_repo = local.cache_repo
|
||||
extra_env = local.envbuilder_env
|
||||
}
|
||||
|
||||
resource "docker_container" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = envbuilder_cached_image.cached.0.image
|
||||
name = local.container_name
|
||||
# Hostname makes the shell more user friendly: coder@my-workspace:~$
|
||||
hostname = data.coder_workspace.me.name
|
||||
# CPU limits are unnecessary since Docker will load balance automatically
|
||||
memory = 32768
|
||||
runtime = "sysbox-runc"
|
||||
# Use environment computed from the provider
|
||||
env = envbuilder_cached_image.cached.0.env
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
volumes {
|
||||
container_path = "/home/coder/"
|
||||
volume_name = docker_volume.home_volume.name
|
||||
read_only = false
|
||||
}
|
||||
volumes {
|
||||
container_path = local.repo_dir
|
||||
volume_name = docker_volume.workspaces.name
|
||||
read_only = false
|
||||
}
|
||||
capabilities {
|
||||
add = ["CAP_NET_ADMIN", "CAP_SYS_NICE"]
|
||||
}
|
||||
# Add labels in Docker to keep track of orphan resources.
|
||||
labels {
|
||||
label = "coder.owner"
|
||||
value = data.coder_workspace_owner.me.name
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner_id"
|
||||
value = data.coder_workspace_owner.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_id"
|
||||
value = data.coder_workspace.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_name"
|
||||
value = data.coder_workspace.me.name
|
||||
}
|
||||
}
|
||||
|
||||
resource "coder_metadata" "container_info" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
resource_id = coder_agent.dev.id
|
||||
item {
|
||||
key = "memory"
|
||||
value = docker_container.workspace[0].memory
|
||||
}
|
||||
item {
|
||||
key = "runtime"
|
||||
value = docker_container.workspace[0].runtime
|
||||
}
|
||||
item {
|
||||
key = "region"
|
||||
value = data.coder_parameter.region.option[index(data.coder_parameter.region.option.*.value, data.coder_parameter.region.value)].name
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
# dogfood template
|
||||
|
||||
Ammar is this template's admin.
|
||||
|
||||
## Personalization
|
||||
|
||||
The startup script runs your `~/personalize` file if it exists.
|
||||
|
||||
## Hosting
|
||||
|
||||
Coder dogfoods on a beefy, single Teraswitch machine.
|
||||
|
||||
- We decided to use a bare metal provider for best-in-class cost-to-performance.
|
||||
- We decided to use a single machine (vertical scaling) for fast parallelized builds and tests.
|
||||
|
||||
## Provisioner Configuration
|
||||
|
||||
Our dogfood coderd box runs an SSH tunnel to our dogfood Docker host's docker socket.
|
||||
|
||||
The socket is mounted onto `/var/run/dogfood-docker.sock` in the coderd box.
|
||||
|
||||
The SSH tunnel command can be found hanging out in the screen session named `forward`.
|
||||
|
||||
The tunnel and corresponding SSH key is owned by root.
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"name": "Develop Coder on Coder using Envbuilder",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
|
||||
"features": {},
|
||||
"runArgs": ["--cap-add=SYS_PTRACE"]
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
# Dogfooding Guide
|
||||
|
||||
This guide explains how to
|
||||
[dogfood](https://www.techopedia.com/definition/30784/dogfooding) coder for
|
||||
employees at Coder.
|
||||
|
||||
## How to
|
||||
|
||||
The following explains how to do certain things related to dogfooding.
|
||||
|
||||
### Dogfood using Coder's Deployment
|
||||
|
||||
1. Go to
|
||||
[https://dogfood.cdr.dev/templates/coder-ts](https://dogfood.cdr.dev/templates/coder-ts)
|
||||
1. If you don't have an account, sign in with GitHub
|
||||
2. If you see a dialog/pop-up, hit "Cancel" (this is because of Rippling)
|
||||
2. Create a workspace
|
||||
3. [Connect with your favorite IDE](https://coder.com/docs/user-guides/workspace-access)
|
||||
4. Clone the repo: `git clone git@github.com:coder/coder.git`
|
||||
5. Follow the [contributing guide](https://coder.com/docs/CONTRIBUTING)
|
||||
|
||||
### Run Coder in your Coder Workspace
|
||||
|
||||
1. Clone the Git repo
|
||||
`[https://github.com/coder/coder](https://github.com/coder/coder)` and `cd`
|
||||
into it
|
||||
2. Run `sudo apt update` and then `sudo apt install -y netcat`
|
||||
- skip this step if using the `coder` template
|
||||
3. Run `make bin`
|
||||
|
||||
<aside>
|
||||
💡 If you run into the following error:
|
||||
|
||||
```js
|
||||
pg_dump: server version: 13.7 (Debian 13.7-1.pgdg110+1); pg_dump version: 11.16 (Ubuntu 11.16-1.pgdg20.04+1)
|
||||
pg_dump: aborting because of server version mismatch
|
||||
```
|
||||
|
||||
Don’t fret! This is a known issue. To get around it:
|
||||
|
||||
1. Add `export DB_FROM=coderdb` to your `.bashrc` (make sure you
|
||||
`source ~/.bashrc`)
|
||||
2. Run `sudo service postgresql start`
|
||||
3. Run `sudo -u postgres psql` (this will open the PostgreSQL CLI)
|
||||
4. Run `postgres-# alter user postgres password 'postgres';`
|
||||
5. Run `postgres-# CREATE DATABASE coderdb;`
|
||||
6. Run `postgres-# grant all privileges on database coderdb to postgres;`
|
||||
7. Run `exit` to exit the PostgreSQL terminal
|
||||
8. Try `make bin` again.
|
||||
</aside>
|
||||
|
||||
4. Run `./scripts/develop.sh` which will start _two_ separate processes:
|
||||
1. `[http://localhost:3000](http://localhost:3000)` — backend API server
|
||||
👈 Backend devs will want to talk to this
|
||||
2. `[http://localhost:8080](http://localhost:8080)` — Node.js dev server
|
||||
👈 Frontend devs will want to talk to this
|
||||
5. Ensure that you’re logged in: `./scripts/coder-dev.sh list` — should return
|
||||
no workspace. If this returns an error, double-check the output of running
|
||||
`scripts/develop.sh`.
|
||||
6. A template named `docker` will have automatically been created for you. If you just
|
||||
want to create a workspace quickly, you can run `./scripts/coder-dev.sh create myworkspace -t docker`
|
||||
and this will get you going quickly!
|
||||
7. To create your own template, you can do:
|
||||
`./scripts/coder-dev.sh templates init` and choose your preferred option.
|
||||
For example, choosing “Develop in Docker” will create a new folder `docker`
|
||||
that contains the bare bones for starting a Docker workspace template. Then,
|
||||
enter the folder that was just created and customize as you wish.
|
||||
|
||||
<aside>
|
||||
💡 **For all Docker templates:**
|
||||
This step depends on whether you are developing on a Coder v1 workspace, versus a Coder v2 workspace, versus a VM, versus locally. In any case, check the output of the command `docker context ls` to determine where your Docker daemon is listening. Then open `./docker/main.tf` and check inside the block `provider "docker"` that the variable `"host"` is set correctly.
|
||||
</aside>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### My Docker containers keep failing and I have no idea what's going on
|
||||
|
||||
```console
|
||||
✔ Queued [236ms]
|
||||
✔ Setting up [5ms]
|
||||
⧗ Starting workspace
|
||||
Terraform 1.1.9
|
||||
coder_agent.dev: Plan to create
|
||||
docker_volume.home_volume: Plan to create
|
||||
docker_container.workspace[0]: Plan to create
|
||||
Plan: 3 to add, 0 to change, 0 to destroy.
|
||||
coder_agent.dev: Creating...
|
||||
coder_agent.dev: Creation complete after 0s [id=b2f132bd-9af1-48a7-81dc-187a18ee00d5]
|
||||
docker_volume.home_volume: Creating...
|
||||
docker_volume.home_volume: Creation complete after 0s [id=coder-maf-mywork-root]
|
||||
docker_container.workspace[0]: Creating...
|
||||
docker_container.workspace[0]: Creation errored after 0s
|
||||
Error: container exited immediately
|
||||
|
||||
✘ Starting workspace [2045ms]
|
||||
terraform apply: exit status 1
|
||||
Run 'coder create --help' for usage.
|
||||
```
|
||||
|
||||
Check the output of `docker ps -a`
|
||||
|
||||
- If you see a container with the status `Exited` run
|
||||
`docker logs <container name>` and see what the issue with the container
|
||||
output is
|
||||
|
||||
Enable verbose container logging for Docker:
|
||||
|
||||
```shell
|
||||
sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.orig
|
||||
sudo cat > /etc/docker/daemon.json << EOF
|
||||
{
|
||||
"debug": true,
|
||||
"log-driver": "journald"
|
||||
}
|
||||
EOF
|
||||
sudo systemctl restart docker
|
||||
# You should now see container logs in journald.
|
||||
# Try starting a workspace again and see what the actual error is!
|
||||
sudo journalctl -u docker -f
|
||||
```
|
||||
|
||||
### Help! I'm still blocked
|
||||
|
||||
Post in the #dogfood Slack channel internally or open a Discussion on GitHub and
|
||||
tag @jsjoeio or @bpmct
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,35 +0,0 @@
|
||||
# vscode-coder template
|
||||
|
||||
This template is for developing the
|
||||
[coder/vscode-coder](https://github.com/coder/vscode-coder) VS Code extension.
|
||||
|
||||
## Personalization
|
||||
|
||||
The template includes a `personalize` module that runs your `~/personalize`
|
||||
file if it exists.
|
||||
|
||||
## Testing
|
||||
|
||||
The workspace comes with Playwright Chromium, GTK libraries, xauth, and a
|
||||
D-Bus daemon pre-configured for running tests headlessly, the same way CI
|
||||
does.
|
||||
|
||||
Integration tests launch a real VS Code instance and require a virtual
|
||||
framebuffer. Run them with `xvfb-run -a pnpm test:integration` to match
|
||||
CI behavior.
|
||||
|
||||
See the repo's
|
||||
[AGENTS.md](https://github.com/coder/vscode-coder/blob/main/AGENTS.md)
|
||||
for the full list of commands.
|
||||
|
||||
## Hosting
|
||||
|
||||
Coder dogfoods on a single Teraswitch bare metal machine for best-in-class
|
||||
cost-to-performance. Workspaces run as Docker containers with regional
|
||||
Tailscale endpoints for Pittsburgh, Falkenstein, Sydney, and Cape Town.
|
||||
|
||||
## Provisioner Configuration
|
||||
|
||||
The dogfood coderd box runs an SSH tunnel to the Docker host's socket,
|
||||
mounted at `/var/run/dogfood-docker.sock`. The tunnel runs in a screen
|
||||
session named `forward` and is owned by root.
|
||||
@@ -1,574 +0,0 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.13.0"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
version = "~> 4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
// These are cluster service addresses mapped to Tailscale nodes.
|
||||
// Ask Dean or Kyle for help.
|
||||
docker_host = {
|
||||
"" = "tcp://rubinsky-pit-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
"us-pittsburgh" = "tcp://rubinsky-pit-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
// For legacy reasons, this host is labelled `eu-helsinki` but it's
|
||||
// actually in Germany now.
|
||||
"eu-helsinki" = "tcp://katerose-fsn-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
"ap-sydney" = "tcp://wolfgang-syd-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
"za-cpt" = "tcp://schonkopf-cpt-cdr-dev.tailscale.svc.cluster.local:2375"
|
||||
}
|
||||
|
||||
repo_base_dir = data.coder_parameter.repo_base_dir.value == "~" ? "/home/coder" : replace(data.coder_parameter.repo_base_dir.value, "/^~\\//", "/home/coder/")
|
||||
repo_dir = replace(try(module.git-clone[0].repo_dir, ""), "/^~\\//", "/home/coder/")
|
||||
container_name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
}
|
||||
|
||||
# --- Parameters ---
|
||||
|
||||
data "coder_parameter" "repo_base_dir" {
|
||||
type = "string"
|
||||
name = "Repository Base Directory"
|
||||
default = "~"
|
||||
description = "The directory specified will be created (if missing) and [coder/vscode-coder](https://github.com/coder/vscode-coder) will be automatically cloned into [base directory]/vscode-coder."
|
||||
mutable = true
|
||||
}
|
||||
|
||||
locals {
|
||||
default_regions = {
|
||||
"north-america" : "us-pittsburgh"
|
||||
"europe" : "eu-helsinki"
|
||||
"australia" : "ap-sydney"
|
||||
"africa" : "za-cpt"
|
||||
}
|
||||
|
||||
user_groups = data.coder_workspace_owner.me.groups
|
||||
user_region = coalescelist([
|
||||
for g in local.user_groups :
|
||||
local.default_regions[g] if contains(keys(local.default_regions), g)
|
||||
], ["us-pittsburgh"])[0]
|
||||
}
|
||||
|
||||
data "coder_parameter" "region" {
|
||||
type = "string"
|
||||
name = "Region"
|
||||
icon = "/emojis/1f30e.png"
|
||||
default = local.user_region
|
||||
option {
|
||||
icon = "/emojis/1f1fa-1f1f8.png"
|
||||
name = "Pittsburgh"
|
||||
value = "us-pittsburgh"
|
||||
}
|
||||
option {
|
||||
icon = "/emojis/1f1e9-1f1ea.png"
|
||||
name = "Falkenstein"
|
||||
// For legacy reasons, this host is labelled `eu-helsinki` but it's
|
||||
// actually in Germany now.
|
||||
value = "eu-helsinki"
|
||||
}
|
||||
option {
|
||||
icon = "/emojis/1f1e6-1f1fa.png"
|
||||
name = "Sydney"
|
||||
value = "ap-sydney"
|
||||
}
|
||||
option {
|
||||
icon = "/emojis/1f1ff-1f1e6.png"
|
||||
name = "Cape Town"
|
||||
value = "za-cpt"
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_parameter" "res_mon_memory_threshold" {
|
||||
type = "number"
|
||||
name = "Memory usage threshold"
|
||||
default = 80
|
||||
description = "The memory usage threshold used in resources monitoring to trigger notifications."
|
||||
mutable = true
|
||||
validation {
|
||||
min = 0
|
||||
max = 100
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_parameter" "res_mon_volume_threshold" {
|
||||
type = "number"
|
||||
name = "Volume usage threshold"
|
||||
default = 90
|
||||
description = "The volume usage threshold used in resources monitoring to trigger notifications."
|
||||
mutable = true
|
||||
validation {
|
||||
min = 0
|
||||
max = 100
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_parameter" "res_mon_volume_path" {
|
||||
type = "string"
|
||||
name = "Volume path"
|
||||
default = "/home/coder"
|
||||
description = "The path monitored in resources monitoring to trigger notifications."
|
||||
mutable = true
|
||||
}
|
||||
|
||||
data "coder_parameter" "use_ai_gateway" {
|
||||
type = "bool"
|
||||
name = "Use AI Gateway"
|
||||
default = true
|
||||
description = "If enabled, AI requests will be sent via AI Gateway."
|
||||
mutable = true
|
||||
}
|
||||
|
||||
# Fallback when AI Gateway is disabled. Injected by the pipeline that
|
||||
# pushes this template.
|
||||
variable "anthropic_api_key" {
|
||||
type = string
|
||||
description = "Anthropic API key, used when AI Gateway is disabled."
|
||||
default = ""
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
data "coder_parameter" "ide_choices" {
|
||||
type = "list(string)"
|
||||
name = "Select IDEs"
|
||||
form_type = "multi-select"
|
||||
mutable = true
|
||||
description = "Choose one or more IDEs to enable in your workspace"
|
||||
default = jsonencode(["vscode", "code-server", "cursor"])
|
||||
option {
|
||||
name = "VS Code Desktop"
|
||||
value = "vscode"
|
||||
icon = "/icon/code.svg"
|
||||
}
|
||||
option {
|
||||
name = "code-server"
|
||||
value = "code-server"
|
||||
icon = "/icon/code.svg"
|
||||
}
|
||||
option {
|
||||
name = "VS Code Web"
|
||||
value = "vscode-web"
|
||||
icon = "/icon/code.svg"
|
||||
}
|
||||
option {
|
||||
name = "Cursor"
|
||||
value = "cursor"
|
||||
icon = "/icon/cursor.svg"
|
||||
}
|
||||
option {
|
||||
name = "Windsurf"
|
||||
value = "windsurf"
|
||||
icon = "/icon/windsurf.svg"
|
||||
}
|
||||
option {
|
||||
name = "Zed"
|
||||
value = "zed"
|
||||
icon = "/icon/zed.svg"
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_parameter" "vscode_channel" {
|
||||
count = contains(jsondecode(data.coder_parameter.ide_choices.value), "vscode") ? 1 : 0
|
||||
type = "string"
|
||||
name = "VS Code Desktop channel"
|
||||
description = "Choose the VS Code Desktop channel"
|
||||
mutable = true
|
||||
default = "stable"
|
||||
option {
|
||||
value = "stable"
|
||||
name = "Stable"
|
||||
icon = "/icon/code.svg"
|
||||
}
|
||||
option {
|
||||
value = "insiders"
|
||||
name = "Insiders"
|
||||
icon = "/icon/code-insiders.svg"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Providers and data sources ---
|
||||
|
||||
provider "docker" {
|
||||
host = lookup(local.docker_host, data.coder_parameter.region.value)
|
||||
}
|
||||
|
||||
provider "coder" {}
|
||||
|
||||
data "coder_external_auth" "github" {
|
||||
id = "github"
|
||||
}
|
||||
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
data "coder_workspace_tags" "tags" {
|
||||
tags = {
|
||||
"cluster" : "dogfood-v2"
|
||||
"env" : "gke"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Modules ---
|
||||
|
||||
module "dotfiles" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "dev.registry.coder.com/coder/dotfiles/coder"
|
||||
version = "1.4.2"
|
||||
agent_id = coder_agent.dev.id
|
||||
}
|
||||
|
||||
module "git-config" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "dev.registry.coder.com/coder/git-config/coder"
|
||||
version = "1.0.34"
|
||||
agent_id = coder_agent.dev.id
|
||||
allow_email_change = true
|
||||
}
|
||||
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "dev.registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.3.0"
|
||||
agent_id = coder_agent.dev.id
|
||||
url = "https://github.com/coder/vscode-coder"
|
||||
base_dir = local.repo_base_dir
|
||||
post_clone_script = <<-EOT
|
||||
#!/usr/bin/env bash
|
||||
set -eux -o pipefail
|
||||
coder exp sync start git-clone
|
||||
coder exp sync complete git-clone
|
||||
EOT
|
||||
}
|
||||
|
||||
module "personalize" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "dev.registry.coder.com/coder/personalize/coder"
|
||||
version = "1.0.33"
|
||||
agent_id = coder_agent.dev.id
|
||||
}
|
||||
|
||||
module "code-server" {
|
||||
count = contains(jsondecode(data.coder_parameter.ide_choices.value), "code-server") ? data.coder_workspace.me.start_count : 0
|
||||
source = "dev.registry.coder.com/coder/code-server/coder"
|
||||
version = "1.5.2"
|
||||
agent_id = coder_agent.dev.id
|
||||
folder = local.repo_dir
|
||||
auto_install_extensions = true
|
||||
group = "Web Editors"
|
||||
}
|
||||
|
||||
module "vscode-web" {
|
||||
count = contains(jsondecode(data.coder_parameter.ide_choices.value), "vscode-web") ? data.coder_workspace.me.start_count : 0
|
||||
source = "dev.registry.coder.com/coder/vscode-web/coder"
|
||||
version = "1.6.2"
|
||||
agent_id = coder_agent.dev.id
|
||||
folder = local.repo_dir
|
||||
extensions = ["github.copilot"]
|
||||
auto_install_extensions = true
|
||||
accept_license = true
|
||||
group = "Web Editors"
|
||||
}
|
||||
|
||||
module "copyparty" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "dev.registry.coder.com/djarbz/copyparty/coder"
|
||||
version = "1.0.2"
|
||||
agent_id = coder_agent.dev.id
|
||||
subdomain = true
|
||||
pinned_version = "v1.20.23"
|
||||
arguments = [
|
||||
# copyparty listens on all interfaces by default; the agent proxies localhost.
|
||||
"-i", "127.0.0.1",
|
||||
# Serve the home directory at the web root with all permissions.
|
||||
"-v", "/home/coder:/:A",
|
||||
]
|
||||
}
|
||||
|
||||
module "coder-login" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "dev.registry.coder.com/coder/coder-login/coder"
|
||||
version = "1.1.1"
|
||||
agent_id = coder_agent.dev.id
|
||||
}
|
||||
|
||||
module "cursor" {
|
||||
count = contains(jsondecode(data.coder_parameter.ide_choices.value), "cursor") ? data.coder_workspace.me.start_count : 0
|
||||
source = "dev.registry.coder.com/coder/cursor/coder"
|
||||
version = "1.4.1"
|
||||
agent_id = coder_agent.dev.id
|
||||
folder = local.repo_dir
|
||||
}
|
||||
|
||||
module "windsurf" {
|
||||
count = contains(jsondecode(data.coder_parameter.ide_choices.value), "windsurf") ? data.coder_workspace.me.start_count : 0
|
||||
source = "dev.registry.coder.com/coder/windsurf/coder"
|
||||
version = "1.3.2"
|
||||
agent_id = coder_agent.dev.id
|
||||
folder = local.repo_dir
|
||||
}
|
||||
|
||||
module "zed" {
|
||||
count = contains(jsondecode(data.coder_parameter.ide_choices.value), "zed") ? data.coder_workspace.me.start_count : 0
|
||||
source = "dev.registry.coder.com/coder/zed/coder"
|
||||
version = "1.1.5"
|
||||
agent_id = coder_agent.dev.id
|
||||
agent_name = "dev"
|
||||
folder = local.repo_dir
|
||||
}
|
||||
|
||||
# --- Agent ---
|
||||
|
||||
resource "coder_agent" "dev" {
|
||||
arch = "amd64"
|
||||
os = "linux"
|
||||
dir = local.repo_dir
|
||||
env = merge(
|
||||
{
|
||||
OIDC_TOKEN : data.coder_workspace_owner.me.oidc_access_token,
|
||||
},
|
||||
data.coder_parameter.use_ai_gateway.value ? {
|
||||
ANTHROPIC_BASE_URL : "https://dogfood.cdr.dev/api/v2/ai-gateway/anthropic",
|
||||
ANTHROPIC_AUTH_TOKEN : data.coder_workspace_owner.me.session_token,
|
||||
OPENAI_BASE_URL : "https://dogfood.cdr.dev/api/v2/ai-gateway/openai/v1",
|
||||
OPENAI_API_KEY : data.coder_workspace_owner.me.session_token,
|
||||
} : {}
|
||||
)
|
||||
startup_script_behavior = "blocking"
|
||||
|
||||
display_apps {
|
||||
vscode = contains(jsondecode(data.coder_parameter.ide_choices.value), "vscode") && try(data.coder_parameter.vscode_channel[0].value, "stable") == "stable"
|
||||
vscode_insiders = contains(jsondecode(data.coder_parameter.ide_choices.value), "vscode") && try(data.coder_parameter.vscode_channel[0].value, "stable") == "insiders"
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "cpu_usage"
|
||||
order = 0
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "ram_usage"
|
||||
order = 1
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "/home Usage"
|
||||
key = "home_usage"
|
||||
order = 2
|
||||
script = "sudo du -sh /home/coder | awk '{print $1}'"
|
||||
interval = 3600
|
||||
timeout = 60
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Word of the Day"
|
||||
key = "word"
|
||||
order = 3
|
||||
script = <<EOT
|
||||
#!/usr/bin/env bash
|
||||
curl -o - --silent https://www.merriam-webster.com/word-of-the-day 2>&1 | awk ' $0 ~ "Word of the Day: [A-z]+" { print $5; exit }'
|
||||
EOT
|
||||
interval = 86400
|
||||
timeout = 5
|
||||
}
|
||||
|
||||
resources_monitoring {
|
||||
memory {
|
||||
enabled = true
|
||||
threshold = data.coder_parameter.res_mon_memory_threshold.value
|
||||
}
|
||||
volume {
|
||||
enabled = true
|
||||
threshold = data.coder_parameter.res_mon_volume_threshold.value
|
||||
path = data.coder_parameter.res_mon_volume_path.value
|
||||
}
|
||||
}
|
||||
|
||||
startup_script = <<-EOT
|
||||
#!/usr/bin/env bash
|
||||
set -eux -o pipefail
|
||||
|
||||
function cleanup() {
|
||||
coder exp sync complete agent-startup
|
||||
touch /tmp/.coder-startup-script.done
|
||||
}
|
||||
trap cleanup EXIT
|
||||
coder exp sync start agent-startup
|
||||
|
||||
# Start dbus to suppress noisy Electron/Chromium errors in tests.
|
||||
sudo mkdir -p /run/dbus
|
||||
sudo dbus-daemon --system 2>/dev/null || true
|
||||
|
||||
if ! gh api user --jq .login >/dev/null 2>&1; then
|
||||
echo "Logging into GitHub CLI..."
|
||||
if ! coder external-auth access-token github | gh auth login --hostname github.com --with-token; then
|
||||
echo "GitHub CLI authentication failed; gh commands may not work."
|
||||
fi
|
||||
else
|
||||
echo "GitHub CLI already has working credentials."
|
||||
fi
|
||||
EOT
|
||||
}
|
||||
|
||||
# --- Scripts ---
|
||||
|
||||
resource "coder_script" "install-deps" {
|
||||
agent_id = coder_agent.dev.id
|
||||
display_name = "Installing Dependencies"
|
||||
run_on_start = true
|
||||
start_blocks_login = false
|
||||
script = <<EOT
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
trap 'coder exp sync complete install-deps' EXIT
|
||||
coder exp sync want install-deps git-clone
|
||||
coder exp sync start install-deps
|
||||
|
||||
cd "${local.repo_dir}" && pnpm install
|
||||
|
||||
# Playwright maintains the list of system libs each Chromium version
|
||||
# needs, so we don't have to track them in the Dockerfile.
|
||||
# Electron additionally requires libgtk-3-0 which Playwright skips
|
||||
# because its bundled Chromium doesn't use GTK. xauth is needed
|
||||
# by xvfb-run for integration tests.
|
||||
sudo npx --yes playwright install-deps chromium
|
||||
sudo apt-get install -y --no-install-recommends libgtk-3-0 xauth
|
||||
EOT
|
||||
}
|
||||
|
||||
# --- Docker resources ---
|
||||
|
||||
resource "coder_metadata" "home_volume" {
|
||||
resource_id = docker_volume.home_volume.id
|
||||
daily_cost = 1
|
||||
}
|
||||
|
||||
resource "docker_volume" "home_volume" {
|
||||
name = "coder-${data.coder_workspace.me.id}-home"
|
||||
lifecycle {
|
||||
ignore_changes = all
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner"
|
||||
value = data.coder_workspace_owner.me.name
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner_id"
|
||||
value = data.coder_workspace_owner.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_id"
|
||||
value = data.coder_workspace.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_name_at_creation"
|
||||
value = data.coder_workspace.me.name
|
||||
}
|
||||
}
|
||||
|
||||
data "docker_registry_image" "vscode_coder" {
|
||||
name = "codercom/oss-dogfood-vscode-coder:latest"
|
||||
}
|
||||
|
||||
resource "docker_image" "vscode_coder" {
|
||||
name = "codercom/oss-dogfood-vscode-coder:latest@${data.docker_registry_image.vscode_coder.sha256_digest}"
|
||||
pull_triggers = [
|
||||
data.docker_registry_image.vscode_coder.sha256_digest,
|
||||
filesha1("Dockerfile"),
|
||||
]
|
||||
keep_locally = true
|
||||
}
|
||||
|
||||
resource "docker_container" "workspace" {
|
||||
lifecycle {
|
||||
ignore_changes = [name, hostname, labels, env, entrypoint]
|
||||
}
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = docker_image.vscode_coder.name
|
||||
name = local.container_name
|
||||
hostname = data.coder_workspace.me.name
|
||||
entrypoint = ["sh", "-c", coder_agent.dev.init_script]
|
||||
memory = 8192
|
||||
|
||||
# Allow the agent to finish cleanup traps on shutdown.
|
||||
destroy_grace_seconds = 60
|
||||
stop_timeout = 60
|
||||
stop_signal = "SIGINT"
|
||||
|
||||
env = [
|
||||
"CODER_AGENT_TOKEN=${coder_agent.dev.token}",
|
||||
]
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
volumes {
|
||||
container_path = "/home/coder/"
|
||||
volume_name = docker_volume.home_volume.name
|
||||
read_only = false
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner"
|
||||
value = data.coder_workspace_owner.me.name
|
||||
}
|
||||
labels {
|
||||
label = "coder.owner_id"
|
||||
value = data.coder_workspace_owner.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_id"
|
||||
value = data.coder_workspace.me.id
|
||||
}
|
||||
labels {
|
||||
label = "coder.workspace_name"
|
||||
value = data.coder_workspace.me.name
|
||||
}
|
||||
}
|
||||
|
||||
resource "coder_metadata" "container_info" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
resource_id = docker_container.workspace[0].id
|
||||
item {
|
||||
key = "memory"
|
||||
value = docker_container.workspace[0].memory
|
||||
}
|
||||
item {
|
||||
key = "region"
|
||||
value = data.coder_parameter.region.option[index(data.coder_parameter.region.option.*.value, data.coder_parameter.region.value)].name
|
||||
}
|
||||
}
|
||||
|
||||
module "claude-code" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "dev.registry.coder.com/coder/claude-code/coder"
|
||||
version = "5.4.1"
|
||||
enable_ai_gateway = data.coder_parameter.use_ai_gateway.value
|
||||
anthropic_api_key = data.coder_parameter.use_ai_gateway.value ? "" : var.anthropic_api_key
|
||||
agent_id = coder_agent.dev.id
|
||||
workdir = local.repo_dir
|
||||
}
|
||||
|
||||
resource "coder_app" "claude" {
|
||||
agent_id = coder_agent.dev.id
|
||||
slug = "claude"
|
||||
display_name = "Claude Code"
|
||||
icon = "/icon/claude.svg"
|
||||
open_in = "slim-window"
|
||||
command = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
cd "${local.repo_dir}"
|
||||
exec tmux new-session -A -s claude claude
|
||||
EOT
|
||||
}
|
||||
@@ -52,7 +52,7 @@ fi
|
||||
# Helper: run a make target inside the image.
|
||||
#
|
||||
# Mounts /home/coder/ as a single named volume to mirror the dogfood
|
||||
# workspace template (dogfood/coder/main.tf), so caches (Go modules,
|
||||
# workspace template, so caches (Go modules,
|
||||
# Go build, pnpm store, mise data, etc.) persist the same way they do
|
||||
# in real workspaces. Per-cache subpath volumes would come up
|
||||
# root-owned on first mount because Docker creates non-existent
|
||||
|
||||
Reference in New Issue
Block a user