Skip to content

docs: describe workspace tags #13352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@
"description": "Prompt the template administrator for additional information about a template",
"path": "./templates/variables.md"
},
{
"title": "Workspace Tags",
"description": "Control provisioning using Workspace Tags and Parameters",
"path": "./templates/workspace-tags.md"
},
{
"title": "Administering templates",
"description": "Configuration settings for template admins",
Expand Down
87 changes: 87 additions & 0 deletions docs/templates/workspace-tags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Workspace Tags

Template administrators can leverage static template tags to limit workspace
provisioning to designated provisioner groups that have locally deployed
credentials for creating workspace resources. While this method ensures
controlled access, it offers limited flexibility and does not permit users to
select the nodes for their workspace creation.

By using `coder_workspace_tags` and `coder_parameter`s, template administrators
can enable dynamic tag selection and modify static template tags.

## Dynamic tag selection

Here is a sample `coder_workspace_tags` data resource with a few workspace tags
specified:

```hcl
data "coder_workspace_tags" "custom_workspace_tags" {
tags = {
"zone" = "developers"
"runtime" = data.coder_parameter.runtime_selector.value
"project_id" = "PROJECT_${data.coder_parameter.project_name.value}"
"cache" = data.coder_parameter.feature_cache_enabled.value == "true" ? "with-cache" : "no-cache"
}
}
```

**Legend**

- `zone` - static tag value set to `developers`
- `runtime` - supported by the string-type `coder_parameter` to select
provisioner runtime, `runtime_selector`
- `project_id` - a formatted string supported by the string-type
`coder_parameter`, `project_name`
- `cache` - an HCL condition involving boolean-type `coder_parameter`,
`feature_cache_enabled`

Review the
[full template example](https://github.com/coder/coder/tree/main/examples/workspace-tags)
using `coder_workspace_tags` and `coder_parameter`s.

## Constraints

### Tagged provisioners

It is possible to choose tag combinations that no provisioner can handle. This
will cause the provisioner job to get stuck in the queue until a provisioner is
added that can handle its combination of tags.

Before releasing the template version with configurable workspace tags, ensure
that every tag set is associated with at least one healthy provisioner.

### Parameters types

Provisioners require job tags to be defined in plain string format. When a
workspace tag refers to a `coder_parameter` without involving the string
formatter, for example,
(`"runtime" = data.coder_parameter.runtime_selector.value`), the Coder
provisioner server can transform only the following parameter types to strings:
_string_, _number_, and _bool_.

### Mutability

A mutable `coder_parameter` can be dangerous for a workspace tag as it allows
the workspace owner to change a provisioner group (due to different tags). In
most cases, `coder_parameter`s backing `coder_workspace_tags` should be marked
as immutable and set only once, during workspace creation.

### HCL syntax

When importing the template version with `coder_workspace_tags`, the Coder
provisioner server extracts raw partial queries for each workspace tag and
stores them in the database. During workspace build time, the Coder server uses
the [Hashicorp HCL library](https://github.com/hashicorp/hcl) to evaluate these
raw queries on-the-fly without processing the entire Terraform template. This
evaluation is simpler but also limited in terms of available functions,
variables, and references to other resources.

**Supported syntax**

- Static string: `foobar_tag = "foobaz"`
- Formatted string: `foobar_tag = "foobaz ${data.coder_parameter.foobaz.value}"`
- Reference to `coder_parameter`:
`foobar_tag = data.coder_parameter.foobar.value`
- Boolean logic: `production_tag = !data.coder_parameter.staging_env.value`
- Condition:
`cache = data.coder_parameter.feature_cache_enabled.value == "true" ? "with-cache" : "no-cache"`
1 change: 0 additions & 1 deletion examples/parameters-dynamic-options/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,5 @@ Update the template and push it using the following command:
./scripts/coder-dev.sh templates push examples-parameters-dynamic-options \
-d examples/parameters-dynamic-options \
--variables-file examples/parameters-dynamic-options/variables.yml \
--create \
-y
```
26 changes: 26 additions & 0 deletions examples/workspace-tags/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: Sample Template with Workspace Tags
description: Review the sample template and introduce dynamic workspace tags to your template
tags: [local, docker, workspace-tags]
icon: /icon/docker.png
---

# Overview

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).

# Use case

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.

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.

## Development

Update the template and push it using the following command:

```
./scripts/coder-dev.sh templates push examples-workspace-tags \
-d examples/workspace-tags \
-y
```
170 changes: 170 additions & 0 deletions examples/workspace-tags/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
terraform {
required_providers {
coder = {
source = "coder/coder"
}
docker = {
source = "kreuzwerker/docker"
}
}
}

locals {
username = data.coder_workspace.me.owner
}

data "coder_provisioner" "me" {
}

data "coder_workspace" "me" {
}

data "coder_workspace_tags" "custom_workspace_tags" {
tags = {
"zone" = "developers"
"runtime" = data.coder_parameter.runtime_selector.value
"project_id" = "PROJECT_${data.coder_parameter.project_name.value}"
"cache" = data.coder_parameter.feature_cache_enabled.value == "true" ? "with-cache" : "no-cache"
}
}

data "coder_parameter" "runtime_selector" {
name = "runtime_selector"
display_name = "Provisioner Runtime"
default = "development"

option {
name = "Development (free zone)"
value = "development"
}
option {
name = "Staging (internal access)"
value = "staging"
}
option {
name = "Production (air-gapped)"
value = "production"
}

mutable = false
}

data "coder_parameter" "project_name" {
name = "project_name"
display_name = "Project name"
description = "Specify the project name."

mutable = false
}

data "coder_parameter" "feature_cache_enabled" {
name = "feature_cache_enabled"
display_name = "Enable cache?"
type = "bool"
default = false

mutable = false
}

resource "coder_agent" "main" {
arch = data.coder_provisioner.me.arch
os = "linux"
startup_script = <<EOF
#!/bin/sh
# install and start code-server
curl -fsSL https://code-server.dev/install.sh | sh -s -- --version 4.8.3
code-server --auth none --port 13337
EOF

env = {
GIT_AUTHOR_NAME = "${data.coder_workspace.me.owner}"
GIT_COMMITTER_NAME = "${data.coder_workspace.me.owner}"
GIT_AUTHOR_EMAIL = "${data.coder_workspace.me.owner_email}"
GIT_COMMITTER_EMAIL = "${data.coder_workspace.me.owner_email}"
}
}

resource "coder_app" "code-server" {
agent_id = coder_agent.main.id
slug = "code-server"
display_name = "code-server"
url = "http://localhost:13337/?folder=/home/${local.username}"
icon = "/icon/code.svg"
subdomain = false
share = "owner"

healthcheck {
url = "http://localhost:13337/healthz"
interval = 5
threshold = 6
}
}

resource "docker_volume" "home_volume" {
name = "coder-${data.coder_workspace.me.id}-home"
lifecycle {
ignore_changes = all
}
labels {
label = "coder.owner"
value = data.coder_workspace.me.owner
}
labels {
label = "coder.owner_id"
value = data.coder_workspace.me.owner_id
}
labels {
label = "coder.workspace_id"
value = data.coder_workspace.me.id
}
labels {
label = "coder.workspace_name_at_creation"
value = data.coder_workspace.me.name
}
}

resource "coder_metadata" "home_info" {
resource_id = docker_volume.home_volume.id

item {
key = "size"
value = "5 GiB"
}
}

resource "docker_container" "workspace" {
count = data.coder_workspace.me.start_count
image = "ubuntu:22.04"
name = "coder-${data.coder_workspace.me.owner}-${lower(data.coder_workspace.me.name)}"
hostname = data.coder_workspace.me.name
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"
}
volumes {
container_path = "/home/${local.username}"
volume_name = docker_volume.home_volume.name
read_only = false
}

labels {
label = "coder.owner"
value = data.coder_workspace.me.owner
}
labels {
label = "coder.owner_id"
value = data.coder_workspace.me.owner_id
}
labels {
label = "coder.workspace_id"
value = data.coder_workspace.me.id
}
labels {
label = "coder.workspace_name"
value = data.coder_workspace.me.name
}
}
Loading