Split single-container Coder template into per-env templates
The old root main.tf tried to switch dev profiles inside one shared container via a coder_parameter dropdown; the settings-application path looked for a *.json cache file that never existed (the cache was written as *.code-profile), so profile settings never actually applied, and VS Code extensions were copied from extensions/ (which turns out to be Claude Code plugin bundles, not real VS Code extension packages). Replace it with one independent Coder template per environment (templates/default, 3d-printing, cobol, python, ttrpg, web). Each reads its matching profile-templates/*.code-profile file at template-push time via file()/jsondecode(), feeds the extension ID list straight into the code-server module's `extensions` input, and writes the raw settings.json text via a coder_script - no runtime Gitea zip download needed anymore. Also add scripts/cli-setup-wizard.sh, hooked into every new interactive shell until completed, offering to install/log into GitHub Copilot CLI, Google Antigravity CLI, and Claude Code CLI. VS Code extensions are deliberately not asked about there since Terraform already handles them. All six templates verified with `terraform init`/`validate` against the real coder-server container on octo-winsrv. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
* text=auto eol=lf
|
||||
*.sh text eol=lf
|
||||
*.tf text eol=lf
|
||||
*.code-profile -text
|
||||
@@ -1,2 +1,86 @@
|
||||
# Profiles-for-Coder
|
||||
|
||||
Coder templates for per-discipline dev environments (Default, 3D Printing,
|
||||
COBOL, Python, TTRPG, Web). Each environment is its own Coder **template** -
|
||||
not a dropdown inside one shared container, which is what this repo used to
|
||||
do and which didn't actually work.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
templates/
|
||||
default/main.tf # Standard Default Dev
|
||||
3d-printing/main.tf # 3D Printing & Engineering
|
||||
cobol/main.tf # COBOL Modern Mainframe
|
||||
python/main.tf # Python Engineering
|
||||
ttrpg/main.tf # TTRPG & Lore Building
|
||||
web/main.tf # Web Applications
|
||||
scripts/
|
||||
cli-setup-wizard.sh # shared first-run wizard, see below
|
||||
profile-templates/ # VS Code .code-profile exports, one per env
|
||||
extensions/ # Claude Code plugin/skill bundles (see note below)
|
||||
```
|
||||
|
||||
Each `templates/<env>/main.tf` is a complete, independent Coder template
|
||||
(agent, docker container, code-server, JetBrains). They're deliberately not
|
||||
built from a shared Terraform module - only their `locals` block differs
|
||||
(which profile file to read). Push them individually:
|
||||
|
||||
```sh
|
||||
coder templates push profiles-default -d templates/default
|
||||
coder templates push profiles-3d -d templates/3d-printing
|
||||
coder templates push profiles-cobol -d templates/cobol
|
||||
coder templates push profiles-python -d templates/python
|
||||
coder templates push profiles-ttrpg -d templates/ttrpg
|
||||
coder templates push profiles-web -d templates/web
|
||||
```
|
||||
|
||||
### How the VS Code profile gets applied
|
||||
|
||||
`profile-templates/*.code-profile` is a real VS Code Profile export: a JSON
|
||||
file whose `settings` and `extensions` fields are themselves JSON-encoded
|
||||
strings (double/triple-nested). Each template's `main.tf` reads and decodes
|
||||
its matching file **at `terraform apply`/push time** (via `file()` +
|
||||
`jsondecode()`), then:
|
||||
|
||||
- passes the extension ID list straight into the `code-server` module's
|
||||
`extensions` input, so code-server installs them on first boot - no
|
||||
interactive prompt needed, Terraform handles it declaratively;
|
||||
- writes the raw `settings.json` text (comments and all - VS Code tolerates
|
||||
JSONC) to `~/.local/share/code-server/User/settings.json` via a
|
||||
`coder_script`.
|
||||
|
||||
This replaces the old approach, which downloaded a zip of this repo from
|
||||
Gitea *inside* the running container and tried to apply settings from
|
||||
`~/.local/share/profiles-cache/<profile>.json` - a path that never matched
|
||||
the actual `.code-profile` file extension, so settings never applied. That
|
||||
bug (plus the single shared container) is why "one container, many envs"
|
||||
never really worked.
|
||||
|
||||
### CLI setup wizard
|
||||
|
||||
`scripts/cli-setup-wizard.sh` is dropped onto every workspace and hooked
|
||||
into `~/.bashrc`. It runs in every new interactive terminal - until the user
|
||||
finishes it - and offers to install + log into:
|
||||
|
||||
- **GitHub Copilot CLI** (`npm install -g @github/copilot`, then `copilot login`)
|
||||
- **Google Antigravity CLI** (`curl -fsSL https://antigravity.google/cli/install.sh | bash`, binary `agy`)
|
||||
- **Claude Code CLI** (`npm install -g @anthropic-ai/claude-code`, then `claude`)
|
||||
|
||||
It does **not** ask about VS Code extensions, since those are handled by
|
||||
Terraform (see above). Once the user confirms completion it writes a
|
||||
sentinel file (`~/.cache/coder-cli-wizard/done`) and stops prompting. It can
|
||||
always be re-run manually: `bash /opt/coder/cli-setup-wizard.sh --force`.
|
||||
|
||||
### `extensions/` directory
|
||||
|
||||
Heads up: `extensions/awesome-skills-plugin` and `extensions/custom-specialty-plugin`
|
||||
are **Claude Code plugin/skill bundles** (`plugin.json` + `SKILL.md` files),
|
||||
not actual VS Code extension packages. The old root `main.tf` copied this
|
||||
folder straight into code-server's extensions directory, which would never
|
||||
have worked as VS Code extensions regardless of the container bug above.
|
||||
This rewrite doesn't wire `extensions/` into anything - it's left as-is
|
||||
pending a decision on whether/how to install these as Claude Code plugins
|
||||
inside each workspace (e.g. `custom-specialty-plugin/skills/cobol-teacher`
|
||||
for the COBOL env, `openscad-parametric` for 3D, `ttrpg-lore-weaver` /
|
||||
`foundryvtt-modding` for TTRPG).
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env bash
|
||||
# Coder workspace first-run CLI setup wizard.
|
||||
#
|
||||
# Meant to be `source`d from a new interactive shell (e.g. via .bashrc). It asks,
|
||||
# once per user per workspace, whether to install and log into a few optional
|
||||
# AI coding CLIs. It re-runs on every new terminal until the user lets it finish
|
||||
# (or explicitly skips it for good), then gets out of the way.
|
||||
#
|
||||
# VS Code / code-server extensions are intentionally NOT asked about here -
|
||||
# they're installed declaratively by the Coder template itself (the
|
||||
# `code-server` module's `extensions` input, populated from the matching
|
||||
# profile-templates/*.code-profile file at template-push time).
|
||||
#
|
||||
# Manual re-run: bash /opt/coder/cli-setup-wizard.sh --force
|
||||
|
||||
set -u
|
||||
|
||||
WIZARD_DONE_FILE="${HOME}/.cache/coder-cli-wizard/done"
|
||||
FORCE=0
|
||||
[ "${1:-}" = "--force" ] && FORCE=1
|
||||
|
||||
export PATH="${HOME}/.local/bin:${PATH}"
|
||||
|
||||
# Only bother interactive shells with a real terminal attached, and only until
|
||||
# the user marks the wizard as done.
|
||||
if [ "$FORCE" -ne 1 ]; then
|
||||
case "$-" in
|
||||
*i*) : ;;
|
||||
*) return 0 2>/dev/null || exit 0 ;;
|
||||
esac
|
||||
[ -t 0 ] || { return 0 2>/dev/null || exit 0; }
|
||||
[ -f "$WIZARD_DONE_FILE" ] && { return 0 2>/dev/null || exit 0; }
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "$WIZARD_DONE_FILE")"
|
||||
|
||||
ask_yes_no() {
|
||||
local prompt="$1" reply
|
||||
read -r -p "$prompt [y/N] " reply
|
||||
case "$reply" in
|
||||
[Yy]*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "==================================================================="
|
||||
echo " Coder workspace setup wizard"
|
||||
echo " Runs once per new terminal until you finish it. Ctrl+C any time"
|
||||
echo " to skip for now - it'll ask again next terminal."
|
||||
echo "==================================================================="
|
||||
|
||||
# --- GitHub Copilot CLI ---
|
||||
if command -v copilot >/dev/null 2>&1; then
|
||||
echo "GitHub Copilot CLI already installed, skipping."
|
||||
elif command -v npm >/dev/null 2>&1; then
|
||||
if ask_yes_no "Install GitHub Copilot CLI and log in?"; then
|
||||
if npm install -g @github/copilot; then
|
||||
copilot login || echo "Install succeeded but login didn't complete. Retry any time with: copilot login"
|
||||
else
|
||||
echo "Copilot CLI install failed. Retry later with: npm install -g @github/copilot && copilot login"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Skipping GitHub Copilot CLI: npm not found on this workspace image."
|
||||
fi
|
||||
|
||||
# --- Google Antigravity CLI (agy) ---
|
||||
if command -v agy >/dev/null 2>&1; then
|
||||
echo "Antigravity CLI already installed, skipping."
|
||||
else
|
||||
if ask_yes_no "Install Google Antigravity CLI (agy) and log in?"; then
|
||||
if curl -fsSL https://antigravity.google/cli/install.sh | bash; then
|
||||
echo "Launching 'agy' once to complete sign-in (exit with /logout or Ctrl+D when done)..."
|
||||
agy || echo "Sign-in didn't complete. Retry any time by running: agy"
|
||||
else
|
||||
echo "Antigravity CLI install failed. Retry later with: curl -fsSL https://antigravity.google/cli/install.sh | bash"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Claude Code CLI ---
|
||||
if command -v claude >/dev/null 2>&1; then
|
||||
echo "Claude Code CLI already installed, skipping."
|
||||
elif command -v npm >/dev/null 2>&1; then
|
||||
if ask_yes_no "Install Claude Code CLI and log in?"; then
|
||||
if npm install -g @anthropic-ai/claude-code; then
|
||||
echo "Launching 'claude' once to complete sign-in (use /login if not prompted; Ctrl+C to exit when done)..."
|
||||
claude || echo "Sign-in didn't complete. Retry any time by running: claude"
|
||||
else
|
||||
echo "Claude Code CLI install failed. Retry later with: npm install -g @anthropic-ai/claude-code"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Skipping Claude Code CLI: npm not found on this workspace image."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if ask_yes_no "Mark setup wizard as complete so it stops asking on new terminals?"; then
|
||||
touch "$WIZARD_DONE_FILE"
|
||||
echo "Done. Re-run any time with: bash /opt/coder/cli-setup-wizard.sh --force"
|
||||
else
|
||||
echo "OK, this'll ask again next time you open a terminal."
|
||||
fi
|
||||
|
||||
return 0 2>/dev/null || exit 0
|
||||
@@ -0,0 +1,269 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
env_name = "3D Printing & Engineering"
|
||||
profile = jsondecode(file("${path.module}/../../profile-templates/3D.code-profile"))
|
||||
settings_raw = jsondecode(local.profile.settings).settings
|
||||
extensions = [for e in jsondecode(local.profile.extensions) : e.identifier.id]
|
||||
}
|
||||
|
||||
variable "docker_socket" {
|
||||
default = ""
|
||||
description = "(Optional) Docker socket URI"
|
||||
type = string
|
||||
}
|
||||
|
||||
provider "docker" {
|
||||
# Defaulting to null if the variable is an empty string lets us have an optional variable without having to set our own default
|
||||
host = var.docker_socket != "" ? var.docker_socket : null
|
||||
}
|
||||
|
||||
data "coder_provisioner" "me" {}
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
arch = data.coder_provisioner.me.arch
|
||||
os = "linux"
|
||||
startup_script = <<-EOT
|
||||
set -e
|
||||
|
||||
# Prepare user home with default files on first start.
|
||||
if [ ! -f ~/.init_done ]; then
|
||||
cp -rT /etc/skel ~
|
||||
touch ~/.init_done
|
||||
fi
|
||||
|
||||
# Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here
|
||||
EOT
|
||||
|
||||
# These environment variables allow you to make Git commits right away after creating a
|
||||
# workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
|
||||
# You can remove this block if you'd prefer to configure Git manually or using
|
||||
# dotfiles. (see docs/dotfiles.md)
|
||||
env = {
|
||||
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}"
|
||||
}
|
||||
|
||||
# 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.
|
||||
# For basic resources, you can use the `coder stat` command.
|
||||
# If you need more control, you can write your own script.
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "0_cpu_usage"
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "1_ram_usage"
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Home Disk"
|
||||
key = "3_home_disk"
|
||||
script = "coder stat disk --path $${HOME}"
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage (Host)"
|
||||
key = "4_cpu_usage_host"
|
||||
script = "coder stat cpu --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Memory Usage (Host)"
|
||||
key = "5_mem_usage_host"
|
||||
script = "coder stat mem --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Load Average (Host)"
|
||||
key = "6_load_host"
|
||||
# get load avg scaled by number of cores
|
||||
script = <<EOT
|
||||
echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }'
|
||||
EOT
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Swap Usage (Host)"
|
||||
key = "7_swap_host"
|
||||
script = <<EOT
|
||||
free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }'
|
||||
EOT
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/code-server
|
||||
# `extensions` is populated at template-push time from this env's
|
||||
# profile-templates/*.code-profile file, so no interactive prompt is
|
||||
# needed for VS Code extensions - Terraform handles it declaratively.
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
# Pass the target folder here natively
|
||||
folder = "/home/coder/workspace"
|
||||
|
||||
extensions = local.extensions
|
||||
order = 1
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/jetbrains
|
||||
module "jetbrains" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/jetbrains/coder"
|
||||
version = "~> 1.1"
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "main"
|
||||
folder = "/home/coder"
|
||||
tooltip = "You need to [install JetBrains Toolbox](https://coder.com/docs/user-guides/workspace-access/jetbrains/toolbox) to use this app."
|
||||
}
|
||||
|
||||
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_container" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
# Uses lower() to avoid Docker restriction on container names.
|
||||
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
# Hostname makes the shell more user friendly: coder@my-workspace:~$
|
||||
hostname = data.coder_workspace.me.name
|
||||
# Use the docker gateway if the access URL is 127.0.0.1
|
||||
entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
|
||||
env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
host {
|
||||
host = "code.octoturge.com"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
volumes {
|
||||
container_path = "/home/coder"
|
||||
volume_name = docker_volume.home_volume.name
|
||||
read_only = false
|
||||
}
|
||||
|
||||
# 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
|
||||
}
|
||||
labels {
|
||||
label = "coder.profile"
|
||||
value = local.env_name
|
||||
}
|
||||
}
|
||||
|
||||
# Writes this env's VS Code settings.json, sourced straight from the
|
||||
# matching profile-templates/*.code-profile file at template-push time.
|
||||
resource "coder_script" "apply_settings" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Apply ${local.env_name} VS Code Settings"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p "$HOME/workspace"
|
||||
mkdir -p "$HOME/.local/share/code-server/User"
|
||||
echo '${base64encode(local.settings_raw)}' | base64 -d > "$HOME/.local/share/code-server/User/settings.json"
|
||||
EOT
|
||||
}
|
||||
|
||||
# Drops the shared CLI setup wizard onto the workspace and hooks it into
|
||||
# every new interactive shell (via .bashrc) until the user completes it.
|
||||
# See ../../scripts/cli-setup-wizard.sh for what it actually asks.
|
||||
resource "coder_script" "cli_setup_wizard" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install CLI Setup Wizard"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p /opt/coder
|
||||
echo '${base64encode(file("${path.module}/../../scripts/cli-setup-wizard.sh"))}' | base64 -d > /opt/coder/cli-setup-wizard.sh
|
||||
chmod +x /opt/coder/cli-setup-wizard.sh
|
||||
|
||||
MARKER="# >>> coder cli setup wizard >>>"
|
||||
if ! grep -qF "$MARKER" "$HOME/.bashrc" 2>/dev/null; then
|
||||
{
|
||||
echo ""
|
||||
echo "$MARKER"
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"'
|
||||
echo 'source /opt/coder/cli-setup-wizard.sh'
|
||||
echo "# <<< coder cli setup wizard <<<"
|
||||
} >> "$HOME/.bashrc"
|
||||
fi
|
||||
EOT
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
env_name = "COBOL Modern Mainframe"
|
||||
profile = jsondecode(file("${path.module}/../../profile-templates/COBOL.code-profile"))
|
||||
settings_raw = jsondecode(local.profile.settings).settings
|
||||
extensions = [for e in jsondecode(local.profile.extensions) : e.identifier.id]
|
||||
}
|
||||
|
||||
variable "docker_socket" {
|
||||
default = ""
|
||||
description = "(Optional) Docker socket URI"
|
||||
type = string
|
||||
}
|
||||
|
||||
provider "docker" {
|
||||
# Defaulting to null if the variable is an empty string lets us have an optional variable without having to set our own default
|
||||
host = var.docker_socket != "" ? var.docker_socket : null
|
||||
}
|
||||
|
||||
data "coder_provisioner" "me" {}
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
arch = data.coder_provisioner.me.arch
|
||||
os = "linux"
|
||||
startup_script = <<-EOT
|
||||
set -e
|
||||
|
||||
# Prepare user home with default files on first start.
|
||||
if [ ! -f ~/.init_done ]; then
|
||||
cp -rT /etc/skel ~
|
||||
touch ~/.init_done
|
||||
fi
|
||||
|
||||
# Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here
|
||||
EOT
|
||||
|
||||
# These environment variables allow you to make Git commits right away after creating a
|
||||
# workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
|
||||
# You can remove this block if you'd prefer to configure Git manually or using
|
||||
# dotfiles. (see docs/dotfiles.md)
|
||||
env = {
|
||||
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}"
|
||||
}
|
||||
|
||||
# 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.
|
||||
# For basic resources, you can use the `coder stat` command.
|
||||
# If you need more control, you can write your own script.
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "0_cpu_usage"
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "1_ram_usage"
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Home Disk"
|
||||
key = "3_home_disk"
|
||||
script = "coder stat disk --path $${HOME}"
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage (Host)"
|
||||
key = "4_cpu_usage_host"
|
||||
script = "coder stat cpu --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Memory Usage (Host)"
|
||||
key = "5_mem_usage_host"
|
||||
script = "coder stat mem --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Load Average (Host)"
|
||||
key = "6_load_host"
|
||||
# get load avg scaled by number of cores
|
||||
script = <<EOT
|
||||
echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }'
|
||||
EOT
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Swap Usage (Host)"
|
||||
key = "7_swap_host"
|
||||
script = <<EOT
|
||||
free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }'
|
||||
EOT
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/code-server
|
||||
# `extensions` is populated at template-push time from this env's
|
||||
# profile-templates/*.code-profile file, so no interactive prompt is
|
||||
# needed for VS Code extensions - Terraform handles it declaratively.
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
# Pass the target folder here natively
|
||||
folder = "/home/coder/workspace"
|
||||
|
||||
extensions = local.extensions
|
||||
order = 1
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/jetbrains
|
||||
module "jetbrains" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/jetbrains/coder"
|
||||
version = "~> 1.1"
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "main"
|
||||
folder = "/home/coder"
|
||||
tooltip = "You need to [install JetBrains Toolbox](https://coder.com/docs/user-guides/workspace-access/jetbrains/toolbox) to use this app."
|
||||
}
|
||||
|
||||
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_container" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
# Uses lower() to avoid Docker restriction on container names.
|
||||
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
# Hostname makes the shell more user friendly: coder@my-workspace:~$
|
||||
hostname = data.coder_workspace.me.name
|
||||
# Use the docker gateway if the access URL is 127.0.0.1
|
||||
entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
|
||||
env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
host {
|
||||
host = "code.octoturge.com"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
volumes {
|
||||
container_path = "/home/coder"
|
||||
volume_name = docker_volume.home_volume.name
|
||||
read_only = false
|
||||
}
|
||||
|
||||
# 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
|
||||
}
|
||||
labels {
|
||||
label = "coder.profile"
|
||||
value = local.env_name
|
||||
}
|
||||
}
|
||||
|
||||
# Writes this env's VS Code settings.json, sourced straight from the
|
||||
# matching profile-templates/*.code-profile file at template-push time.
|
||||
resource "coder_script" "apply_settings" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Apply ${local.env_name} VS Code Settings"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p "$HOME/workspace"
|
||||
mkdir -p "$HOME/.local/share/code-server/User"
|
||||
echo '${base64encode(local.settings_raw)}' | base64 -d > "$HOME/.local/share/code-server/User/settings.json"
|
||||
EOT
|
||||
}
|
||||
|
||||
# Drops the shared CLI setup wizard onto the workspace and hooks it into
|
||||
# every new interactive shell (via .bashrc) until the user completes it.
|
||||
# See ../../scripts/cli-setup-wizard.sh for what it actually asks.
|
||||
resource "coder_script" "cli_setup_wizard" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install CLI Setup Wizard"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p /opt/coder
|
||||
echo '${base64encode(file("${path.module}/../../scripts/cli-setup-wizard.sh"))}' | base64 -d > /opt/coder/cli-setup-wizard.sh
|
||||
chmod +x /opt/coder/cli-setup-wizard.sh
|
||||
|
||||
MARKER="# >>> coder cli setup wizard >>>"
|
||||
if ! grep -qF "$MARKER" "$HOME/.bashrc" 2>/dev/null; then
|
||||
{
|
||||
echo ""
|
||||
echo "$MARKER"
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"'
|
||||
echo 'source /opt/coder/cli-setup-wizard.sh'
|
||||
echo "# <<< coder cli setup wizard <<<"
|
||||
} >> "$HOME/.bashrc"
|
||||
fi
|
||||
EOT
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
env_name = "Default"
|
||||
profile = jsondecode(file("${path.module}/../../profile-templates/Default.code-profile"))
|
||||
settings_raw = jsondecode(local.profile.settings).settings
|
||||
extensions = [for e in jsondecode(local.profile.extensions) : e.identifier.id]
|
||||
}
|
||||
|
||||
variable "docker_socket" {
|
||||
default = ""
|
||||
description = "(Optional) Docker socket URI"
|
||||
type = string
|
||||
}
|
||||
|
||||
provider "docker" {
|
||||
# Defaulting to null if the variable is an empty string lets us have an optional variable without having to set our own default
|
||||
host = var.docker_socket != "" ? var.docker_socket : null
|
||||
}
|
||||
|
||||
data "coder_provisioner" "me" {}
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
arch = data.coder_provisioner.me.arch
|
||||
os = "linux"
|
||||
startup_script = <<-EOT
|
||||
set -e
|
||||
|
||||
# Prepare user home with default files on first start.
|
||||
if [ ! -f ~/.init_done ]; then
|
||||
cp -rT /etc/skel ~
|
||||
touch ~/.init_done
|
||||
fi
|
||||
|
||||
# Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here
|
||||
EOT
|
||||
|
||||
# These environment variables allow you to make Git commits right away after creating a
|
||||
# workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
|
||||
# You can remove this block if you'd prefer to configure Git manually or using
|
||||
# dotfiles. (see docs/dotfiles.md)
|
||||
env = {
|
||||
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}"
|
||||
}
|
||||
|
||||
# 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.
|
||||
# For basic resources, you can use the `coder stat` command.
|
||||
# If you need more control, you can write your own script.
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "0_cpu_usage"
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "1_ram_usage"
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Home Disk"
|
||||
key = "3_home_disk"
|
||||
script = "coder stat disk --path $${HOME}"
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage (Host)"
|
||||
key = "4_cpu_usage_host"
|
||||
script = "coder stat cpu --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Memory Usage (Host)"
|
||||
key = "5_mem_usage_host"
|
||||
script = "coder stat mem --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Load Average (Host)"
|
||||
key = "6_load_host"
|
||||
# get load avg scaled by number of cores
|
||||
script = <<EOT
|
||||
echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }'
|
||||
EOT
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Swap Usage (Host)"
|
||||
key = "7_swap_host"
|
||||
script = <<EOT
|
||||
free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }'
|
||||
EOT
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/code-server
|
||||
# `extensions` is populated at template-push time from this env's
|
||||
# profile-templates/*.code-profile file, so no interactive prompt is
|
||||
# needed for VS Code extensions - Terraform handles it declaratively.
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
# Pass the target folder here natively
|
||||
folder = "/home/coder/workspace"
|
||||
|
||||
extensions = local.extensions
|
||||
order = 1
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/jetbrains
|
||||
module "jetbrains" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/jetbrains/coder"
|
||||
version = "~> 1.1"
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "main"
|
||||
folder = "/home/coder"
|
||||
tooltip = "You need to [install JetBrains Toolbox](https://coder.com/docs/user-guides/workspace-access/jetbrains/toolbox) to use this app."
|
||||
}
|
||||
|
||||
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_container" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
# Uses lower() to avoid Docker restriction on container names.
|
||||
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
# Hostname makes the shell more user friendly: coder@my-workspace:~$
|
||||
hostname = data.coder_workspace.me.name
|
||||
# Use the docker gateway if the access URL is 127.0.0.1
|
||||
entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
|
||||
env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
host {
|
||||
host = "code.octoturge.com"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
volumes {
|
||||
container_path = "/home/coder"
|
||||
volume_name = docker_volume.home_volume.name
|
||||
read_only = false
|
||||
}
|
||||
|
||||
# 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
|
||||
}
|
||||
labels {
|
||||
label = "coder.profile"
|
||||
value = local.env_name
|
||||
}
|
||||
}
|
||||
|
||||
# Writes this env's VS Code settings.json, sourced straight from the
|
||||
# matching profile-templates/*.code-profile file at template-push time.
|
||||
resource "coder_script" "apply_settings" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Apply ${local.env_name} VS Code Settings"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p "$HOME/workspace"
|
||||
mkdir -p "$HOME/.local/share/code-server/User"
|
||||
echo '${base64encode(local.settings_raw)}' | base64 -d > "$HOME/.local/share/code-server/User/settings.json"
|
||||
EOT
|
||||
}
|
||||
|
||||
# Drops the shared CLI setup wizard onto the workspace and hooks it into
|
||||
# every new interactive shell (via .bashrc) until the user completes it.
|
||||
# See ../../scripts/cli-setup-wizard.sh for what it actually asks.
|
||||
resource "coder_script" "cli_setup_wizard" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install CLI Setup Wizard"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p /opt/coder
|
||||
echo '${base64encode(file("${path.module}/../../scripts/cli-setup-wizard.sh"))}' | base64 -d > /opt/coder/cli-setup-wizard.sh
|
||||
chmod +x /opt/coder/cli-setup-wizard.sh
|
||||
|
||||
MARKER="# >>> coder cli setup wizard >>>"
|
||||
if ! grep -qF "$MARKER" "$HOME/.bashrc" 2>/dev/null; then
|
||||
{
|
||||
echo ""
|
||||
echo "$MARKER"
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"'
|
||||
echo 'source /opt/coder/cli-setup-wizard.sh'
|
||||
echo "# <<< coder cli setup wizard <<<"
|
||||
} >> "$HOME/.bashrc"
|
||||
fi
|
||||
EOT
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
env_name = "Python Engineering"
|
||||
profile = jsondecode(file("${path.module}/../../profile-templates/Python.code-profile"))
|
||||
settings_raw = jsondecode(local.profile.settings).settings
|
||||
extensions = [for e in jsondecode(local.profile.extensions) : e.identifier.id]
|
||||
}
|
||||
|
||||
variable "docker_socket" {
|
||||
default = ""
|
||||
description = "(Optional) Docker socket URI"
|
||||
type = string
|
||||
}
|
||||
|
||||
provider "docker" {
|
||||
# Defaulting to null if the variable is an empty string lets us have an optional variable without having to set our own default
|
||||
host = var.docker_socket != "" ? var.docker_socket : null
|
||||
}
|
||||
|
||||
data "coder_provisioner" "me" {}
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
arch = data.coder_provisioner.me.arch
|
||||
os = "linux"
|
||||
startup_script = <<-EOT
|
||||
set -e
|
||||
|
||||
# Prepare user home with default files on first start.
|
||||
if [ ! -f ~/.init_done ]; then
|
||||
cp -rT /etc/skel ~
|
||||
touch ~/.init_done
|
||||
fi
|
||||
|
||||
# Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here
|
||||
EOT
|
||||
|
||||
# These environment variables allow you to make Git commits right away after creating a
|
||||
# workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
|
||||
# You can remove this block if you'd prefer to configure Git manually or using
|
||||
# dotfiles. (see docs/dotfiles.md)
|
||||
env = {
|
||||
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}"
|
||||
}
|
||||
|
||||
# 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.
|
||||
# For basic resources, you can use the `coder stat` command.
|
||||
# If you need more control, you can write your own script.
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "0_cpu_usage"
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "1_ram_usage"
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Home Disk"
|
||||
key = "3_home_disk"
|
||||
script = "coder stat disk --path $${HOME}"
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage (Host)"
|
||||
key = "4_cpu_usage_host"
|
||||
script = "coder stat cpu --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Memory Usage (Host)"
|
||||
key = "5_mem_usage_host"
|
||||
script = "coder stat mem --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Load Average (Host)"
|
||||
key = "6_load_host"
|
||||
# get load avg scaled by number of cores
|
||||
script = <<EOT
|
||||
echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }'
|
||||
EOT
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Swap Usage (Host)"
|
||||
key = "7_swap_host"
|
||||
script = <<EOT
|
||||
free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }'
|
||||
EOT
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/code-server
|
||||
# `extensions` is populated at template-push time from this env's
|
||||
# profile-templates/*.code-profile file, so no interactive prompt is
|
||||
# needed for VS Code extensions - Terraform handles it declaratively.
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
# Pass the target folder here natively
|
||||
folder = "/home/coder/workspace"
|
||||
|
||||
extensions = local.extensions
|
||||
order = 1
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/jetbrains
|
||||
module "jetbrains" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/jetbrains/coder"
|
||||
version = "~> 1.1"
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "main"
|
||||
folder = "/home/coder"
|
||||
tooltip = "You need to [install JetBrains Toolbox](https://coder.com/docs/user-guides/workspace-access/jetbrains/toolbox) to use this app."
|
||||
}
|
||||
|
||||
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_container" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
# Uses lower() to avoid Docker restriction on container names.
|
||||
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
# Hostname makes the shell more user friendly: coder@my-workspace:~$
|
||||
hostname = data.coder_workspace.me.name
|
||||
# Use the docker gateway if the access URL is 127.0.0.1
|
||||
entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
|
||||
env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
host {
|
||||
host = "code.octoturge.com"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
volumes {
|
||||
container_path = "/home/coder"
|
||||
volume_name = docker_volume.home_volume.name
|
||||
read_only = false
|
||||
}
|
||||
|
||||
# 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
|
||||
}
|
||||
labels {
|
||||
label = "coder.profile"
|
||||
value = local.env_name
|
||||
}
|
||||
}
|
||||
|
||||
# Writes this env's VS Code settings.json, sourced straight from the
|
||||
# matching profile-templates/*.code-profile file at template-push time.
|
||||
resource "coder_script" "apply_settings" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Apply ${local.env_name} VS Code Settings"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p "$HOME/workspace"
|
||||
mkdir -p "$HOME/.local/share/code-server/User"
|
||||
echo '${base64encode(local.settings_raw)}' | base64 -d > "$HOME/.local/share/code-server/User/settings.json"
|
||||
EOT
|
||||
}
|
||||
|
||||
# Drops the shared CLI setup wizard onto the workspace and hooks it into
|
||||
# every new interactive shell (via .bashrc) until the user completes it.
|
||||
# See ../../scripts/cli-setup-wizard.sh for what it actually asks.
|
||||
resource "coder_script" "cli_setup_wizard" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install CLI Setup Wizard"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p /opt/coder
|
||||
echo '${base64encode(file("${path.module}/../../scripts/cli-setup-wizard.sh"))}' | base64 -d > /opt/coder/cli-setup-wizard.sh
|
||||
chmod +x /opt/coder/cli-setup-wizard.sh
|
||||
|
||||
MARKER="# >>> coder cli setup wizard >>>"
|
||||
if ! grep -qF "$MARKER" "$HOME/.bashrc" 2>/dev/null; then
|
||||
{
|
||||
echo ""
|
||||
echo "$MARKER"
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"'
|
||||
echo 'source /opt/coder/cli-setup-wizard.sh'
|
||||
echo "# <<< coder cli setup wizard <<<"
|
||||
} >> "$HOME/.bashrc"
|
||||
fi
|
||||
EOT
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
env_name = "TTRPG & Lore Building"
|
||||
profile = jsondecode(file("${path.module}/../../profile-templates/TTRPG.code-profile"))
|
||||
settings_raw = jsondecode(local.profile.settings).settings
|
||||
extensions = [for e in jsondecode(local.profile.extensions) : e.identifier.id]
|
||||
}
|
||||
|
||||
variable "docker_socket" {
|
||||
default = ""
|
||||
description = "(Optional) Docker socket URI"
|
||||
type = string
|
||||
}
|
||||
|
||||
provider "docker" {
|
||||
# Defaulting to null if the variable is an empty string lets us have an optional variable without having to set our own default
|
||||
host = var.docker_socket != "" ? var.docker_socket : null
|
||||
}
|
||||
|
||||
data "coder_provisioner" "me" {}
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
arch = data.coder_provisioner.me.arch
|
||||
os = "linux"
|
||||
startup_script = <<-EOT
|
||||
set -e
|
||||
|
||||
# Prepare user home with default files on first start.
|
||||
if [ ! -f ~/.init_done ]; then
|
||||
cp -rT /etc/skel ~
|
||||
touch ~/.init_done
|
||||
fi
|
||||
|
||||
# Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here
|
||||
EOT
|
||||
|
||||
# These environment variables allow you to make Git commits right away after creating a
|
||||
# workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
|
||||
# You can remove this block if you'd prefer to configure Git manually or using
|
||||
# dotfiles. (see docs/dotfiles.md)
|
||||
env = {
|
||||
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}"
|
||||
}
|
||||
|
||||
# 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.
|
||||
# For basic resources, you can use the `coder stat` command.
|
||||
# If you need more control, you can write your own script.
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "0_cpu_usage"
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "1_ram_usage"
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Home Disk"
|
||||
key = "3_home_disk"
|
||||
script = "coder stat disk --path $${HOME}"
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage (Host)"
|
||||
key = "4_cpu_usage_host"
|
||||
script = "coder stat cpu --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Memory Usage (Host)"
|
||||
key = "5_mem_usage_host"
|
||||
script = "coder stat mem --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Load Average (Host)"
|
||||
key = "6_load_host"
|
||||
# get load avg scaled by number of cores
|
||||
script = <<EOT
|
||||
echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }'
|
||||
EOT
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Swap Usage (Host)"
|
||||
key = "7_swap_host"
|
||||
script = <<EOT
|
||||
free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }'
|
||||
EOT
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/code-server
|
||||
# `extensions` is populated at template-push time from this env's
|
||||
# profile-templates/*.code-profile file, so no interactive prompt is
|
||||
# needed for VS Code extensions - Terraform handles it declaratively.
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
# Pass the target folder here natively
|
||||
folder = "/home/coder/workspace"
|
||||
|
||||
extensions = local.extensions
|
||||
order = 1
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/jetbrains
|
||||
module "jetbrains" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/jetbrains/coder"
|
||||
version = "~> 1.1"
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "main"
|
||||
folder = "/home/coder"
|
||||
tooltip = "You need to [install JetBrains Toolbox](https://coder.com/docs/user-guides/workspace-access/jetbrains/toolbox) to use this app."
|
||||
}
|
||||
|
||||
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_container" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
# Uses lower() to avoid Docker restriction on container names.
|
||||
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
# Hostname makes the shell more user friendly: coder@my-workspace:~$
|
||||
hostname = data.coder_workspace.me.name
|
||||
# Use the docker gateway if the access URL is 127.0.0.1
|
||||
entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
|
||||
env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
host {
|
||||
host = "code.octoturge.com"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
volumes {
|
||||
container_path = "/home/coder"
|
||||
volume_name = docker_volume.home_volume.name
|
||||
read_only = false
|
||||
}
|
||||
|
||||
# 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
|
||||
}
|
||||
labels {
|
||||
label = "coder.profile"
|
||||
value = local.env_name
|
||||
}
|
||||
}
|
||||
|
||||
# Writes this env's VS Code settings.json, sourced straight from the
|
||||
# matching profile-templates/*.code-profile file at template-push time.
|
||||
resource "coder_script" "apply_settings" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Apply ${local.env_name} VS Code Settings"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p "$HOME/workspace"
|
||||
mkdir -p "$HOME/.local/share/code-server/User"
|
||||
echo '${base64encode(local.settings_raw)}' | base64 -d > "$HOME/.local/share/code-server/User/settings.json"
|
||||
EOT
|
||||
}
|
||||
|
||||
# Drops the shared CLI setup wizard onto the workspace and hooks it into
|
||||
# every new interactive shell (via .bashrc) until the user completes it.
|
||||
# See ../../scripts/cli-setup-wizard.sh for what it actually asks.
|
||||
resource "coder_script" "cli_setup_wizard" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install CLI Setup Wizard"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p /opt/coder
|
||||
echo '${base64encode(file("${path.module}/../../scripts/cli-setup-wizard.sh"))}' | base64 -d > /opt/coder/cli-setup-wizard.sh
|
||||
chmod +x /opt/coder/cli-setup-wizard.sh
|
||||
|
||||
MARKER="# >>> coder cli setup wizard >>>"
|
||||
if ! grep -qF "$MARKER" "$HOME/.bashrc" 2>/dev/null; then
|
||||
{
|
||||
echo ""
|
||||
echo "$MARKER"
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"'
|
||||
echo 'source /opt/coder/cli-setup-wizard.sh'
|
||||
echo "# <<< coder cli setup wizard <<<"
|
||||
} >> "$HOME/.bashrc"
|
||||
fi
|
||||
EOT
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
}
|
||||
docker = {
|
||||
source = "kreuzwerker/docker"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
env_name = "Web Applications"
|
||||
profile = jsondecode(file("${path.module}/../../profile-templates/Web.code-profile"))
|
||||
settings_raw = jsondecode(local.profile.settings).settings
|
||||
extensions = [for e in jsondecode(local.profile.extensions) : e.identifier.id]
|
||||
}
|
||||
|
||||
variable "docker_socket" {
|
||||
default = ""
|
||||
description = "(Optional) Docker socket URI"
|
||||
type = string
|
||||
}
|
||||
|
||||
provider "docker" {
|
||||
# Defaulting to null if the variable is an empty string lets us have an optional variable without having to set our own default
|
||||
host = var.docker_socket != "" ? var.docker_socket : null
|
||||
}
|
||||
|
||||
data "coder_provisioner" "me" {}
|
||||
data "coder_workspace" "me" {}
|
||||
data "coder_workspace_owner" "me" {}
|
||||
|
||||
resource "coder_agent" "main" {
|
||||
arch = data.coder_provisioner.me.arch
|
||||
os = "linux"
|
||||
startup_script = <<-EOT
|
||||
set -e
|
||||
|
||||
# Prepare user home with default files on first start.
|
||||
if [ ! -f ~/.init_done ]; then
|
||||
cp -rT /etc/skel ~
|
||||
touch ~/.init_done
|
||||
fi
|
||||
|
||||
# Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here
|
||||
EOT
|
||||
|
||||
# These environment variables allow you to make Git commits right away after creating a
|
||||
# workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
|
||||
# You can remove this block if you'd prefer to configure Git manually or using
|
||||
# dotfiles. (see docs/dotfiles.md)
|
||||
env = {
|
||||
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}"
|
||||
}
|
||||
|
||||
# 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.
|
||||
# For basic resources, you can use the `coder stat` command.
|
||||
# If you need more control, you can write your own script.
|
||||
metadata {
|
||||
display_name = "CPU Usage"
|
||||
key = "0_cpu_usage"
|
||||
script = "coder stat cpu"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "RAM Usage"
|
||||
key = "1_ram_usage"
|
||||
script = "coder stat mem"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Home Disk"
|
||||
key = "3_home_disk"
|
||||
script = "coder stat disk --path $${HOME}"
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "CPU Usage (Host)"
|
||||
key = "4_cpu_usage_host"
|
||||
script = "coder stat cpu --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Memory Usage (Host)"
|
||||
key = "5_mem_usage_host"
|
||||
script = "coder stat mem --host"
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Load Average (Host)"
|
||||
key = "6_load_host"
|
||||
# get load avg scaled by number of cores
|
||||
script = <<EOT
|
||||
echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }'
|
||||
EOT
|
||||
interval = 60
|
||||
timeout = 1
|
||||
}
|
||||
|
||||
metadata {
|
||||
display_name = "Swap Usage (Host)"
|
||||
key = "7_swap_host"
|
||||
script = <<EOT
|
||||
free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }'
|
||||
EOT
|
||||
interval = 10
|
||||
timeout = 1
|
||||
}
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/code-server
|
||||
# `extensions` is populated at template-push time from this env's
|
||||
# profile-templates/*.code-profile file, so no interactive prompt is
|
||||
# needed for VS Code extensions - Terraform handles it declaratively.
|
||||
module "code-server" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/code-server/coder"
|
||||
version = "~> 1.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
# Pass the target folder here natively
|
||||
folder = "/home/coder/workspace"
|
||||
|
||||
extensions = local.extensions
|
||||
order = 1
|
||||
}
|
||||
|
||||
# See https://registry.coder.com/modules/coder/jetbrains
|
||||
module "jetbrains" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/jetbrains/coder"
|
||||
version = "~> 1.1"
|
||||
agent_id = coder_agent.main.id
|
||||
agent_name = "main"
|
||||
folder = "/home/coder"
|
||||
tooltip = "You need to [install JetBrains Toolbox](https://coder.com/docs/user-guides/workspace-access/jetbrains/toolbox) to use this app."
|
||||
}
|
||||
|
||||
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_container" "workspace" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
image = "codercom/enterprise-base:ubuntu"
|
||||
# Uses lower() to avoid Docker restriction on container names.
|
||||
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
|
||||
# Hostname makes the shell more user friendly: coder@my-workspace:~$
|
||||
hostname = data.coder_workspace.me.name
|
||||
# Use the docker gateway if the access URL is 127.0.0.1
|
||||
entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
|
||||
env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
|
||||
host {
|
||||
host = "host.docker.internal"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
host {
|
||||
host = "code.octoturge.com"
|
||||
ip = "host-gateway"
|
||||
}
|
||||
volumes {
|
||||
container_path = "/home/coder"
|
||||
volume_name = docker_volume.home_volume.name
|
||||
read_only = false
|
||||
}
|
||||
|
||||
# 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
|
||||
}
|
||||
labels {
|
||||
label = "coder.profile"
|
||||
value = local.env_name
|
||||
}
|
||||
}
|
||||
|
||||
# Writes this env's VS Code settings.json, sourced straight from the
|
||||
# matching profile-templates/*.code-profile file at template-push time.
|
||||
resource "coder_script" "apply_settings" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Apply ${local.env_name} VS Code Settings"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p "$HOME/workspace"
|
||||
mkdir -p "$HOME/.local/share/code-server/User"
|
||||
echo '${base64encode(local.settings_raw)}' | base64 -d > "$HOME/.local/share/code-server/User/settings.json"
|
||||
EOT
|
||||
}
|
||||
|
||||
# Drops the shared CLI setup wizard onto the workspace and hooks it into
|
||||
# every new interactive shell (via .bashrc) until the user completes it.
|
||||
# See ../../scripts/cli-setup-wizard.sh for what it actually asks.
|
||||
resource "coder_script" "cli_setup_wizard" {
|
||||
agent_id = coder_agent.main.id
|
||||
display_name = "Install CLI Setup Wizard"
|
||||
run_on_start = true
|
||||
script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -e
|
||||
mkdir -p /opt/coder
|
||||
echo '${base64encode(file("${path.module}/../../scripts/cli-setup-wizard.sh"))}' | base64 -d > /opt/coder/cli-setup-wizard.sh
|
||||
chmod +x /opt/coder/cli-setup-wizard.sh
|
||||
|
||||
MARKER="# >>> coder cli setup wizard >>>"
|
||||
if ! grep -qF "$MARKER" "$HOME/.bashrc" 2>/dev/null; then
|
||||
{
|
||||
echo ""
|
||||
echo "$MARKER"
|
||||
echo 'export PATH="$HOME/.local/bin:$PATH"'
|
||||
echo 'source /opt/coder/cli-setup-wizard.sh'
|
||||
echo "# <<< coder cli setup wizard <<<"
|
||||
} >> "$HOME/.bashrc"
|
||||
fi
|
||||
EOT
|
||||
}
|
||||
Reference in New Issue
Block a user