Compare commits

..

6 Commits

Author SHA1 Message Date
DevCats 19519a0a13 fix: add shebang to zed coder_script (#504)
## Description

Add `#!/bin/sh` to zed_settings coder_script
<!-- Briefly describe what this PR does and why -->

## Type of Change

- [ ] New module
- [ ] New template
- [X] Bug fix
- [ ] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Module Information

<!-- Delete this section if not applicable -->

**Path:** `registry/coder/modules/zed`  
**New version:** `v1.1.1`  
**Breaking change:** [ ] Yes [X] No

## Testing & Validation

- [X] Tests pass (`bun test`)
- [X] Code formatted (`bun fmt`)
- [X] Changes tested locally

## Related Issues

https://github.com/coder/registry/issues/482
<!-- Link related issues or write "None" if not applicable -->
2025-10-23 07:39:27 -05:00
Rowan Smith 63e42283ce chore: Update templates from Always to IfNotPresent for image_pull_policy (#501)
## Description

Change `image_pull_policy` from `Always` to `IfNotPresent` on Coder
owned templates. Given these are a reference point for users and
customers and they copy them into their own templates I think it makes
sense to encourage the use of caching of images.

## Type of Change

- [ ] New module
- [ ] New template
- [ ] Bug fix
- [x] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Template Information

**Path:** 


https://github.com/coder/registry/tree/main/registry/coder/templates/kubernetes-devcontainer

https://github.com/coder/registry/tree/main/registry/coder/templates/kubernetes-envbox

https://github.com/coder/registry/tree/main/registry/coder/templates/kubernetes

## Testing & Validation

- [ ] Tests pass (`bun test`)
- [ ] Code formatted (`bun fmt`)
- [x] Changes tested locally

## Related Issues

None
2025-10-23 04:28:58 +00:00
Eric Paulsen 0c5a8a2354 add nfs-deployment template (#502)
## Description

this PR adds a new template to the registry, which shows how to mount an
NFS share to a K8s deployment workspace.

## Type of Change

- [ ] New module
- [x] New template
- [ ] Bug fix
- [ ] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Template Information

<!-- Delete this section if not applicable -->

**Path:** `registry/ericpaulsen/templates/nfs-deployment`

## Testing & Validation

- [x] Tests pass (`bun test`)
- [x] Code formatted (`bun fmt`)
- [x] Changes tested locally

## Related Issues

None

---------

Co-authored-by: DevCats <christofer@coder.com>
2025-10-22 11:51:58 -05:00
DevCats 51ec6e3212 fix: resolve issues with claude-code session resumption (#496)
## Description

Fixes session resumption logic by having the continue flag decide
whether to continue a workspace based on session history

## Type of Change

- [ ] New module
- [ ] New template
- [X] Bug fix
- [X] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Module Information

<!-- Delete this section if not applicable -->

**Path:** `registry/coder/modules/claude-code`  
**New version:** `v3.2.2`  
**Breaking change:** [ ] Yes [X] No

## Testing & Validation

- [X] Tests pass (`bun test`)
- [X] Code formatted (`bun fmt`)
- [X] Changes tested locally

## Related Issues

<!-- Link related issues or write "None" if not applicable -->

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-22 10:58:01 -05:00
DevCats 843b1f1e5a chore: change copilot default version to latest (#499)
## Description

Changes `copilot_version` default to `latest`

## Type of Change

- [ ] New module
- [ ] New template
- [X] Bug fix
- [ ] Feature/enhancement
- [ ] Documentation
- [ ] Other

## Module Information

<!-- Delete this section if not applicable -->

**Path:** `registry/coder-labs/modules/copilot`  
**New version:** `v0.2.2`  
**Breaking change:** [ ] Yes [X] No

## Testing & Validation

- [X] Tests pass (`bun test`)
- [X] Code formatted (`bun fmt`)
- [X] Changes tested locally

## Related Issues

<!-- Link related issues or write "None" if not applicable -->
2025-10-22 07:33:09 -05:00
Jiachen Jiang 583918bfef added example of boundary to claude code module (#500) 2025-10-21 16:33:15 -05:00
14 changed files with 536 additions and 50 deletions
+1
View File
@@ -6,6 +6,7 @@ HashiCorp = "HashiCorp"
mavrickrishi = "mavrickrishi" # Username
mavrick = "mavrick" # Username
inh = "inh" # Option in setpriv command
exportfs = "exportfs" # nfs related binary
[files]
extend-exclude = ["registry/coder/templates/aws-devcontainer/architecture.svg"] #False positive
@@ -13,7 +13,7 @@ Run [GitHub Copilot CLI](https://docs.github.com/copilot/concepts/agents/about-c
```tf
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.2.1"
version = "0.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder/projects"
}
@@ -51,7 +51,7 @@ data "coder_parameter" "ai_prompt" {
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.2.1"
version = "0.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder/projects"
@@ -71,12 +71,12 @@ Customize tool permissions, MCP servers, and Copilot settings:
```tf
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.2.1"
version = "0.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder/projects"
# Version pinning (defaults to "0.0.334", use "latest" for newest version)
copilot_version = "latest"
# Version pinning (defaults to "latest", use specific version if desired)
copilot_version = "0.0.334"
# Tool permissions
allow_tools = ["shell(git)", "shell(npm)", "write"]
@@ -142,7 +142,7 @@ variable "github_token" {
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.2.1"
version = "0.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder/projects"
github_token = var.github_token
@@ -156,7 +156,7 @@ Run Copilot as a command-line tool without task reporting or web interface. This
```tf
module "copilot" {
source = "registry.coder.com/coder-labs/copilot/coder"
version = "0.2.1"
version = "0.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder"
report_tasks = false
+1 -1
View File
@@ -104,7 +104,7 @@ variable "agentapi_version" {
variable "copilot_version" {
type = string
description = "The version of GitHub Copilot CLI to install. Use 'latest' for the latest version or specify a version like '0.0.334'."
default = "0.0.334"
default = "latest"
}
variable "report_tasks" {
+27 -6
View File
@@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.2.0"
version = "3.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder/project"
claude_api_key = "xxxx-xxxxx-xxxx"
@@ -32,8 +32,29 @@ module "claude-code" {
- You can get the API key from the [Anthropic Console](https://console.anthropic.com/dashboard).
- You can get the Session Token using the `claude setup-token` command. This is a long-lived authentication token (requires Claude subscription)
### Session Resumption Behavior
By default, Claude Code automatically resumes existing conversations when your workspace restarts. Sessions are tracked per workspace directory, so conversations continue where you left off. If no session exists (first start), your `ai_prompt` will run normally. To disable this behavior and always start fresh, set `continue = false`
## Examples
### Usage with Agent Boundaries
This example shows how to configure the Claude Code module to run the agent behind a process-level boundary that restricts its network access.
```tf
module "claude-code" {
source = "dev.registry.coder.com/coder/claude-code/coder"
enable_boundary = true
boundary_version = "main"
boundary_log_dir = "/tmp/boundary_logs"
boundary_log_level = "WARN"
boundary_additional_allowed_urls = ["GET *google.com"]
boundary_proxy_port = "8087"
version = "3.2.1"
}
```
### Usage with Tasks and Advanced Configuration
This example shows how to configure the Claude Code module with an AI prompt, API key shared by all users of the template, and other custom settings.
@@ -49,7 +70,7 @@ data "coder_parameter" "ai_prompt" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.2.0"
version = "3.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder/project"
@@ -85,7 +106,7 @@ Run and configure Claude Code as a standalone CLI in your workspace.
```tf
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.2.0"
version = "3.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder"
install_claude_code = true
@@ -108,7 +129,7 @@ variable "claude_code_oauth_token" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.2.0"
version = "3.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder/project"
claude_code_oauth_token = var.claude_code_oauth_token
@@ -181,7 +202,7 @@ resource "coder_env" "bedrock_api_key" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.2.0"
version = "3.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder/project"
model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
@@ -238,7 +259,7 @@ resource "coder_env" "google_application_credentials" {
module "claude-code" {
source = "registry.coder.com/coder/claude-code/coder"
version = "3.2.0"
version = "3.2.2"
agent_id = coder_agent.example.id
workdir = "/home/coder/project"
model = "claude-sonnet-4@20250514"
@@ -167,7 +167,7 @@ describe("claude-code", async () => {
const { id } = await setup({
moduleVariables: {
permission_mode: mode,
task_prompt: "test prompt",
ai_prompt: "test prompt",
},
});
await execModuleScript(id);
@@ -185,7 +185,7 @@ describe("claude-code", async () => {
const { id } = await setup({
moduleVariables: {
model: model,
task_prompt: "test prompt",
ai_prompt: "test prompt",
},
});
await execModuleScript(id);
@@ -198,13 +198,24 @@ describe("claude-code", async () => {
expect(startLog.stdout).toContain(`--model ${model}`);
});
test("claude-continue-previous-conversation", async () => {
test("claude-continue-resume-existing-session", async () => {
const { id } = await setup({
moduleVariables: {
continue: "true",
task_prompt: "test prompt",
ai_prompt: "test prompt",
},
});
// Create a mock session file with the predefined task session ID
const taskSessionId = "cd32e253-ca16-4fd3-9825-d837e74ae3c2";
const sessionDir = `/home/coder/.claude/projects/-home-coder-project`;
await execContainer(id, ["mkdir", "-p", sessionDir]);
await execContainer(id, [
"bash",
"-c",
`touch ${sessionDir}/session-${taskSessionId}.jsonl`,
]);
await execModuleScript(id);
const startLog = await execContainer(id, [
@@ -212,7 +223,9 @@ describe("claude-code", async () => {
"-c",
"cat /home/coder/.claude-module/agentapi-start.log",
]);
expect(startLog.stdout).toContain("--continue");
expect(startLog.stdout).toContain("--resume");
expect(startLog.stdout).toContain(taskSessionId);
expect(startLog.stdout).toContain("Resuming existing task session");
});
test("pre-post-install-scripts", async () => {
+2 -2
View File
@@ -134,8 +134,8 @@ variable "resume_session_id" {
variable "continue" {
type = bool
description = "Load the most recent conversation in the current directory. Task will fail in a new workspace with no conversation/session to continue"
default = false
description = "Automatically continue existing sessions on workspace restart. When true, resumes existing conversation if found, otherwise runs prompt or starts new session. When false, always starts fresh (ignores existing sessions)."
default = true
}
variable "dangerously_skip_permissions" {
@@ -64,37 +64,70 @@ function validate_claude_installation() {
fi
}
TASK_SESSION_ID="cd32e253-ca16-4fd3-9825-d837e74ae3c2"
task_session_exists() {
if find "$HOME/.claude" -type f -name "*${TASK_SESSION_ID}*" 2> /dev/null | grep -q .; then
return 0
else
return 1
fi
}
ARGS=()
function build_claude_args() {
function start_agentapi() {
mkdir -p "$ARG_WORKDIR"
cd "$ARG_WORKDIR"
if [ -n "$ARG_MODEL" ]; then
ARGS+=(--model "$ARG_MODEL")
fi
if [ -n "$ARG_RESUME_SESSION_ID" ]; then
ARGS+=(--resume "$ARG_RESUME_SESSION_ID")
fi
if [ "$ARG_CONTINUE" = "true" ]; then
ARGS+=(--continue)
fi
if [ -n "$ARG_PERMISSION_MODE" ]; then
ARGS+=(--permission-mode "$ARG_PERMISSION_MODE")
fi
}
function start_agentapi() {
mkdir -p "$ARG_WORKDIR"
cd "$ARG_WORKDIR"
if [ -n "$ARG_AI_PROMPT" ]; then
ARGS+=(--dangerously-skip-permissions "$ARG_AI_PROMPT")
else
if [ -n "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" ]; then
if [ -n "$ARG_RESUME_SESSION_ID" ]; then
echo "Using explicit resume_session_id: $ARG_RESUME_SESSION_ID"
ARGS+=(--resume "$ARG_RESUME_SESSION_ID")
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
ARGS+=(--dangerously-skip-permissions)
fi
elif [ "$ARG_CONTINUE" = "true" ]; then
if task_session_exists; then
echo "Task session detected (ID: $TASK_SESSION_ID)"
ARGS+=(--resume "$TASK_SESSION_ID")
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
ARGS+=(--dangerously-skip-permissions)
fi
echo "Resuming existing task session"
else
echo "No existing task session found"
ARGS+=(--session-id "$TASK_SESSION_ID")
if [ -n "$ARG_AI_PROMPT" ]; then
ARGS+=(--dangerously-skip-permissions "$ARG_AI_PROMPT")
echo "Starting new task session with prompt"
else
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
ARGS+=(--dangerously-skip-permissions)
fi
echo "Starting new task session"
fi
fi
else
echo "Continue disabled, starting fresh session"
if [ -n "$ARG_AI_PROMPT" ]; then
ARGS+=(--dangerously-skip-permissions "$ARG_AI_PROMPT")
echo "Starting new session with prompt"
else
if [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ]; then
ARGS+=(--dangerously-skip-permissions)
fi
echo "Starting claude code session"
fi
fi
printf "Running claude code with args: %s\n" "$(printf '%q ' "${ARGS[@]}")"
if [ "${ARG_ENABLE_BOUNDARY:-false}" = "true" ]; then
@@ -140,5 +173,4 @@ function start_agentapi() {
}
validate_claude_installation
build_claude_args
start_agentapi
+5 -5
View File
@@ -19,7 +19,7 @@ Zed is a high-performance, multiplayer code editor from the creators of Atom and
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.0"
version = "1.1.1"
agent_id = coder_agent.example.id
}
```
@@ -32,7 +32,7 @@ module "zed" {
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.0"
version = "1.1.1"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
}
@@ -44,7 +44,7 @@ module "zed" {
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.0"
version = "1.1.1"
agent_id = coder_agent.example.id
display_name = "Zed Editor"
order = 1
@@ -57,7 +57,7 @@ module "zed" {
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.0"
version = "1.1.1"
agent_id = coder_agent.example.id
agent_name = coder_agent.example.name
}
@@ -73,7 +73,7 @@ You can declaratively set/merge settings with the `settings` input. Provide a JS
module "zed" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/zed/coder"
version = "1.1.0"
version = "1.1.1"
agent_id = coder_agent.example.id
settings = jsonencode({
+1
View File
@@ -73,6 +73,7 @@ resource "coder_script" "zed_settings" {
icon = "/icon/zed.svg"
run_on_start = true
script = <<-EOT
#!/bin/sh
set -eu
SETTINGS_JSON='${replace(var.settings, "\"", "\\\"")}'
if [ -z "$${SETTINGS_JSON}" ] || [ "$${SETTINGS_JSON}" = "{}" ]; then
@@ -264,7 +264,7 @@ resource "kubernetes_deployment" "main" {
container {
name = "dev"
image = var.cache_repo == "" ? local.devcontainer_builder_image : envbuilder_cached_image.cached.0.image
image_pull_policy = "Always"
image_pull_policy = "IfNotPresent"
security_context {
privileged = true
}
@@ -455,4 +455,4 @@ resource "coder_metadata" "container_info" {
key = "cache repo"
value = var.cache_repo == "" ? "not enabled" : var.cache_repo
}
}
}
@@ -152,7 +152,7 @@ resource "kubernetes_pod" "main" {
name = "dev"
# We highly recommend pinning this to a specific release of envbox, as the latest tag may change.
image = "ghcr.io/coder/envbox:latest"
image_pull_policy = "Always"
image_pull_policy = "IfNotPresent"
command = ["/envbox", "docker"]
security_context {
@@ -310,4 +310,4 @@ resource "kubernetes_pod" "main" {
}
}
}
}
}
+1 -1
View File
@@ -287,7 +287,7 @@ resource "kubernetes_deployment" "main" {
container {
name = "dev"
image = "codercom/enterprise-base:ubuntu"
image_pull_policy = "Always"
image_pull_policy = "IfNotPresent"
command = ["sh", "-c", coder_agent.main.init_script]
security_context {
run_as_user = "1000"
@@ -0,0 +1,70 @@
---
display_name: "NFS K8s Deployment"
description: "Mount an NFS share to a Coder K8s workspace"
icon: "../../../../.icons/folder.svg"
verified: false
tags: ["kubernetes", "shared-dir", "nfs"]
---
# NFS K8s Deployment
This template provisions a Coder workspace as a Kubernetes Deployment, with an NFS share mounted
as a volume. The NFS share will synchronize the server-side files onto the client (Coder workspace)
When you stop the Coder workspace and rebuild, the NFS share will be re-mounted, and the changes persisted.
Note the `volume` and `volume_mount` blocks in the deployment and container spec,
respectively:
```terraform
resource "kubernetes_deployment" "main" {
spec {
template {
spec {
container {
volume_mount {
mount_path = data.coder_parameter.nfs_mount_path.value # mount path in the container
name = "nfs-share"
}
}
volume {
name = "nfs-share"
nfs {
path = data.coder_parameter.nfs_mount_path.value # path to be exported from the server
server = data.coder_parameter.nfs_server.value # server IP address
}
}
}
}
}
}
```
## server-side configuration
1. Create an NFS mount on the server for the clients to access:
```console
export NFS_MNT_PATH=/mnt/nfs_share
# Create directory to shaare
sudo mkdir -p $NFS_MNT_PATH
# Assign UID & GIDs access
sudo chown -R uid:gid $NFS_MNT_PATH
sudo chmod 777 $NFS_MNT_PATH
```
1. Grant access to the client by updating the `/etc/exports` file, which
controls the directories shared with remote clients. See
[Red Hat's docs for more information about the configuration options](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/deployment_guide/s1-nfs-server-config-exports).
```console
# Provides read/write access to clients accessing the NFS from any IP address.
/mnt/nfs_share *(rw,sync,no_subtree_check)
```
1. Export the NFS file share directory. You must do this every time you change
`/etc/exports`.
```console
sudo exportfs -a
sudo systemctl restart <nfs-package>
```
@@ -0,0 +1,348 @@
terraform {
required_providers {
coder = {
source = "coder/coder"
}
kubernetes = {
source = "hashicorp/kubernetes"
}
}
}
provider "coder" {
}
provider "kubernetes" {
config_path = var.use_kubeconfig == true ? "~/.kube/config" : null
}
variable "use_kubeconfig" {
type = bool
description = <<-EOF
Use host kubeconfig? (true/false)
Set this to false if the Coder host is itself running as a Pod on the same
Kubernetes cluster as you are deploying workspaces to.
Set this to true if the Coder host is running outside the Kubernetes cluster
for workspaces. A valid "~/.kube/config" must be present on the Coder host.
EOF
default = false
}
variable "namespace" {
type = string
description = "The Kubernetes namespace to create workspaces in (must exist prior to creating workspaces). If the Coder host is itself running as a Pod on the same Kubernetes cluster as you are deploying workspaces to, set this to the same namespace."
}
data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
data "coder_parameter" "cpu" {
name = "cpu"
display_name = "CPU"
description = "The number of CPU cores"
default = "2"
icon = "/icon/memory.svg"
mutable = true
option {
name = "2 Cores"
value = "2"
}
option {
name = "4 Cores"
value = "4"
}
option {
name = "6 Cores"
value = "6"
}
option {
name = "8 Cores"
value = "8"
}
}
data "coder_parameter" "memory" {
name = "memory"
display_name = "Memory"
description = "The amount of memory in GB"
default = "2"
icon = "/icon/memory.svg"
mutable = true
option {
name = "2 GB"
value = "2"
}
option {
name = "4 GB"
value = "4"
}
option {
name = "6 GB"
value = "6"
}
option {
name = "8 GB"
value = "8"
}
}
data "coder_parameter" "home_disk_size" {
name = "home_disk_size"
display_name = "Home disk size"
description = "The size of the home disk in GB"
default = "10"
type = "number"
icon = "/emojis/1f4be.png"
mutable = false
validation {
min = 1
max = 99999
}
}
data "coder_parameter" "nfs_server" {
name = "nfs_server"
type = "string"
display_name = "NFS Server IP"
description = "The NFS server IP address to use for the workspace"
}
data "coder_parameter" "nfs_mount_path" {
name = "nfs_mount_path"
type = "string"
display_name = "NFS Mount Path"
description = "The path in your workspace container to mount the NFS share to"
default = "/mnt/nfs-share"
validation {
regex = "^/[a-zA-Z0-9_-]+(/[a-zA-Z0-9_-]+)*$"
error = "NFS mount path must be a valid path in your workspace container"
}
}
resource "coder_agent" "coder" {
os = "linux"
arch = "amd64"
# 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
}
}
module "vscode-web" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vscode-web/coder"
version = "1.3.1"
agent_id = coder_agent.coder.id
accept_license = true
}
resource "kubernetes_deployment" "main" {
count = data.coder_workspace.me.start_count
depends_on = [
kubernetes_persistent_volume_claim.home
]
wait_for_rollout = false
metadata {
name = "coder-${data.coder_workspace.me.id}"
namespace = var.namespace
labels = {
"app.kubernetes.io/name" = "coder-workspace"
"app.kubernetes.io/instance" = "coder-workspace-${data.coder_workspace.me.id}"
"app.kubernetes.io/part-of" = "coder"
"com.coder.resource" = "true"
"com.coder.workspace.id" = data.coder_workspace.me.id
"com.coder.workspace.name" = data.coder_workspace.me.name
"com.coder.user.id" = data.coder_workspace_owner.me.id
"com.coder.user.username" = data.coder_workspace_owner.me.name
}
annotations = {
"com.coder.user.email" = data.coder_workspace_owner.me.email
}
}
spec {
replicas = 1
selector {
match_labels = {
"app.kubernetes.io/name" = "coder-workspace"
"app.kubernetes.io/instance" = "coder-workspace-${data.coder_workspace.me.id}"
"app.kubernetes.io/part-of" = "coder"
"com.coder.resource" = "true"
"com.coder.workspace.id" = data.coder_workspace.me.id
"com.coder.workspace.name" = data.coder_workspace.me.name
"com.coder.user.id" = data.coder_workspace_owner.me.id
"com.coder.user.username" = data.coder_workspace_owner.me.name
}
}
strategy {
type = "Recreate"
}
template {
metadata {
labels = {
"app.kubernetes.io/name" = "coder-workspace"
"app.kubernetes.io/instance" = "coder-workspace-${data.coder_workspace.me.id}"
"app.kubernetes.io/part-of" = "coder"
"com.coder.resource" = "true"
"com.coder.workspace.id" = data.coder_workspace.me.id
"com.coder.workspace.name" = data.coder_workspace.me.name
"com.coder.user.id" = data.coder_workspace_owner.me.id
"com.coder.user.username" = data.coder_workspace_owner.me.name
}
}
spec {
container {
name = "dev"
image = "codercom/enterprise-base:ubuntu"
image_pull_policy = "Always"
command = ["sh", "-c", coder_agent.coder.init_script]
env {
name = "CODER_AGENT_TOKEN"
value = coder_agent.coder.token
}
resources {
requests = {
"cpu" = "250m"
"memory" = "512Mi"
}
limits = {
"cpu" = "${data.coder_parameter.cpu.value}"
"memory" = "${data.coder_parameter.memory.value}Gi"
}
}
volume_mount {
mount_path = "/home/${lower(data.coder_workspace_owner.me.name)}"
name = "home"
read_only = false
}
volume_mount {
mount_path = data.coder_parameter.nfs_mount_path.value
name = "nfs-share"
}
}
volume {
name = "home"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.home.metadata.0.name
read_only = false
}
}
volume {
name = "nfs-share"
nfs {
path = data.coder_parameter.nfs_mount_path.value
server = data.coder_parameter.nfs_server.value
}
}
affinity {
// This affinity attempts to spread out all workspace pods evenly across
// nodes.
pod_anti_affinity {
preferred_during_scheduling_ignored_during_execution {
weight = 1
pod_affinity_term {
topology_key = "kubernetes.io/hostname"
label_selector {
match_expressions {
key = "app.kubernetes.io/name"
operator = "In"
values = ["coder-workspace"]
}
}
}
}
}
}
}
}
}
}
resource "kubernetes_persistent_volume_claim" "home" {
metadata {
name = "${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace_owner.me.name)}-home"
namespace = var.namespace
labels = {
"app.kubernetes.io/name" = "coder-pvc"
"app.kubernetes.io/instance" = "coder-pvc-${data.coder_workspace.me.id}"
"app.kubernetes.io/part-of" = "coder"
//Coder-specific labels.
"com.coder.resource" = "true"
"com.coder.workspace.id" = data.coder_workspace.me.id
"com.coder.workspace.name" = data.coder_workspace.me.name
"com.coder.user.id" = data.coder_workspace_owner.me.id
"com.coder.user.username" = data.coder_workspace_owner.me.name
}
annotations = {
"com.coder.user.email" = data.coder_workspace_owner.me.email
}
}
wait_until_bound = false
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = "${data.coder_parameter.home_disk_size.value}Gi"
}
}
}
}