Skip to content

Commit 98fa823

Browse files
authored
docs: describe workspace tags (#13352)
1 parent b43344b commit 98fa823

File tree

5 files changed

+288
-1
lines changed

5 files changed

+288
-1
lines changed

docs/manifest.json

+5
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@
200200
"description": "Prompt the template administrator for additional information about a template",
201201
"path": "./templates/variables.md"
202202
},
203+
{
204+
"title": "Workspace Tags",
205+
"description": "Control provisioning using Workspace Tags and Parameters",
206+
"path": "./templates/workspace-tags.md"
207+
},
203208
{
204209
"title": "Administering templates",
205210
"description": "Configuration settings for template admins",

docs/templates/workspace-tags.md

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Workspace Tags
2+
3+
Template administrators can leverage static template tags to limit workspace
4+
provisioning to designated provisioner groups that have locally deployed
5+
credentials for creating workspace resources. While this method ensures
6+
controlled access, it offers limited flexibility and does not permit users to
7+
select the nodes for their workspace creation.
8+
9+
By using `coder_workspace_tags` and `coder_parameter`s, template administrators
10+
can enable dynamic tag selection and modify static template tags.
11+
12+
## Dynamic tag selection
13+
14+
Here is a sample `coder_workspace_tags` data resource with a few workspace tags
15+
specified:
16+
17+
```hcl
18+
data "coder_workspace_tags" "custom_workspace_tags" {
19+
tags = {
20+
"zone" = "developers"
21+
"runtime" = data.coder_parameter.runtime_selector.value
22+
"project_id" = "PROJECT_${data.coder_parameter.project_name.value}"
23+
"cache" = data.coder_parameter.feature_cache_enabled.value == "true" ? "with-cache" : "no-cache"
24+
}
25+
}
26+
```
27+
28+
**Legend**
29+
30+
- `zone` - static tag value set to `developers`
31+
- `runtime` - supported by the string-type `coder_parameter` to select
32+
provisioner runtime, `runtime_selector`
33+
- `project_id` - a formatted string supported by the string-type
34+
`coder_parameter`, `project_name`
35+
- `cache` - an HCL condition involving boolean-type `coder_parameter`,
36+
`feature_cache_enabled`
37+
38+
Review the
39+
[full template example](https://github.com/coder/coder/tree/main/examples/workspace-tags)
40+
using `coder_workspace_tags` and `coder_parameter`s.
41+
42+
## Constraints
43+
44+
### Tagged provisioners
45+
46+
It is possible to choose tag combinations that no provisioner can handle. This
47+
will cause the provisioner job to get stuck in the queue until a provisioner is
48+
added that can handle its combination of tags.
49+
50+
Before releasing the template version with configurable workspace tags, ensure
51+
that every tag set is associated with at least one healthy provisioner.
52+
53+
### Parameters types
54+
55+
Provisioners require job tags to be defined in plain string format. When a
56+
workspace tag refers to a `coder_parameter` without involving the string
57+
formatter, for example,
58+
(`"runtime" = data.coder_parameter.runtime_selector.value`), the Coder
59+
provisioner server can transform only the following parameter types to strings:
60+
_string_, _number_, and _bool_.
61+
62+
### Mutability
63+
64+
A mutable `coder_parameter` can be dangerous for a workspace tag as it allows
65+
the workspace owner to change a provisioner group (due to different tags). In
66+
most cases, `coder_parameter`s backing `coder_workspace_tags` should be marked
67+
as immutable and set only once, during workspace creation.
68+
69+
### HCL syntax
70+
71+
When importing the template version with `coder_workspace_tags`, the Coder
72+
provisioner server extracts raw partial queries for each workspace tag and
73+
stores them in the database. During workspace build time, the Coder server uses
74+
the [Hashicorp HCL library](https://github.com/hashicorp/hcl) to evaluate these
75+
raw queries on-the-fly without processing the entire Terraform template. This
76+
evaluation is simpler but also limited in terms of available functions,
77+
variables, and references to other resources.
78+
79+
**Supported syntax**
80+
81+
- Static string: `foobar_tag = "foobaz"`
82+
- Formatted string: `foobar_tag = "foobaz ${data.coder_parameter.foobaz.value}"`
83+
- Reference to `coder_parameter`:
84+
`foobar_tag = data.coder_parameter.foobar.value`
85+
- Boolean logic: `production_tag = !data.coder_parameter.staging_env.value`
86+
- Condition:
87+
`cache = data.coder_parameter.feature_cache_enabled.value == "true" ? "with-cache" : "no-cache"`

examples/parameters-dynamic-options/README.md

-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,5 @@ Update the template and push it using the following command:
3535
./scripts/coder-dev.sh templates push examples-parameters-dynamic-options \
3636
-d examples/parameters-dynamic-options \
3737
--variables-file examples/parameters-dynamic-options/variables.yml \
38-
--create \
3938
-y
4039
```

examples/workspace-tags/README.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
name: Sample Template with Workspace Tags
3+
description: Review the sample template and introduce dynamic workspace tags to your template
4+
tags: [local, docker, workspace-tags]
5+
icon: /icon/docker.png
6+
---
7+
8+
# Overview
9+
10+
This Coder template presents use of [Workspace Tags](https://coder.com/docs/v2/latest/templates/workspace-tags) [Coder Parameters](https://coder.com/docs/v2/latest/templates/parameters).
11+
12+
# Use case
13+
14+
Template administrators can use static tags to control workspace provisioning, limiting it to specific provisioner groups. However, this restricts workspace users from choosing their preferred workspace nodes.
15+
16+
By using `coder_workspace_tags` and `coder_parameter`s, template administrators can allow dynamic tag selection, avoiding the need to push the same template multiple times with different tags.
17+
18+
## Development
19+
20+
Update the template and push it using the following command:
21+
22+
```
23+
./scripts/coder-dev.sh templates push examples-workspace-tags \
24+
-d examples/workspace-tags \
25+
-y
26+
```

examples/workspace-tags/main.tf

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
terraform {
2+
required_providers {
3+
coder = {
4+
source = "coder/coder"
5+
}
6+
docker = {
7+
source = "kreuzwerker/docker"
8+
}
9+
}
10+
}
11+
12+
locals {
13+
username = data.coder_workspace.me.owner
14+
}
15+
16+
data "coder_provisioner" "me" {
17+
}
18+
19+
data "coder_workspace" "me" {
20+
}
21+
22+
data "coder_workspace_tags" "custom_workspace_tags" {
23+
tags = {
24+
"zone" = "developers"
25+
"runtime" = data.coder_parameter.runtime_selector.value
26+
"project_id" = "PROJECT_${data.coder_parameter.project_name.value}"
27+
"cache" = data.coder_parameter.feature_cache_enabled.value == "true" ? "with-cache" : "no-cache"
28+
}
29+
}
30+
31+
data "coder_parameter" "runtime_selector" {
32+
name = "runtime_selector"
33+
display_name = "Provisioner Runtime"
34+
default = "development"
35+
36+
option {
37+
name = "Development (free zone)"
38+
value = "development"
39+
}
40+
option {
41+
name = "Staging (internal access)"
42+
value = "staging"
43+
}
44+
option {
45+
name = "Production (air-gapped)"
46+
value = "production"
47+
}
48+
49+
mutable = false
50+
}
51+
52+
data "coder_parameter" "project_name" {
53+
name = "project_name"
54+
display_name = "Project name"
55+
description = "Specify the project name."
56+
57+
mutable = false
58+
}
59+
60+
data "coder_parameter" "feature_cache_enabled" {
61+
name = "feature_cache_enabled"
62+
display_name = "Enable cache?"
63+
type = "bool"
64+
default = false
65+
66+
mutable = false
67+
}
68+
69+
resource "coder_agent" "main" {
70+
arch = data.coder_provisioner.me.arch
71+
os = "linux"
72+
startup_script = <<EOF
73+
#!/bin/sh
74+
# install and start code-server
75+
curl -fsSL https://code-server.dev/install.sh | sh -s -- --version 4.8.3
76+
code-server --auth none --port 13337
77+
EOF
78+
79+
env = {
80+
GIT_AUTHOR_NAME = "${data.coder_workspace.me.owner}"
81+
GIT_COMMITTER_NAME = "${data.coder_workspace.me.owner}"
82+
GIT_AUTHOR_EMAIL = "${data.coder_workspace.me.owner_email}"
83+
GIT_COMMITTER_EMAIL = "${data.coder_workspace.me.owner_email}"
84+
}
85+
}
86+
87+
resource "coder_app" "code-server" {
88+
agent_id = coder_agent.main.id
89+
slug = "code-server"
90+
display_name = "code-server"
91+
url = "http://localhost:13337/?folder=/home/${local.username}"
92+
icon = "/icon/code.svg"
93+
subdomain = false
94+
share = "owner"
95+
96+
healthcheck {
97+
url = "http://localhost:13337/healthz"
98+
interval = 5
99+
threshold = 6
100+
}
101+
}
102+
103+
resource "docker_volume" "home_volume" {
104+
name = "coder-${data.coder_workspace.me.id}-home"
105+
lifecycle {
106+
ignore_changes = all
107+
}
108+
labels {
109+
label = "coder.owner"
110+
value = data.coder_workspace.me.owner
111+
}
112+
labels {
113+
label = "coder.owner_id"
114+
value = data.coder_workspace.me.owner_id
115+
}
116+
labels {
117+
label = "coder.workspace_id"
118+
value = data.coder_workspace.me.id
119+
}
120+
labels {
121+
label = "coder.workspace_name_at_creation"
122+
value = data.coder_workspace.me.name
123+
}
124+
}
125+
126+
resource "coder_metadata" "home_info" {
127+
resource_id = docker_volume.home_volume.id
128+
129+
item {
130+
key = "size"
131+
value = "5 GiB"
132+
}
133+
}
134+
135+
resource "docker_container" "workspace" {
136+
count = data.coder_workspace.me.start_count
137+
image = "ubuntu:22.04"
138+
name = "coder-${data.coder_workspace.me.owner}-${lower(data.coder_workspace.me.name)}"
139+
hostname = data.coder_workspace.me.name
140+
entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
141+
env = [
142+
"CODER_AGENT_TOKEN=${coder_agent.main.token}",
143+
]
144+
host {
145+
host = "host.docker.internal"
146+
ip = "host-gateway"
147+
}
148+
volumes {
149+
container_path = "/home/${local.username}"
150+
volume_name = docker_volume.home_volume.name
151+
read_only = false
152+
}
153+
154+
labels {
155+
label = "coder.owner"
156+
value = data.coder_workspace.me.owner
157+
}
158+
labels {
159+
label = "coder.owner_id"
160+
value = data.coder_workspace.me.owner_id
161+
}
162+
labels {
163+
label = "coder.workspace_id"
164+
value = data.coder_workspace.me.id
165+
}
166+
labels {
167+
label = "coder.workspace_name"
168+
value = data.coder_workspace.me.name
169+
}
170+
}

0 commit comments

Comments
 (0)