175 lines
5.2 KiB
Terraform
175 lines
5.2 KiB
Terraform
terraform {
|
|
required_providers {
|
|
coder = { source = "coder/coder" }
|
|
docker = { source = "kreuzwerker/docker" }
|
|
}
|
|
}
|
|
|
|
provider "docker" {}
|
|
|
|
data "coder_workspace" "me" {}
|
|
data "coder_workspace_owner" "me" {}
|
|
|
|
locals {
|
|
username = data.coder_workspace_owner.me.name
|
|
home_dir = "/home/${local.username}"
|
|
home_host_path = "/mnt/pve/unas/services/coder/${local.username}/${data.coder_workspace.me.name}"
|
|
}
|
|
|
|
resource "coder_agent" "main" {
|
|
arch = "amd64"
|
|
os = "linux"
|
|
startup_script = <<-EOT
|
|
set -e
|
|
# --- minimal deps (uv image is slim) ---
|
|
if ! command -v git >/dev/null; then
|
|
sudo apt-get update -qq
|
|
sudo apt-get install -y --no-install-recommends git curl ca-certificates sudo openssh-client nano
|
|
fi
|
|
|
|
# --- latest stable Python via uv (tracks current release channel) ---
|
|
uv python install --default
|
|
uv python pin "$(uv python find | xargs -n1 basename | head -1)" 2>/dev/null || true
|
|
echo "Python: $(uv run python --version)"
|
|
|
|
# --- code-server (browser VS Code) ---
|
|
if ! command -v code-server >/dev/null; then
|
|
curl -fsSL https://code-server.dev/install.sh | sh
|
|
fi
|
|
mkdir -p ~/.config/code-server
|
|
cat > ~/.config/code-server/config.yaml <<CFG
|
|
bind-addr: 127.0.0.1:13337
|
|
auth: none
|
|
cert: false
|
|
CFG
|
|
code-server --disable-telemetry >/tmp/code-server.log 2>&1 &
|
|
|
|
# --- opencode CLI (uses LiteLLM + MCP gateway) ---
|
|
if ! command -v opencode >/dev/null 2>&1; then
|
|
curl -fsSL https://opencode.ai/install | sh >/dev/null 2>&1 || true
|
|
fi
|
|
|
|
# --- Claude Code CLI (routed via LiteLLM ANTHROPIC_BASE_URL) ---
|
|
if ! command -v claude >/dev/null 2>&1; then
|
|
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - >/dev/null
|
|
sudo apt-get install -y --no-install-recommends nodejs >/dev/null
|
|
sudo npm install -g @anthropic-ai/claude-code >/dev/null
|
|
fi
|
|
|
|
# --- workspace scaffold (idempotent) ---
|
|
mkdir -p ~/work ~/home
|
|
[ -f ~/.bashrc ] || echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc
|
|
|
|
# --- dotfiles (optional; user sets via UI param) ---
|
|
if [ -n "${data.coder_parameter.dotfiles_uri.value}" ]; then
|
|
coder dotfiles -y "${data.coder_parameter.dotfiles_uri.value}" || true
|
|
fi
|
|
EOT
|
|
|
|
metadata {
|
|
display_name = "CPU"
|
|
key = "0_cpu"
|
|
script = "coder stat cpu"
|
|
interval = 10
|
|
timeout = 1
|
|
}
|
|
metadata {
|
|
display_name = "RAM"
|
|
key = "1_ram"
|
|
script = "coder stat mem"
|
|
interval = 10
|
|
timeout = 1
|
|
}
|
|
metadata {
|
|
display_name = "Disk"
|
|
key = "2_disk"
|
|
script = "coder stat disk"
|
|
interval = 60
|
|
timeout = 1
|
|
}
|
|
metadata {
|
|
display_name = "Python"
|
|
key = "3_python"
|
|
script = "uv run python --version 2>/dev/null || echo n/a"
|
|
interval = 60
|
|
timeout = 5
|
|
}
|
|
}
|
|
|
|
data "coder_parameter" "dotfiles_uri" {
|
|
name = "dotfiles_uri"
|
|
display_name = "Dotfiles repo (optional)"
|
|
description = "Git URL of a dotfiles repo. Coder will clone it and run install.sh on workspace start."
|
|
type = "string"
|
|
default = "https://git.nuclide.systems/fkrebs/dotfiles.git"
|
|
mutable = true
|
|
}
|
|
|
|
resource "coder_app" "code-server" {
|
|
agent_id = coder_agent.main.id
|
|
slug = "code-server"
|
|
display_name = "VS Code"
|
|
url = "http://localhost:13337"
|
|
icon = "/icon/code.svg"
|
|
subdomain = false
|
|
share = "owner"
|
|
healthcheck {
|
|
url = "http://localhost:13337/healthz"
|
|
interval = 5
|
|
threshold = 6
|
|
}
|
|
}
|
|
|
|
resource "docker_image" "workspace" {
|
|
name = "ghcr.io/astral-sh/uv:bookworm-slim"
|
|
}
|
|
|
|
resource "docker_container" "workspace" {
|
|
count = data.coder_workspace.me.start_count
|
|
image = docker_image.workspace.name
|
|
name = "coder-${local.username}-${lower(data.coder_workspace.me.name)}"
|
|
hostname = data.coder_workspace.me.name
|
|
|
|
# The agent's init script bootstraps everything.
|
|
entrypoint = ["sh", "-c", <<-EOT
|
|
apt-get update -qq && apt-get install -y --no-install-recommends curl ca-certificates sudo procps >/dev/null 2>&1
|
|
${coder_agent.main.init_script}
|
|
EOT
|
|
]
|
|
env = [
|
|
"CODER_AGENT_TOKEN=${coder_agent.main.token}",
|
|
"OPENAI_API_KEY=sk-tapirnase",
|
|
"OPENAI_BASE_URL=http://192.168.1.40:14000/v1",
|
|
"OPENAI_MODEL=qwen3-coder-30b-a3b-instruct",
|
|
"AIDER_MODEL=qwen3-coder-30b-a3b-instruct",
|
|
"AIDER_WEAK_MODEL=mistral-small-latest",
|
|
"EMBEDDING_MODEL=text-embedding-3-large",
|
|
"ANTHROPIC_BASE_URL=http://192.168.1.40:14000",
|
|
"ANTHROPIC_API_KEY=sk-tapirnase",
|
|
"CHAT_ARTIFACTS_ENDPOINT=https://s3.nuclide.systems",
|
|
"CHAT_ARTIFACTS_ACCESS_KEY=GK50bfcfcb7e05fb8421193ab0",
|
|
"CHAT_ARTIFACTS_SECRET_KEY=fa139e0422c0140331a69be4053eb7fb0d04bd64cd33790714099481ba19e0bf",
|
|
"CHAT_ARTIFACTS_BUCKET=chat-artifacts",
|
|
"MCP_GATEWAY_TOKEN=JxxCqKw32XoN4LOHunDikS6u1RpS7R5ythzaqADPuIA",
|
|
]
|
|
|
|
# Persistent home backed by UNAS.
|
|
volumes {
|
|
container_path = local.home_dir
|
|
host_path = local.home_host_path
|
|
read_only = false
|
|
}
|
|
|
|
# Intel Arc GPU.
|
|
devices { host_path = "/dev/dri/renderD128" }
|
|
|
|
# Sane resource caps; tune later.
|
|
memory = 8192
|
|
cpu_shares = 1024
|
|
|
|
host {
|
|
host = "host.docker.internal"
|
|
ip = "host-gateway"
|
|
}
|
|
}
|